{
  "updated": "2026-07-25T08:27:34.024602+00:00",
  "robots": [
    {
      "name": "WA1",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "aw1.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "status": "offline",
      "camera": null
    },
    {
      "name": "WA2",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "aw2.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T19:21:24",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.50.102",
      "last_connected_mac": "8c:f8:c5:96:2e:cc",
      "last_hostname": "aw2.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "E7 | Demo DC 1 (Left Middle)",
      "last_radio": "6e",
      "last_wifi": {
        "satisfaction": 100,
        "satisfaction_real": 96,
        "signal": -46,
        "noise": -94,
        "rssi": 48,
        "channel": 53,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Demo DC 1 (Left Middle)",
        "tx_rate": 34400,
        "rx_rate": 286800,
        "wifi_tx_retries_pct": 26.7,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "WA3",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "aw3.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T21:43:46",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.50.103",
      "last_connected_mac": "00:13:95:65:05:ca",
      "last_hostname": "aw3eth.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "USW Pro XG 24 PoE | 2 | Replacement",
      "last_radio": null,
      "last_wifi": {
        "satisfaction": 100,
        "ap": "USW Pro XG 24 PoE | 2 | Replacement",
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "WA4",
      "network_status": "connected",
      "site": "1-triton",
      "ip": "",
      "hostname": "aw4.hmnd.lan",
      "unifi_name": "aw4 | wifi-0",
      "interface": "wifi-0",
      "connection_type": "wifi",
      "mac": "90:10:57:98:ab:b6",
      "last_seen": "2026-07-25T08:24:43",
      "uptime": 10127,
      "wired": false,
      "ssid": "hmnd-robots",
      "ap": "E7 | Demo DC (Gantry Middle)",
      "signal": -53,
      "channel": 85,
      "radio_proto": "ax",
      "satisfaction": 100,
      "tx_rate": 229400,
      "rx_rate": 286800,
      "tx_bytes": 2037080412,
      "rx_bytes": 112898295737,
      "noise": -93,
      "ccq": 333,
      "rssi": 40,
      "satisfaction_real": 99,
      "tx_retries": 2636793,
      "wifi_tx_retries_pct": 17.5,
      "throughput": null,
      "anomalies": 0,
      "vlan": 50,
      "network": "hmnd-robots",
      "last_wifi": {
        "satisfaction": 100,
        "satisfaction_real": 99,
        "signal": -53,
        "noise": -93,
        "rssi": 40,
        "channel": 85,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Demo DC (Gantry Middle)",
        "tx_rate": 229400,
        "rx_rate": 286800,
        "wifi_tx_retries_pct": 17.5,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "online",
      "camera": null
    },
    {
      "name": "WA5",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "aw5.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T18:00:24",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.50.105",
      "last_connected_mac": "8c:f8:c5:b3:80:d0",
      "last_hostname": "aw5.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "E7 | Demo DC 1 (Left Middle)",
      "last_radio": "6e",
      "last_wifi": {
        "satisfaction": 98,
        "satisfaction_real": 98,
        "signal": -51,
        "noise": -94,
        "rssi": 43,
        "channel": 53,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Demo DC 1 (Left Middle)",
        "tx_rate": 229400,
        "rx_rate": 286800,
        "wifi_tx_retries_pct": 22.7,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "WA6",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "aw6.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T18:18:53",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.50.106",
      "last_connected_mac": "90:10:57:97:84:25",
      "last_hostname": "aw6.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "E7 | Demo DC 1 (Left Middle)",
      "last_radio": "6e",
      "last_wifi": {
        "satisfaction": 100,
        "satisfaction_real": 100,
        "signal": -50,
        "noise": -94,
        "rssi": 44,
        "channel": 53,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Demo DC 1 (Left Middle)",
        "tx_rate": 24000,
        "rx_rate": 286800,
        "wifi_tx_retries_pct": 14.2,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "WA7",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "aw7.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T18:48:19",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.50.107",
      "last_connected_mac": "90:10:57:98:aa:26",
      "last_hostname": "aw7.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "E7 | Demo DC 1 (Left Middle)",
      "last_radio": "6e",
      "last_wifi": {
        "satisfaction": 100,
        "satisfaction_real": 100,
        "signal": -52,
        "noise": -94,
        "rssi": 42,
        "channel": 53,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Demo DC 1 (Left Middle)",
        "tx_rate": 24000,
        "rx_rate": 286800,
        "wifi_tx_retries_pct": 16.9,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "WA8",
      "network_status": "connected",
      "site": "1-triton",
      "ip": "",
      "hostname": "aw8.hmnd.lan",
      "unifi_name": "aw8 | wifi-0",
      "interface": "wifi-0",
      "connection_type": "wifi",
      "mac": "5c:b2:6d:46:6d:56",
      "last_seen": "2026-07-25T08:25:09",
      "uptime": 9610,
      "wired": false,
      "ssid": "hmnd-robots",
      "ap": "E7 | Demo DC 1 (Left Middle)",
      "signal": -58,
      "channel": 53,
      "radio_proto": "ax",
      "satisfaction": 100,
      "tx_rate": 103200,
      "rx_rate": 143400,
      "tx_bytes": 1926143449,
      "rx_bytes": 64834243937,
      "noise": -94,
      "ccq": 333,
      "rssi": 36,
      "satisfaction_real": 98,
      "tx_retries": 1013998,
      "wifi_tx_retries_pct": 16.3,
      "throughput": null,
      "anomalies": -1,
      "vlan": 50,
      "network": "hmnd-robots",
      "last_wifi": {
        "satisfaction": 100,
        "satisfaction_real": 98,
        "signal": -58,
        "noise": -94,
        "rssi": 36,
        "channel": 53,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Demo DC 1 (Left Middle)",
        "tx_rate": 103200,
        "rx_rate": 143400,
        "wifi_tx_retries_pct": 16.3,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "online",
      "camera": null
    },
    {
      "name": "WA9",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "aw9.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T16:54:25",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.50.109",
      "last_connected_mac": "5c:b2:6d:46:6d:0b",
      "last_hostname": "aw9.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "E7 | Eng Lab (Middle Front NL3 )",
      "last_radio": "6e",
      "last_wifi": {
        "satisfaction": 100,
        "satisfaction_real": 100,
        "signal": -61,
        "noise": -93,
        "rssi": 32,
        "channel": 69,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Eng Lab (Middle Front NL3 )",
        "tx_rate": 229400,
        "rx_rate": 229400,
        "wifi_tx_retries_pct": 0.0,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "WA10",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "aw10.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T17:04:32",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.50.110",
      "last_connected_mac": "5c:b2:6d:46:6d:88",
      "last_hostname": "aw10.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "E7 | Eng Lab (Middle Front NL3 )",
      "last_radio": "6e",
      "last_wifi": {
        "satisfaction": 100,
        "satisfaction_real": 100,
        "signal": -54,
        "noise": -93,
        "rssi": 39,
        "channel": 69,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Eng Lab (Middle Front NL3 )",
        "tx_rate": 286800,
        "rx_rate": 286800,
        "wifi_tx_retries_pct": 0.0,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "WA11",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "aw11.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T16:29:18",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.50.111",
      "last_connected_mac": "58:6d:67:f7:d1:36",
      "last_hostname": "aw11.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "E7 | Demo DC 1 (Left Middle)",
      "last_radio": "6e",
      "last_wifi": {
        "satisfaction": 99,
        "satisfaction_real": 99,
        "signal": -61,
        "noise": -94,
        "rssi": 33,
        "channel": 53,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Demo DC 1 (Left Middle)",
        "tx_rate": 258100,
        "rx_rate": 229400,
        "wifi_tx_retries_pct": 11.5,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "WA12",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "aw12.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T20:52:11",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.50.112",
      "last_connected_mac": "c4:03:a8:32:ee:43",
      "last_hostname": "aw12.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "E7 | Demo DC (Gantry Middle)",
      "last_radio": "6e",
      "last_wifi": {
        "satisfaction": 100,
        "satisfaction_real": 100,
        "signal": -52,
        "noise": -93,
        "rssi": 41,
        "channel": 85,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Demo DC (Gantry Middle)",
        "tx_rate": 258100,
        "rx_rate": 286800,
        "wifi_tx_retries_pct": 19.7,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "AB1",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "ab1.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_wifi": {
        "satisfaction": 100,
        "satisfaction_real": 100,
        "signal": -56,
        "noise": -91,
        "rssi": 35,
        "channel": 64,
        "radio_proto": "ax",
        "ssid": "Alpha",
        "ap": "hmnd-lab-ap-01 | Lab Ceiling",
        "tx_rate": 286800,
        "rx_rate": 286800,
        "throughput": 34276.2585757078,
        "wifi_tx_retries_pct": 1.2,
        "vlan": 10,
        "network": "hmnd-alpha"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "AB2",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "ab2.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T16:23:10",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.51.102",
      "last_connected_mac": "90:10:57:98:aa:3a",
      "last_hostname": "ab2.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "E7 | Eng Lab (Middle Front NL3 )",
      "last_radio": "6e",
      "last_wifi": {
        "satisfaction": 100,
        "satisfaction_real": 100,
        "signal": -61,
        "noise": -93,
        "rssi": 32,
        "channel": 69,
        "radio_proto": "ax",
        "ssid": "hmnd-robots",
        "ap": "E7 | Eng Lab (Middle Front NL3 )",
        "tx_rate": 229400,
        "rx_rate": 195000,
        "wifi_tx_retries_pct": 0.0,
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    },
    {
      "name": "AB3",
      "network_status": "disconnected",
      "site": null,
      "ip": null,
      "hostname": "ab3.hmnd.lan",
      "unifi_name": null,
      "interface": null,
      "connection_type": null,
      "mac": null,
      "last_seen": null,
      "uptime": 0,
      "signal": null,
      "wired": null,
      "last_connected_time": "2026-07-24T21:34:33",
      "last_connected_site": "1-triton",
      "last_connected_ip": "10.10.51.103",
      "last_connected_mac": "00:13:95:65:f1:92",
      "last_hostname": "ab3eth.hmnd.lan",
      "last_ssid": "hmnd-robots",
      "last_ap": "USW Pro XG 24 PoE | 2 | Replacement",
      "last_radio": null,
      "last_wifi": {
        "satisfaction": 100,
        "ap": "USW Pro XG 24 PoE | 2 | Replacement",
        "vlan": 50,
        "network": "hmnd-robots"
      },
      "status": "offline",
      "camera": null
    }
  ],
  "aws": {
    "region": "eu-west-2",
    "regions": [
      "ap-south-1",
      "ca-central-1",
      "us-east-2",
      "sa-east-1",
      "us-east-1",
      "ap-northeast-1",
      "ap-southeast-2",
      "eu-central-1",
      "me-central-1",
      "eu-north-1",
      "us-west-2",
      "us-west-1",
      "eu-west-2",
      "ap-northeast-2",
      "ap-northeast-3",
      "ap-southeast-1",
      "eu-south-2",
      "eu-west-1",
      "eu-west-3"
    ],
    "vpcs": [
      {
        "id": "vpc-062421deff0577afc",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "ap-south-1",
        "instances": [],
        "tags": {}
      },
      {
        "id": "vpc-069991148097a2c04",
        "name": "humanoid-lab-uce-ap-south-1-SPOT_p5-48xlarge-vpc",
        "cidr": "10.133.0.0/16",
        "region": "ap-south-1",
        "instances": [],
        "tags": {
          "Name": "humanoid-lab-uce-ap-south-1-SPOT_p5-48xlarge-vpc",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_GROUP": "infra"
        }
      },
      {
        "id": "vpc-0fbe8619e2c9fdfff",
        "name": "humanoid-lab-uce-ca-central-1-SPOT_p5-48xlarge-vpc",
        "cidr": "10.6.0.0/16",
        "region": "ca-central-1",
        "instances": [],
        "tags": {
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac",
          "Name": "humanoid-lab-uce-ca-central-1-SPOT_p5-48xlarge-vpc",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_ENV": "production"
        }
      },
      {
        "id": "vpc-0d5eb6d7653dda613",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "ca-central-1",
        "instances": [],
        "tags": {}
      },
      {
        "id": "vpc-084efa5286f4c06f7",
        "name": "lab-us-east2-vpc",
        "cidr": "10.1.0.0/16",
        "region": "us-east-2",
        "instances": [],
        "tags": {
          "Name": "lab-us-east2-vpc"
        }
      },
      {
        "id": "vpc-06595360aa3f04dae",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "us-east-2",
        "instances": [],
        "tags": {}
      },
      {
        "id": "vpc-0faff022393bf08cc",
        "name": "humanoid-lab-uce-sa-east-1-SPOT_p5-48xlarge-vpc",
        "cidr": "10.54.0.0/16",
        "region": "sa-east-1",
        "instances": [],
        "tags": {
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_ENV": "production",
          "Name": "humanoid-lab-uce-sa-east-1-SPOT_p5-48xlarge-vpc",
          "HM_COST_TAG_SERVICE": "prefect"
        }
      },
      {
        "id": "vpc-050e4b631c5c90af8",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "sa-east-1",
        "instances": [],
        "tags": {}
      },
      {
        "id": "vpc-093845afacfb41061",
        "name": "lab-us-east1-vpc",
        "cidr": "10.3.0.0/16",
        "region": "us-east-1",
        "instances": [],
        "tags": {
          "Name": "lab-us-east1-vpc"
        }
      },
      {
        "id": "vpc-082e962a7d9e344b2",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "us-east-1",
        "instances": [],
        "tags": {}
      },
      {
        "id": "vpc-057a8c9f4c837cb52",
        "name": "humanoid-lab-uce-us-east-1-SPOT_p5-48xlarge-vpc",
        "cidr": "10.7.0.0/16",
        "region": "us-east-1",
        "instances": [],
        "tags": {
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_PROJECT": "general-development",
          "Name": "humanoid-lab-uce-us-east-1-SPOT_p5-48xlarge-vpc",
          "HM_COST_TAG_SERVICE": "prefect"
        }
      },
      {
        "id": "vpc-0cff2641cf8ec1524",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "ap-northeast-1",
        "instances": [],
        "tags": {}
      },
      {
        "id": "vpc-01dffeac396df7795",
        "name": "humanoid-lab-uce-ap-northeast-1-SPOT_p5-48xlarge-vpc",
        "cidr": "10.92.0.0/16",
        "region": "ap-northeast-1",
        "instances": [],
        "tags": {
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_PROJECT": "general-development",
          "Name": "humanoid-lab-uce-ap-northeast-1-SPOT_p5-48xlarge-vpc",
          "HM_COST_TAG_SERVICE": "prefect"
        }
      },
      {
        "id": "vpc-06c435949545f0fb4",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "ap-southeast-2",
        "instances": [],
        "tags": {}
      },
      {
        "id": "vpc-08b5a7bb581eba5a5",
        "name": "humanoid-lab-uce-ap-southeast-2-SPOT_p5-48xlarge-vpc",
        "cidr": "10.85.0.0/16",
        "region": "ap-southeast-2",
        "instances": [],
        "tags": {
          "Name": "humanoid-lab-uce-ap-southeast-2-SPOT_p5-48xlarge-vpc",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_SERVICE": "prefect"
        }
      },
      {
        "id": "vpc-03c6dac4b77bd22a5",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "eu-central-1",
        "instances": [
          {
            "id": "i-041321f96c2df4a01",
            "name": "saas-probe-eu-central-1",
            "type": "t3.nano",
            "state": "running",
            "private_ip": "172.31.30.72",
            "public_ip": "63.177.252.41",
            "vpc_id": "vpc-03c6dac4b77bd22a5",
            "subnet_id": "subnet-0a1269543b3f5d4f5",
            "az": "eu-central-1a",
            "security_groups": [
              "sg-08778a4ed02ce05a1"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "saas-probe",
              "HM_COST_TAG_USER": "general",
              "HM_COST_TAG_ENV": "prod",
              "Environment": "production",
              "Team": "infra",
              "HM_COST_TAG_GROUP": "infra",
              "Region": "eu-central-1",
              "Name": "saas-probe-eu-central-1",
              "Purpose": "saas-probe",
              "HM_COST_TAG_PROJECT": "saas-probe",
              "ManagedBy": "terraform",
              "TerraformDomain": "hmnd-network/saas-probe"
            },
            "network_interfaces": [
              {
                "id": "eni-0a6586b0bd31911ee",
                "subnet_id": "subnet-0a1269543b3f5d4f5",
                "private_ip": "172.31.30.72",
                "public_ip": "63.177.252.41",
                "mac": "02:b9:3a:33:8b:29",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-08778a4ed02ce05a1"
                ]
              }
            ]
          },
          {
            "id": "i-07859e779955a7a9e",
            "name": "tjac-g6-gpu",
            "type": "g6.2xlarge",
            "state": "stopped",
            "private_ip": "172.31.38.145",
            "public_ip": null,
            "vpc_id": "vpc-03c6dac4b77bd22a5",
            "subnet_id": "subnet-0a1729292e87705b7",
            "az": "eu-central-1b",
            "security_groups": [
              "sg-0c238e45f99cfd69e"
            ],
            "tags": {
              "Name": "tjac-g6-gpu"
            },
            "network_interfaces": [
              {
                "id": "eni-07312f92441cb92fe",
                "subnet_id": "subnet-0a1729292e87705b7",
                "private_ip": "172.31.38.145",
                "public_ip": null,
                "mac": "06:3f:f3:e5:b9:2f",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0c238e45f99cfd69e"
                ]
              }
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "vpc-00e7b72129f9e7a2c",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "me-central-1",
        "instances": [
          {
            "id": "i-0c0f3ad485a00d603",
            "name": "kubeadm-k8s-node-1",
            "type": "g5.4xlarge",
            "state": "running",
            "private_ip": "172.31.46.251",
            "public_ip": "158.252.119.42",
            "vpc_id": "vpc-00e7b72129f9e7a2c",
            "subnet_id": "subnet-0badd49fc724f76c6",
            "az": "me-central-1a",
            "security_groups": [
              "sg-0571b6cd7b7c48336"
            ],
            "tags": {
              "Name": "kubeadm-k8s-node-1"
            },
            "network_interfaces": [
              {
                "id": "eni-04c50824288150f84",
                "subnet_id": "subnet-0badd49fc724f76c6",
                "private_ip": "172.31.46.251",
                "public_ip": "158.252.119.42",
                "mac": "06:6e:83:68:01:77",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0571b6cd7b7c48336"
                ]
              }
            ]
          },
          {
            "id": "i-04fa8793a83150d82",
            "name": "kubeadm-k8s-node-2",
            "type": "g5.4xlarge",
            "state": "running",
            "private_ip": "172.31.38.130",
            "public_ip": "158.252.86.147",
            "vpc_id": "vpc-00e7b72129f9e7a2c",
            "subnet_id": "subnet-0badd49fc724f76c6",
            "az": "me-central-1a",
            "security_groups": [
              "sg-0571b6cd7b7c48336"
            ],
            "tags": {
              "Name": "kubeadm-k8s-node-2"
            },
            "network_interfaces": [
              {
                "id": "eni-0efe8b303497f7346",
                "subnet_id": "subnet-0badd49fc724f76c6",
                "private_ip": "172.31.38.130",
                "public_ip": "158.252.86.147",
                "mac": "06:64:3a:85:9a:d9",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0571b6cd7b7c48336"
                ]
              }
            ]
          },
          {
            "id": "i-0051850e41b26678a",
            "name": "kubeadm-k8s-node-3",
            "type": "g5.4xlarge",
            "state": "running",
            "private_ip": "172.31.33.154",
            "public_ip": "3.28.39.161",
            "vpc_id": "vpc-00e7b72129f9e7a2c",
            "subnet_id": "subnet-0badd49fc724f76c6",
            "az": "me-central-1a",
            "security_groups": [
              "sg-0571b6cd7b7c48336"
            ],
            "tags": {
              "Name": "kubeadm-k8s-node-3"
            },
            "network_interfaces": [
              {
                "id": "eni-0dd1f99b346d91d0a",
                "subnet_id": "subnet-0badd49fc724f76c6",
                "private_ip": "172.31.33.154",
                "public_ip": "3.28.39.161",
                "mac": "06:bb:b5:cd:05:1f",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0571b6cd7b7c48336"
                ]
              }
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "vpc-0f7272f2c99faf857",
        "name": "lab-eu-north-1-vpc",
        "cidr": "10.4.0.0/16",
        "region": "eu-north-1",
        "instances": [
          {
            "id": "i-0d2f02a42192c0b5c",
            "name": "test",
            "type": "t3.micro",
            "state": "running",
            "private_ip": "10.4.44.1",
            "public_ip": "13.53.139.187",
            "vpc_id": "vpc-0f7272f2c99faf857",
            "subnet_id": "subnet-09344ae80abe2f7f8",
            "az": "eu-north-1c",
            "security_groups": [
              "sg-05709247507f96540"
            ],
            "tags": {
              "HM_COST_TAG_USER": "general",
              "Name": "test",
              "HM_COST_TAG_SERVICE": "dev-vm"
            },
            "network_interfaces": [
              {
                "id": "eni-0a05f36c9d1de31e5",
                "subnet_id": "subnet-09344ae80abe2f7f8",
                "private_ip": "10.4.44.1",
                "public_ip": "13.53.139.187",
                "mac": "0e:6a:80:f2:62:43",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-05709247507f96540"
                ]
              }
            ]
          }
        ],
        "tags": {
          "Name": "lab-eu-north-1-vpc",
          "Project": "network-infrastructure",
          "Terraform": "true",
          "Environment": "production"
        }
      },
      {
        "id": "vpc-05b5920e463e9a82b",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "eu-north-1",
        "instances": [],
        "tags": {}
      },
      {
        "id": "vpc-00613666bbf826344",
        "name": "humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-vpc",
        "cidr": "10.96.0.0/16",
        "region": "eu-north-1",
        "instances": [],
        "tags": {
          "Name": "humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-vpc",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_SERVICE": "prefect"
        }
      },
      {
        "id": "vpc-0aab0c7ab152bce5b",
        "name": "lab-us-west-2-vpc",
        "cidr": "10.0.0.0/16",
        "region": "us-west-2",
        "instances": [
          {
            "id": "i-0f81908e2826c92d4",
            "name": "coder-ius-workspace",
            "type": "g6.4xlarge",
            "state": "stopped",
            "private_ip": "10.0.130.252",
            "public_ip": null,
            "vpc_id": "vpc-0aab0c7ab152bce5b",
            "subnet_id": "subnet-0af74d62382d09be1",
            "az": "us-west-2a",
            "security_groups": [
              "sg-01d6f22f87e359d94"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "coder",
              "Coder_Provisioned": "true",
              "Name": "coder-ius-workspace",
              "HM_COST_TAG_ENV": "alpha",
              "HM_COST_TAG_USER": "ius",
              "HM_COST_TAG_GROUP": "control",
              "aws-dlami-autogenerated-tag-do-not-delete": "250428 PR21 Isaac Sim Coder Image US",
              "HM_COST_TAG_PROJECT": "general"
            },
            "network_interfaces": [
              {
                "id": "eni-08ef01c4649aaa080",
                "subnet_id": "subnet-0af74d62382d09be1",
                "private_ip": "10.0.130.252",
                "public_ip": null,
                "mac": "02:2a:0c:5c:2c:93",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-01d6f22f87e359d94"
                ]
              }
            ]
          }
        ],
        "tags": {
          "Name": "lab-us-west-2-vpc"
        }
      },
      {
        "id": "vpc-0da7cd54df9b385e4",
        "name": "packer-vpc",
        "cidr": "10.1.0.0/16",
        "region": "us-west-2",
        "instances": [],
        "tags": {
          "Name": "packer-vpc"
        }
      },
      {
        "id": "vpc-028c5f171f9b93e38",
        "name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-vpc",
        "cidr": "10.246.0.0/16",
        "region": "us-west-2",
        "instances": [],
        "tags": {
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_ENV": "production",
          "Name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-vpc"
        }
      },
      {
        "id": "vpc-018c61725c49d5d9a",
        "name": "hmnd-ml-vpc-dev-us-west-1",
        "cidr": "10.1.0.0/16",
        "region": "us-west-1",
        "instances": [
          {
            "id": "i-0e0af99120980ddcc",
            "name": "dmac-kubectl-prefect-ubuntu",
            "type": "t3.large",
            "state": "running",
            "private_ip": "10.1.10.40",
            "public_ip": "54.241.84.233",
            "vpc_id": "vpc-018c61725c49d5d9a",
            "subnet_id": "subnet-028efb33ad3d62f9b",
            "az": "us-west-1a",
            "security_groups": [
              "sg-063566d0137773a12"
            ],
            "tags": {
              "OS": "Ubuntu-22.04",
              "HM_COST_TAG_USER": "dmac",
              "ManagedBy": "manual",
              "Project": "HMND-ML",
              "HM_COST_TAG_SERVICE": "dev-vm",
              "Name": "dmac-kubectl-prefect-ubuntu",
              "Purpose": "kubectl-prefect-workloads"
            },
            "network_interfaces": [
              {
                "id": "eni-0950d6ba4e9a8c477",
                "subnet_id": "subnet-028efb33ad3d62f9b",
                "private_ip": "10.1.10.40",
                "public_ip": "54.241.84.233",
                "mac": "06:34:b3:f6:4a:d1",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-063566d0137773a12"
                ]
              }
            ]
          },
          {
            "id": "i-0b50770b0b655f1c4",
            "name": "hmnd-ml-eks-node-dev-us-west-1",
            "type": "m5.large",
            "state": "running",
            "private_ip": "10.1.66.171",
            "public_ip": null,
            "vpc_id": "vpc-018c61725c49d5d9a",
            "subnet_id": "subnet-06f02c2f719778af6",
            "az": "us-west-1a",
            "security_groups": [
              "sg-09a0d5aaaed83009d"
            ],
            "tags": {
              "k8s.io/cluster-autoscaler/enabled": "true",
              "aws:eks:cluster-name": "hmnd-ml-dev-us-west-1",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-us-west-1": "owned",
              "Project": "HMND-ML",
              "ManagedBy": "Terraform",
              "aws:ec2launchtemplate:version": "2",
              "aws:ec2:fleet-id": "fleet-17b40e0c-e484-ee94-2cb0-27a04d47a1b8",
              "aws:ec2launchtemplate:id": "lt-0c77278ef2f3cd0a1",
              "aws:autoscaling:groupName": "eks-hmnd-ml-nodes-dev-us-west-1-32ccb619-7f87-47b5-c2e9-f9bf4b6a66d5",
              "kubernetes.io/cluster/hmnd-ml-dev-us-west-1": "owned",
              "Region": "us-west-1",
              "Purpose": "ml-compute",
              "eks:cluster-name": "hmnd-ml-dev-us-west-1",
              "Environment": "dev",
              "HM_COST_TAG_SERVICE": "ec2-eks-system",
              "eks:nodegroup-name": "hmnd-ml-nodes-dev-us-west-1",
              "Name": "hmnd-ml-eks-node-dev-us-west-1"
            },
            "network_interfaces": [
              {
                "id": "eni-06290b3e39a0b5313",
                "subnet_id": "subnet-06f02c2f719778af6",
                "private_ip": "10.1.66.171",
                "public_ip": null,
                "mac": "06:44:a2:6b:99:5b",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-09a0d5aaaed83009d"
                ]
              },
              {
                "id": "eni-03328ed5c73bedf88",
                "subnet_id": "subnet-06f02c2f719778af6",
                "private_ip": "10.1.65.16",
                "public_ip": null,
                "mac": "06:ee:5d:93:0e:05",
                "device_index": 1,
                "description": "aws-K8S-i-0b50770b0b655f1c4",
                "security_groups": [
                  "sg-09a0d5aaaed83009d"
                ]
              },
              {
                "id": "eni-04adbf20fce7e91e8",
                "subnet_id": "subnet-06f02c2f719778af6",
                "private_ip": "10.1.64.116",
                "public_ip": null,
                "mac": "06:fc:a6:28:4a:07",
                "device_index": 2,
                "description": "aws-K8S-i-0b50770b0b655f1c4",
                "security_groups": [
                  "sg-09a0d5aaaed83009d"
                ]
              }
            ]
          },
          {
            "id": "i-064e682e46737b245",
            "name": "hmnd-ml-eks-node-dev-us-west-1",
            "type": "m5.large",
            "state": "running",
            "private_ip": "10.1.80.185",
            "public_ip": null,
            "vpc_id": "vpc-018c61725c49d5d9a",
            "subnet_id": "subnet-06162af46f40935b2",
            "az": "us-west-1b",
            "security_groups": [
              "sg-09a0d5aaaed83009d"
            ],
            "tags": {
              "Environment": "dev",
              "aws:autoscaling:groupName": "eks-hmnd-ml-nodes-dev-us-west-1-32ccb619-7f87-47b5-c2e9-f9bf4b6a66d5",
              "kubernetes.io/cluster/hmnd-ml-dev-us-west-1": "owned",
              "Name": "hmnd-ml-eks-node-dev-us-west-1",
              "aws:ec2:fleet-id": "fleet-891e3097-fba6-cc8d-8e92-81a08e6286ef",
              "eks:nodegroup-name": "hmnd-ml-nodes-dev-us-west-1",
              "Purpose": "ml-compute",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-us-west-1": "owned",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "aws:ec2launchtemplate:id": "lt-0c77278ef2f3cd0a1",
              "aws:eks:cluster-name": "hmnd-ml-dev-us-west-1",
              "aws:ec2launchtemplate:version": "2",
              "HM_COST_TAG_SERVICE": "ec2-eks-system",
              "ManagedBy": "Terraform",
              "Project": "HMND-ML",
              "eks:cluster-name": "hmnd-ml-dev-us-west-1",
              "Region": "us-west-1"
            },
            "network_interfaces": [
              {
                "id": "eni-0db840af2238945b8",
                "subnet_id": "subnet-06162af46f40935b2",
                "private_ip": "10.1.92.113",
                "public_ip": null,
                "mac": "02:a8:dd:7c:91:45",
                "device_index": 1,
                "description": "aws-K8S-i-064e682e46737b245",
                "security_groups": [
                  "sg-09a0d5aaaed83009d"
                ]
              },
              {
                "id": "eni-02ee2c603dfb7cab9",
                "subnet_id": "subnet-06162af46f40935b2",
                "private_ip": "10.1.95.49",
                "public_ip": null,
                "mac": "02:8d:b2:08:95:4f",
                "device_index": 2,
                "description": "aws-K8S-i-064e682e46737b245",
                "security_groups": [
                  "sg-09a0d5aaaed83009d"
                ]
              },
              {
                "id": "eni-0772bad625a5b0bff",
                "subnet_id": "subnet-06162af46f40935b2",
                "private_ip": "10.1.80.185",
                "public_ip": null,
                "mac": "02:65:7c:41:92:17",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-09a0d5aaaed83009d"
                ]
              }
            ]
          }
        ],
        "tags": {
          "ManagedBy": "Terraform",
          "Name": "hmnd-ml-vpc-dev-us-west-1",
          "Purpose": "ml-workloads-fsx-lustre",
          "kubernetes.io/cluster/hmnd-ml-dev-us-west-1": "shared",
          "Region": "us-west-1",
          "Environment": "dev",
          "Project": "HMND-ML"
        }
      },
      {
        "id": "vpc-0843dca91e5e4b27e",
        "name": "humanoid-lab-uce-us-west-1-SPOT_p5-48xlarge-vpc",
        "cidr": "10.134.0.0/16",
        "region": "us-west-1",
        "instances": [],
        "tags": {
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac",
          "Name": "humanoid-lab-uce-us-west-1-SPOT_p5-48xlarge-vpc",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_SERVICE": "prefect"
        }
      },
      {
        "id": "vpc-006b54fa0165dba13",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "us-west-1",
        "instances": [],
        "tags": {}
      },
      {
        "id": "vpc-094933326926cea6e",
        "name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksVPC",
        "cidr": "10.53.0.0/16",
        "region": "eu-west-2",
        "instances": [
          {
            "id": "i-0541168f0ea1966dd",
            "name": "dbricks",
            "type": "t2.nano",
            "state": "running",
            "private_ip": "10.53.0.172",
            "public_ip": null,
            "vpc_id": "vpc-094933326926cea6e",
            "subnet_id": "subnet-05dd478c41aa47262",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-06a4d2cf35471df4b"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "databricks-worker",
              "Name": "dbricks"
            },
            "network_interfaces": [
              {
                "id": "eni-01ad25c5e276c37a4",
                "subnet_id": "subnet-05dd478c41aa47262",
                "private_ip": "10.53.0.172",
                "public_ip": null,
                "mac": "06:b7:dd:6d:25:df",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-06a4d2cf35471df4b"
                ]
              }
            ]
          },
          {
            "id": "i-0e4e797be4cf80fa2",
            "name": "mdukov test",
            "type": "t2.micro",
            "state": "running",
            "private_ip": "10.53.0.181",
            "public_ip": null,
            "vpc_id": "vpc-094933326926cea6e",
            "subnet_id": "subnet-05dd478c41aa47262",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-091dc0dd9c0733e12"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "dev-vm",
              "Name": "mdukov test",
              "HM_COST_TAG_USER": "mdukov"
            },
            "network_interfaces": [
              {
                "id": "eni-0062f9f0e606fc0fc",
                "subnet_id": "subnet-05dd478c41aa47262",
                "private_ip": "10.53.0.181",
                "public_ip": null,
                "mac": "06:ac:25:a7:7d:e9",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-091dc0dd9c0733e12"
                ]
              }
            ]
          },
          {
            "id": "i-0afc6185c8111c8cc",
            "name": "workerenv-2982982158993688-afae1ccb-3b35-4f1d-afd7-5e90d6a3adfc-worker",
            "type": "c4.4xlarge",
            "state": "running",
            "private_ip": "10.53.197.171",
            "public_ip": null,
            "vpc_id": "vpc-094933326926cea6e",
            "subnet_id": "subnet-028a26ab98353ce33",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-0ab6d2f79668baf6e"
            ],
            "tags": {
              "HM_COST_TAG_PROJECT": "databricks",
              "ResourceClass": "SingleNode",
              "ClusterName": "ingest_prometheus_metrics",
              "Creator": "sfed@skl.vc",
              "management_service": "instance_manager_service",
              "Name": "workerenv-2982982158993688-afae1ccb-3b35-4f1d-afd7-5e90d6a3adfc-worker",
              "ClusterId": "0218-165818-prosx1xq",
              "Vendor": "Databricks",
              "HM_COST_TAG_SERVICE": "databricks-ec2-prometheus-ingest"
            },
            "network_interfaces": [
              {
                "id": "eni-0db8af55aab3de03f",
                "subnet_id": "subnet-028a26ab98353ce33",
                "private_ip": "10.53.197.171",
                "public_ip": null,
                "mac": "0a:8a:ff:3a:d0:d3",
                "device_index": 0,
                "description": "databricks_netif",
                "security_groups": [
                  "sg-0ab6d2f79668baf6e"
                ]
              }
            ]
          }
        ],
        "tags": {
          "Name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksVPC",
          "Vendor": "Databricks",
          "aws:cloudformation:stack-name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71",
          "aws:cloudformation:stack-id": "arn:aws:cloudformation:eu-west-2:767828728064:stack/AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71/2072bcd0-f805-11ef-bda0-0202abced499",
          "aws:cloudformation:logical-id": "DBSVpc"
        }
      },
      {
        "id": "vpc-064b86b11d9115a70",
        "name": "lab",
        "cidr": "172.31.0.0/16",
        "region": "eu-west-2",
        "instances": [
          {
            "id": "i-02fb1bbb84b197ef5",
            "name": "gw-2a-vpn",
            "type": "c7i.2xlarge",
            "state": "running",
            "private_ip": "172.31.9.238",
            "public_ip": "35.178.237.19",
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-004aaae93f1c2bf12",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0dd57778deccaecf7"
            ],
            "tags": {
              "Policy": "protected",
              "HM_COST_TAG_SERVICE": "vpn-gateways",
              "Name": "gw-2a-vpn"
            },
            "network_interfaces": [
              {
                "id": "eni-05b4beadf5c9bc5fa",
                "subnet_id": "subnet-004aaae93f1c2bf12",
                "private_ip": "172.31.9.238",
                "public_ip": "35.178.237.19",
                "mac": "06:3c:5f:b1:cf:65",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0dd57778deccaecf7"
                ]
              }
            ]
          },
          {
            "id": "i-0f96df12419e4ceba",
            "name": "dmac-workstation",
            "type": "g4dn.2xlarge",
            "state": "stopped",
            "private_ip": "172.31.22.165",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0a9082da517f0b8a2"
            ],
            "tags": {
              "Policy": "protected",
              "AutoStopWorkEnd": "22",
              "AutoStopCpuLimit": "3",
              "AutoStopNetOutLimit": "3000",
              "aws-dlami-autogenerated-tag-do-not-delete": "workstation-dcv-isaac-ros",
              "AutoStopWorkStart": "8",
              "Name": "dmac-workstation",
              "Owner": "dmac",
              "AutoStopInactiveHours": "2",
              "AutoStopNetInLimit": "3000",
              "Type": "workstation"
            },
            "network_interfaces": [
              {
                "id": "eni-02eefc3d89c2144ca",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.22.165",
                "public_ip": null,
                "mac": "06:d3:0c:60:a5:59",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0a9082da517f0b8a2"
                ]
              }
            ]
          },
          {
            "id": "i-021416757cf1a71b8",
            "name": "mata-workstation",
            "type": "g4dn.2xlarge",
            "state": "stopped",
            "private_ip": "172.31.21.212",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-023f193030815f8cd"
            ],
            "tags": {
              "Policy": "protected",
              "AutoStopCpuLimit": "3",
              "Name": "mata-workstation",
              "_AutoStopInactiveHours": "2",
              "AutoStopNetInLimit": "3000",
              "AutoStopWorkStart": "10",
              "Owner": "mata",
              "Type": "workstation",
              "AutoStopWorkEnd": "18",
              "AutoStopNetOutLimit": "3000"
            },
            "network_interfaces": [
              {
                "id": "eni-00e04ad04d05c4c73",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.21.212",
                "public_ip": null,
                "mac": "06:70:e7:90:37:e1",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-023f193030815f8cd"
                ]
              }
            ]
          },
          {
            "id": "i-0d76ac7dffa3b9c8c",
            "name": "server-coolify",
            "type": "t2.medium",
            "state": "running",
            "private_ip": "172.31.30.172",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0968388d2224b98d7"
            ],
            "tags": {
              "Policy": "protected",
              "HM_COST_TAG_SERVICE": "coolify",
              "Name": "server-coolify"
            },
            "network_interfaces": [
              {
                "id": "eni-0e9e24b564bd6f61e",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.30.172",
                "public_ip": null,
                "mac": "06:ad:06:0d:85:21",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0968388d2224b98d7"
                ]
              }
            ]
          },
          {
            "id": "i-0512f93e09b46e2f8",
            "name": "server-coder",
            "type": "t2.large",
            "state": "running",
            "private_ip": "172.31.27.108",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0c2a7801c154df644"
            ],
            "tags": {
              "Policy": "protected",
              "Name": "server-coder",
              "HM_COST_TAG_SERVICE": "coder"
            },
            "network_interfaces": [
              {
                "id": "eni-058244cdf8a40f240",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.27.108",
                "public_ip": null,
                "mac": "06:f7:9d:b1:7c:e5",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0c2a7801c154df644"
                ]
              }
            ]
          },
          {
            "id": "i-0e5ec3d743d5645f2",
            "name": "server-authentik",
            "type": "t2.large",
            "state": "running",
            "private_ip": "172.31.29.167",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-04bc829996b25d2a7"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "authentik",
              "Policy": "protected",
              "Name": "server-authentik"
            },
            "network_interfaces": [
              {
                "id": "eni-040aff86dde05d28d",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.29.167",
                "public_ip": null,
                "mac": "06:36:c6:51:fb:fd",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-04bc829996b25d2a7"
                ]
              }
            ]
          },
          {
            "id": "i-092808f97fea6a003",
            "name": "coder-dalm-workspace",
            "type": "g6.xlarge",
            "state": "running",
            "private_ip": "172.31.27.189",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-039183fd84ecae7fd"
            ],
            "tags": {
              "HM_COST_TAG_GROUP": "manipulation",
              "aws-dlami-autogenerated-tag-do-not-delete": "workstation-dcv-isaac-ros",
              "Coder_Provisioned": "true",
              "HM_COST_TAG_SERVICE": "coder",
              "HM_COST_TAG_USER": "dalm",
              "HM_COST_TAG_ENV": "pre_alpha",
              "HM_COST_TAG_PROJECT": "tesco_poc",
              "Name": "coder-dalm-workspace"
            },
            "network_interfaces": [
              {
                "id": "eni-0db30c969e61215c0",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.27.189",
                "public_ip": null,
                "mac": "06:67:9c:33:e4:93",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-039183fd84ecae7fd"
                ]
              }
            ]
          },
          {
            "id": "i-0f3614107edcc719b",
            "name": "isaac-poc",
            "type": "g4dn.2xlarge",
            "state": "stopped",
            "private_ip": "172.31.22.93",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0c9e10471313cf4e7"
            ],
            "tags": {
              "Name": "isaac-poc"
            },
            "network_interfaces": [
              {
                "id": "eni-0ce4262789d313c7e",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.22.93",
                "public_ip": null,
                "mac": "06:84:c7:a3:af:b7",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0c9e10471313cf4e7"
                ]
              }
            ]
          },
          {
            "id": "i-02bc8fd9140692c82",
            "name": "maxd-workstation",
            "type": "g4dn.xlarge",
            "state": "stopped",
            "private_ip": "172.31.21.255",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-023f193030815f8cd"
            ],
            "tags": {
              "Name": "maxd-workstation"
            },
            "network_interfaces": [
              {
                "id": "eni-09f0b6e1c33fee4fa",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.21.255",
                "public_ip": null,
                "mac": "06:52:e7:ed:18:27",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-023f193030815f8cd"
                ]
              }
            ]
          },
          {
            "id": "i-089066d3a739240dc",
            "name": "isaac-test",
            "type": "g4dn.xlarge",
            "state": "stopped",
            "private_ip": "172.31.21.144",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0fdf0800b8d80750e"
            ],
            "tags": {
              "Name": "isaac-test"
            },
            "network_interfaces": [
              {
                "id": "eni-0ecddd783a7d2b50f",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.21.144",
                "public_ip": null,
                "mac": "06:ae:0e:85:11:91",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0fdf0800b8d80750e"
                ]
              }
            ]
          },
          {
            "id": "i-04321a612a96a54ac",
            "name": "gitsync-test",
            "type": "t4g.nano",
            "state": "stopped",
            "private_ip": "172.31.21.237",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-09bd1dd3acfe39079"
            ],
            "tags": {
              "Name": "gitsync-test"
            },
            "network_interfaces": [
              {
                "id": "eni-0502ea9452e8e7d38",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.21.237",
                "public_ip": null,
                "mac": "06:60:22:9a:fc:f7",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-09bd1dd3acfe39079"
                ]
              }
            ]
          },
          {
            "id": "i-01c32ebddb96c3f34",
            "name": "data-flywheel-portal",
            "type": "m7i.2xlarge",
            "state": "running",
            "private_ip": "172.31.17.25",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0dea1110605ed1794"
            ],
            "tags": {
              "Name": "data-flywheel-portal",
              "HM_COST_TAG_SERVICE": "data-flywheel-portal"
            },
            "network_interfaces": [
              {
                "id": "eni-062190442d6802843",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.17.25",
                "public_ip": null,
                "mac": "06:f8:88:8b:40:b7",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0dea1110605ed1794"
                ]
              }
            ]
          },
          {
            "id": "i-068dcf84dc6ee7a7d",
            "name": "poc_vpn_gw",
            "type": "t2.micro",
            "state": "running",
            "private_ip": "172.31.2.135",
            "public_ip": "3.8.1.55",
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-004aaae93f1c2bf12",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0dd57778deccaecf7"
            ],
            "tags": {
              "Name": "poc_vpn_gw",
              "HM_COST_TAG_SERVICE": "vpn-gateways"
            },
            "network_interfaces": [
              {
                "id": "eni-00f0697362146e415",
                "subnet_id": "subnet-004aaae93f1c2bf12",
                "private_ip": "172.31.2.135",
                "public_ip": "3.8.1.55",
                "mac": "06:02:ee:5d:52:3f",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0dd57778deccaecf7"
                ]
              }
            ]
          },
          {
            "id": "i-0ec2a4b809f732506",
            "name": "sky-sky-jobs-controller-365e2493-365e2493-head",
            "type": "c6i.xlarge",
            "state": "stopped",
            "private_ip": "172.31.1.187",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-004aaae93f1c2bf12",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-031e7780d5cfe661b"
            ],
            "tags": {
              "ManagedBy": "skypilot",
              "ray-cluster-name": "sky-jobs-controller-365e2493-365e2493",
              "Owner": "{{USER}}",
              "Team": "shared",
              "Environment": "production",
              "ray-node-type": "head",
              "skypilot-head-node": "1",
              "Name": "sky-sky-jobs-controller-365e2493-365e2493-head",
              "skypilot-cluster-name": "sky-jobs-controller-365e2493-365e2493",
              "skypilot-user": "ntb",
              "Project": "hmnd-cloud"
            },
            "network_interfaces": [
              {
                "id": "eni-0f4d36eb8be3eb845",
                "subnet_id": "subnet-004aaae93f1c2bf12",
                "private_ip": "172.31.1.187",
                "public_ip": null,
                "mac": "06:31:d6:8e:47:eb",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-031e7780d5cfe661b"
                ]
              }
            ]
          },
          {
            "id": "i-08ac57710dd02b529",
            "name": "vpn-deployment",
            "type": "t3.medium",
            "state": "running",
            "private_ip": "172.31.10.2",
            "public_ip": "13.43.239.105",
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-004aaae93f1c2bf12",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0dd57778deccaecf7"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "vpn-gateways",
              "Name": "vpn-deployment"
            },
            "network_interfaces": [
              {
                "id": "eni-0929b3260dd6ce1f7",
                "subnet_id": "subnet-004aaae93f1c2bf12",
                "private_ip": "172.31.10.2",
                "public_ip": "13.43.239.105",
                "mac": "06:8d:97:40:88:1f",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0dd57778deccaecf7"
                ]
              }
            ]
          },
          {
            "id": "i-0ac76b402587550db",
            "name": "humanoid-console-ubuntu",
            "type": "t2.medium",
            "state": "stopped",
            "private_ip": "172.31.32.12",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-0e58728fa58e7443f",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-00e15893612402eee"
            ],
            "tags": {
              "Name": "humanoid-console-ubuntu"
            },
            "network_interfaces": [
              {
                "id": "eni-0364aa9301758e5db",
                "subnet_id": "subnet-0e58728fa58e7443f",
                "private_ip": "172.31.32.12",
                "public_ip": null,
                "mac": "0a:87:c6:67:cd:51",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-00e15893612402eee"
                ]
              }
            ]
          },
          {
            "id": "i-0d1a929ebdb62aa31",
            "name": "codg_build_arm64",
            "type": "c6gd.4xlarge",
            "state": "stopped",
            "private_ip": "172.31.32.7",
            "public_ip": "35.176.238.159",
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-0e58728fa58e7443f",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-050d1a67a282cef34"
            ],
            "tags": {
              "Name": "codg_build_arm64"
            },
            "network_interfaces": [
              {
                "id": "eni-01c8fe4ada126be1f",
                "subnet_id": "subnet-0e58728fa58e7443f",
                "private_ip": "172.31.32.7",
                "public_ip": "35.176.238.159",
                "mac": "0a:da:11:00:4e:2d",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-050d1a67a282cef34"
                ]
              }
            ]
          },
          {
            "id": "i-078ee976b6ca00ec2",
            "name": "github-runner-x64",
            "type": "t3a.2xlarge",
            "state": "running",
            "private_ip": "172.31.48.8",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-00bfbc041b7ac4e95",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-0120bef45ab4b005b"
            ],
            "tags": {
              "Name": "github-runner-x64"
            },
            "network_interfaces": [
              {
                "id": "eni-0fe5ee75c9328556b",
                "subnet_id": "subnet-00bfbc041b7ac4e95",
                "private_ip": "172.31.48.8",
                "public_ip": null,
                "mac": "0a:c0:e9:37:7a:a7",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0120bef45ab4b005b"
                ]
              }
            ]
          },
          {
            "id": "i-05f627ad041baf6fb",
            "name": "github-runner-arm64",
            "type": "t4g.2xlarge",
            "state": "running",
            "private_ip": "172.31.48.4",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-00bfbc041b7ac4e95",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-0120bef45ab4b005b"
            ],
            "tags": {
              "Name": "github-runner-arm64"
            },
            "network_interfaces": [
              {
                "id": "eni-07b0ecab346286b0d",
                "subnet_id": "subnet-00bfbc041b7ac4e95",
                "private_ip": "172.31.48.4",
                "public_ip": null,
                "mac": "0a:8d:b1:79:98:e1",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0120bef45ab4b005b"
                ]
              }
            ]
          },
          {
            "id": "i-0a2a8a74b519c6d26",
            "name": "github-runner-x64-optimized",
            "type": "c5n.2xlarge",
            "state": "running",
            "private_ip": "172.31.48.14",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-00bfbc041b7ac4e95",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-0120bef45ab4b005b"
            ],
            "tags": {
              "Name": "github-runner-x64-optimized",
              "ConfigVersion": "v3-force-replacement",
              "Performance": "high-throughput",
              "Type": "optimized"
            },
            "network_interfaces": [
              {
                "id": "eni-0feef6ccf9098ec09",
                "subnet_id": "subnet-00bfbc041b7ac4e95",
                "private_ip": "172.31.48.14",
                "public_ip": null,
                "mac": "0a:90:08:9d:b1:13",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0120bef45ab4b005b"
                ]
              }
            ]
          },
          {
            "id": "i-0ac77ea2e09183905",
            "name": "codg-sim-testing",
            "type": "g4dn.2xlarge",
            "state": "stopped",
            "private_ip": "172.31.27.98",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-04cf4b8ee86aeb9e4"
            ],
            "tags": {
              "Name": "codg-sim-testing"
            },
            "network_interfaces": [
              {
                "id": "eni-003e7c3710a0e175a",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.27.98",
                "public_ip": null,
                "mac": "06:a7:0a:88:33:9f",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-04cf4b8ee86aeb9e4"
                ]
              }
            ]
          },
          {
            "id": "i-097e3890a52be33df",
            "name": "coder-ius-workspace",
            "type": "g4dn.xlarge",
            "state": "stopped",
            "private_ip": "172.31.29.7",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-039183fd84ecae7fd"
            ],
            "tags": {
              "Coder_Provisioned": "true",
              "HM_COST_TAG_USER": "ius",
              "HM_COST_TAG_ENV": "pre_alpha",
              "HM_COST_TAG_SERVICE": "coder",
              "aws-dlami-autogenerated-tag-do-not-delete": "workstation-dcv-isaac-ros",
              "HM_COST_TAG_GROUP": "control",
              "HM_COST_TAG_PROJECT": "general",
              "Name": "coder-ius-workspace"
            },
            "network_interfaces": [
              {
                "id": "eni-0a967d560354fef7d",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.29.7",
                "public_ip": null,
                "mac": "06:50:6b:81:96:77",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-039183fd84ecae7fd"
                ]
              }
            ]
          },
          {
            "id": "i-03bfe8e5a9773ce7e",
            "name": "coder-ius-workspace",
            "type": "g4dn.xlarge",
            "state": "stopped",
            "private_ip": "172.31.23.131",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-039183fd84ecae7fd"
            ],
            "tags": {
              "HM_COST_TAG_ENV": "pre_alpha",
              "HM_COST_TAG_GROUP": "infra",
              "Name": "coder-ius-workspace",
              "aws-dlami-autogenerated-tag-do-not-delete": "workstation-dcv-isaac-ros",
              "Coder_Provisioned": "true",
              "HM_COST_TAG_PROJECT": "general",
              "HM_COST_TAG_SERVICE": "coder",
              "HM_COST_TAG_USER": "ius"
            },
            "network_interfaces": [
              {
                "id": "eni-0d505ce6261be0b98",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.23.131",
                "public_ip": null,
                "mac": "06:d9:3b:83:d3:eb",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-039183fd84ecae7fd"
                ]
              }
            ]
          },
          {
            "id": "i-0b71e35c35d688665",
            "name": "coder-cfil-workspace",
            "type": "g6.4xlarge",
            "state": "stopped",
            "private_ip": "172.31.22.75",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-039183fd84ecae7fd"
            ],
            "tags": {
              "HM_COST_TAG_GROUP": "vla",
              "HM_COST_TAG_SERVICE": "coder",
              "Coder_Provisioned": "true",
              "HM_COST_TAG_ENV": "pre_alpha",
              "HM_COST_TAG_USER": "cfil",
              "Name": "coder-cfil-workspace",
              "HM_COST_TAG_PROJECT": "general"
            },
            "network_interfaces": [
              {
                "id": "eni-07f66e52d765a4cdc",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.22.75",
                "public_ip": null,
                "mac": "06:af:13:33:18:bf",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-039183fd84ecae7fd"
                ]
              }
            ]
          },
          {
            "id": "i-0767ed5e9d8bfb664",
            "name": "coder-ssam-workspace",
            "type": "g5.4xlarge",
            "state": "stopped",
            "private_ip": "172.31.20.55",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-039183fd84ecae7fd"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "coder",
              "Name": "coder-ssam-workspace",
              "HM_COST_TAG_GROUP": "control",
              "HM_COST_TAG_PROJECT": "general",
              "HM_COST_TAG_USER": "ssam",
              "aws-dlami-autogenerated-tag-do-not-delete": "workstation-dcv-isaac-ros",
              "Coder_Provisioned": "true",
              "HM_COST_TAG_ENV": "alpha"
            },
            "network_interfaces": [
              {
                "id": "eni-0ae20934e9a3bd1bc",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.20.55",
                "public_ip": null,
                "mac": "06:fb:05:c0:68:3f",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-039183fd84ecae7fd"
                ]
              }
            ]
          },
          {
            "id": "i-0e88e65b9a03364fc",
            "name": "coder-ius-workspace",
            "type": "g4dn.xlarge",
            "state": "stopped",
            "private_ip": "172.31.29.148",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-039183fd84ecae7fd"
            ],
            "tags": {
              "HM_COST_TAG_ENV": "alpha",
              "HM_COST_TAG_SERVICE": "coder",
              "Name": "coder-ius-workspace",
              "aws-dlami-autogenerated-tag-do-not-delete": "workstation-dcv-isaac-ros",
              "Coder_Provisioned": "true",
              "HM_COST_TAG_USER": "ius",
              "HM_COST_TAG_GROUP": "control",
              "HM_COST_TAG_PROJECT": "general"
            },
            "network_interfaces": [
              {
                "id": "eni-0fbc323daba99b8bd",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.29.148",
                "public_ip": null,
                "mac": "06:42:ab:7b:eb:c9",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-039183fd84ecae7fd"
                ]
              }
            ]
          },
          {
            "id": "i-0e91b1967135afa02",
            "name": "coder-ius-workspace",
            "type": "g4dn.xlarge",
            "state": "stopped",
            "private_ip": "172.31.28.153",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-039183fd84ecae7fd"
            ],
            "tags": {
              "HM_COST_TAG_ENV": "alpha",
              "HM_COST_TAG_GROUP": "control",
              "Name": "coder-ius-workspace",
              "aws-dlami-autogenerated-tag-do-not-delete": "workstation-dcv-isaac-ros",
              "Coder_Provisioned": "true",
              "HM_COST_TAG_PROJECT": "general",
              "HM_COST_TAG_SERVICE": "coder",
              "HM_COST_TAG_USER": "ius"
            },
            "network_interfaces": [
              {
                "id": "eni-014f9d5e89d8614af",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.28.153",
                "public_ip": null,
                "mac": "06:89:39:91:43:bd",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-039183fd84ecae7fd"
                ]
              }
            ]
          },
          {
            "id": "i-01f2d86c8307e483c",
            "name": "sam-fleet-dev",
            "type": "t4g.2xlarge",
            "state": "running",
            "private_ip": "172.31.8.251",
            "public_ip": "35.177.129.5",
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-004aaae93f1c2bf12",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0fd168fe0a3c8e876"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "dev-vm",
              "Name": "sam-fleet-dev",
              "HM_COST_TAG_USER": "sam"
            },
            "network_interfaces": [
              {
                "id": "eni-0f43ed9c13caa64d4",
                "subnet_id": "subnet-004aaae93f1c2bf12",
                "private_ip": "172.31.8.251",
                "public_ip": "35.177.129.5",
                "mac": "06:10:4c:f0:4b:39",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0fd168fe0a3c8e876"
                ]
              }
            ]
          },
          {
            "id": "i-07f91b7ab8d6b3c88",
            "name": "cursor-agent-ssm-relay",
            "type": "t4g.small",
            "state": "running",
            "private_ip": "172.31.27.201",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-038086629e7b1b9ff"
            ],
            "tags": {
              "Team": "infra",
              "HM_COST_TAG_GROUP": "infra",
              "ManagedBy": "cli",
              "HM_COST_TAG_USER": "general",
              "Name": "cursor-agent-ssm-relay",
              "HM_COST_TAG_PROJECT": "cursor-cloud",
              "Purpose": "cursor-cloud-ssm-relay",
              "HM_COST_TAG_SERVICE": "cursor-cloud",
              "HM_COST_TAG_ENV": "prod"
            },
            "network_interfaces": [
              {
                "id": "eni-070c1ff3d1abb6d18",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.27.201",
                "public_ip": null,
                "mac": "06:01:c9:2c:22:a5",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-038086629e7b1b9ff"
                ]
              }
            ]
          },
          {
            "id": "i-004d4658ce58d5be3",
            "name": "infra-dashboard-probe",
            "type": "t4g.medium",
            "state": "running",
            "private_ip": "172.31.30.110",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0a53c6016eb5b4804"
            ],
            "tags": {
              "HM_COST_TAG_ENV": "prod",
              "HM_COST_TAG_USER": "general",
              "Purpose": "infra-dashboard",
              "TerraformDomain": "hmnd-network/infra-dashboard",
              "Name": "infra-dashboard-probe",
              "Region": "eu-west-2",
              "HM_COST_TAG_PROJECT": "infra-dashboard",
              "Team": "infra",
              "Environment": "production",
              "ManagedBy": "terraform",
              "HM_COST_TAG_GROUP": "infra",
              "HM_COST_TAG_SERVICE": "infra-dashboard"
            },
            "network_interfaces": [
              {
                "id": "eni-0c9f20ad418fcb66b",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.30.110",
                "public_ip": null,
                "mac": "06:54:1c:21:6b:d7",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0a53c6016eb5b4804"
                ]
              }
            ]
          },
          {
            "id": "i-037dd778153e59690",
            "name": "tjac-reverseshell",
            "type": "t3.micro",
            "state": "stopped",
            "private_ip": "172.31.32.5",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-0e58728fa58e7443f",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-0e7027b0307c563b4"
            ],
            "tags": {
              "Name": "tjac-reverseshell"
            },
            "network_interfaces": [
              {
                "id": "eni-0acac01350eaefe32",
                "subnet_id": "subnet-0e58728fa58e7443f",
                "private_ip": "172.31.32.5",
                "public_ip": null,
                "mac": "0a:6a:94:cc:8f:b7",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0e7027b0307c563b4"
                ]
              }
            ]
          },
          {
            "id": "i-0e20c3a8659baef80",
            "name": "coder-RicardoDelfin-workspace",
            "type": "g4dn.xlarge",
            "state": "stopped",
            "private_ip": "172.31.31.164",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-039183fd84ecae7fd"
            ],
            "tags": {
              "aws-dlami-autogenerated-tag-do-not-delete": "workstation-dcv-isaac-ros",
              "HM_COST_TAG_PROJECT": "general",
              "Name": "coder-RicardoDelfin-workspace",
              "HM_COST_TAG_USER": "RicardoDelfin",
              "HM_COST_TAG_ENV": "alpha",
              "Coder_Provisioned": "true",
              "HM_COST_TAG_GROUP": "infra",
              "HM_COST_TAG_SERVICE": "coder"
            },
            "network_interfaces": [
              {
                "id": "eni-0503bc74e6ed8a0cd",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.31.164",
                "public_ip": null,
                "mac": "06:d0:00:36:a1:c3",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-039183fd84ecae7fd"
                ]
              }
            ]
          },
          {
            "id": "i-0860eef0f57df8db5",
            "name": "coder-nebr-workspace",
            "type": "g4dn.4xlarge",
            "state": "stopped",
            "private_ip": "172.31.21.112",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-039183fd84ecae7fd"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "coder",
              "Coder_Provisioned": "true",
              "Name": "coder-nebr-workspace",
              "HM_COST_TAG_ENV": "beta",
              "HM_COST_TAG_PROJECT": "general",
              "HM_COST_TAG_GROUP": "simulation",
              "HM_COST_TAG_USER": "nebr"
            },
            "network_interfaces": [
              {
                "id": "eni-0201665d29aa297da",
                "subnet_id": "subnet-06c6dd49ea348c9fa",
                "private_ip": "172.31.21.112",
                "public_ip": null,
                "mac": "06:26:a6:6a:67:ad",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-039183fd84ecae7fd"
                ]
              }
            ]
          },
          {
            "id": "i-098b5e0ef90c866d7",
            "name": "rdelfin-devvm",
            "type": "t3.xlarge",
            "state": "running",
            "private_ip": "172.31.65.177",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-0068f0b99d020a06b",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-066a3bf374ee525bd"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "dev-vm",
              "Name": "rdelfin-devvm",
              "HM_COST_TAG_USER": "rdelfin"
            },
            "network_interfaces": [
              {
                "id": "eni-082ddd508590ef6df",
                "subnet_id": "subnet-0068f0b99d020a06b",
                "private_ip": "172.31.65.177",
                "public_ip": null,
                "mac": "0a:64:4c:c7:db:29",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-066a3bf374ee525bd"
                ]
              }
            ]
          },
          {
            "id": "i-06beb2fd0bd784401",
            "name": "forge-cloud-fleet-metal",
            "type": "c5n.metal",
            "state": "stopped",
            "private_ip": "172.31.97.137",
            "public_ip": null,
            "vpc_id": "vpc-064b86b11d9115a70",
            "subnet_id": "subnet-0751336b834bc07ef",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-071f7692d80d00713"
            ],
            "tags": {
              "Owner": "forge",
              "Name": "forge-cloud-fleet-metal",
              "Purpose": "hmnd-cloud-fleet-rtpc-orin"
            },
            "network_interfaces": [
              {
                "id": "eni-076cb97e97a1d5bc9",
                "subnet_id": "subnet-0751336b834bc07ef",
                "private_ip": "172.31.97.137",
                "public_ip": null,
                "mac": "0a:74:de:fb:69:6d",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-071f7692d80d00713"
                ]
              }
            ]
          }
        ],
        "tags": {
          "Policy": "protected",
          "Name": "lab"
        }
      },
      {
        "id": "vpc-033eb69021e3deafb",
        "name": "hmnd-ml-vpc-dev-eu-west-2",
        "cidr": "10.3.0.0/16",
        "region": "eu-west-2",
        "instances": [
          {
            "id": "i-0140351e4d1cbaaf2",
            "name": "hmnd-ml-grafana-stack-dev-eu-west-2",
            "type": "m5.xlarge",
            "state": "running",
            "private_ip": "10.3.76.100",
            "public_ip": "18.170.5.194",
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0379e30a82da9d80f",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "Name": "hmnd-ml-grafana-stack-dev-eu-west-2",
              "Region": "eu-west-2",
              "Purpose": "grafana-observability-stack",
              "Environment": "dev",
              "Project": "HMND-ML",
              "ManagedBy": "Terraform"
            },
            "network_interfaces": [
              {
                "id": "eni-05f4dc397b9ad80b1",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.76.100",
                "public_ip": "18.170.5.194",
                "mac": "06:ae:e5:e1:db:2d",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-03ca9483e16daccf4",
            "name": "hmnd-ml-p5-node-dev-eu-west-2",
            "type": "p5.48xlarge",
            "state": "running",
            "private_ip": "10.3.91.97",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "ec2-p5-gpu",
              "aws:ec2launchtemplate:id": "lt-06cca66abbae2df90",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "aws:autoscaling:groupName": "eks-hmnd-ml-p5-dev-eu-west-2-58cda43d-8ee4-71fb-fa78-ac74629fb00b",
              "Purpose": "p5-training",
              "eks:nodegroup-name": "hmnd-ml-p5-dev-eu-west-2",
              "ManagedBy": "Terraform",
              "Environment": "dev",
              "aws:ec2launchtemplate:version": "1",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Project": "HMND-ML",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Region": "eu-west-2",
              "aws:ec2:fleet-id": "fleet-609dd20c-bf07-641c-049a-2f00217d6e4b",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "CapacityReservationId": "cr-006a0d2c6e1cf9b81,cr-0d6441b3dffd94160",
              "Name": "hmnd-ml-p5-node-dev-eu-west-2",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned"
            },
            "network_interfaces": [
              {
                "id": "eni-0600ddcd1bd4ce217",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.81.130",
                "public_ip": null,
                "mac": "0a:20:57:15:a8:b7",
                "device_index": 1,
                "description": "aws-K8S-i-03ca9483e16daccf4",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-0e9093425631d2146",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.91.97",
                "public_ip": null,
                "mac": "0a:1f:d4:f0:c3:4f",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-06411d2201629f66e",
            "name": "hmnd-ml-p5-node-dev-eu-west-2",
            "type": "p5.48xlarge",
            "state": "running",
            "private_ip": "10.3.83.17",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "ec2-p5-gpu",
              "aws:ec2launchtemplate:id": "lt-06cca66abbae2df90",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned",
              "aws:autoscaling:groupName": "eks-hmnd-ml-p5-dev-eu-west-2-58cda43d-8ee4-71fb-fa78-ac74629fb00b",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "eks:nodegroup-name": "hmnd-ml-p5-dev-eu-west-2",
              "Project": "HMND-ML",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "ManagedBy": "Terraform",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "Purpose": "p5-training",
              "aws:ec2launchtemplate:version": "1",
              "Environment": "dev",
              "Region": "eu-west-2",
              "aws:ec2:fleet-id": "fleet-609dd20c-bf07-641c-049a-2f00217d6e4b",
              "Name": "hmnd-ml-p5-node-dev-eu-west-2",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "CapacityReservationId": "cr-006a0d2c6e1cf9b81,cr-0d6441b3dffd94160"
            },
            "network_interfaces": [
              {
                "id": "eni-098ef809bd6fa5769",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.89.131",
                "public_ip": null,
                "mac": "0a:35:6e:c2:4a:c3",
                "device_index": 1,
                "description": "aws-K8S-i-06411d2201629f66e",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-0966c26bd669f98df",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.83.17",
                "public_ip": null,
                "mac": "0a:6b:ba:28:d0:41",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-064dc61bf24f1138c",
            "name": "hmnd-ml-p5-node-dev-eu-west-2",
            "type": "p5.48xlarge",
            "state": "running",
            "private_ip": "10.3.81.145",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "Region": "eu-west-2",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "ManagedBy": "Terraform",
              "Project": "HMND-ML",
              "Environment": "dev",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "Purpose": "p5-training",
              "aws:autoscaling:groupName": "eks-hmnd-ml-p5-dev-eu-west-2-58cda43d-8ee4-71fb-fa78-ac74629fb00b",
              "aws:ec2launchtemplate:version": "1",
              "Name": "hmnd-ml-p5-node-dev-eu-west-2",
              "aws:ec2:fleet-id": "fleet-609dd20c-bf07-641c-049a-2f00217d6e4b",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:ec2launchtemplate:id": "lt-06cca66abbae2df90",
              "eks:nodegroup-name": "hmnd-ml-p5-dev-eu-west-2",
              "CapacityReservationId": "cr-006a0d2c6e1cf9b81,cr-0d6441b3dffd94160",
              "HM_COST_TAG_SERVICE": "ec2-p5-gpu",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned"
            },
            "network_interfaces": [
              {
                "id": "eni-026b6a56b5fbc10e8",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.90.131",
                "public_ip": null,
                "mac": "0a:0a:86:9a:be:85",
                "device_index": 1,
                "description": "aws-K8S-i-064dc61bf24f1138c",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-0a0ffaf9f4d110d67",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.81.145",
                "public_ip": null,
                "mac": "0a:b9:62:59:2f:25",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-03d16003896fc29b1",
            "name": "hmnd-ml-p5-node-dev-eu-west-2",
            "type": "p5.48xlarge",
            "state": "running",
            "private_ip": "10.3.87.48",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "ManagedBy": "Terraform",
              "Region": "eu-west-2",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "CapacityReservationId": "cr-006a0d2c6e1cf9b81,cr-0d6441b3dffd94160",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "aws:ec2launchtemplate:id": "lt-06cca66abbae2df90",
              "aws:ec2:fleet-id": "fleet-609dd20c-bf07-641c-049a-2f00217d6e4b",
              "Name": "hmnd-ml-p5-node-dev-eu-west-2",
              "aws:autoscaling:groupName": "eks-hmnd-ml-p5-dev-eu-west-2-58cda43d-8ee4-71fb-fa78-ac74629fb00b",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned",
              "HM_COST_TAG_SERVICE": "ec2-p5-gpu",
              "aws:ec2launchtemplate:version": "1",
              "Purpose": "p5-training",
              "Environment": "dev",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Project": "HMND-ML",
              "eks:nodegroup-name": "hmnd-ml-p5-dev-eu-west-2"
            },
            "network_interfaces": [
              {
                "id": "eni-09e04bd0a31c9afd4",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.86.0",
                "public_ip": null,
                "mac": "0a:e2:21:72:94:d3",
                "device_index": 1,
                "description": "aws-K8S-i-03d16003896fc29b1",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-0ee3b32062534d10f",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.87.48",
                "public_ip": null,
                "mac": "0a:c2:d7:52:fb:b5",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-02f391b85215101b5",
            "name": "tjac-gpu",
            "type": "g4dn.xlarge",
            "state": "stopped",
            "private_ip": "10.3.6.249",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-05e3b850ac2203676",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0b293017d0f742a10"
            ],
            "tags": {
              "Name": "tjac-gpu"
            },
            "network_interfaces": [
              {
                "id": "eni-0c09b6ebb6d89a206",
                "subnet_id": "subnet-05e3b850ac2203676",
                "private_ip": "10.3.6.249",
                "public_ip": null,
                "mac": "06:9f:38:a0:5e:a7",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0b293017d0f742a10"
                ]
              }
            ]
          },
          {
            "id": "i-055d0db437dc441ec",
            "name": "tjac-gpu-2",
            "type": "g4dn.xlarge",
            "state": "stopped",
            "private_ip": "10.3.5.8",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-05e3b850ac2203676",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0b293017d0f742a10"
            ],
            "tags": {
              "Name": "tjac-gpu-2"
            },
            "network_interfaces": [
              {
                "id": "eni-07cfa8e13bc75484a",
                "subnet_id": "subnet-05e3b850ac2203676",
                "private_ip": "10.3.5.8",
                "public_ip": null,
                "mac": "06:34:4f:8c:c0:ab",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0b293017d0f742a10"
                ]
              }
            ]
          },
          {
            "id": "i-0db434d79b2d845f4",
            "name": "hmnd-ml-p5-node-dev-eu-west-2",
            "type": "p5.48xlarge",
            "state": "running",
            "private_ip": "10.3.89.197",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "Purpose": "p5-training",
              "eks:nodegroup-name": "hmnd-ml-p5-dev-eu-west-2",
              "Environment": "dev",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:autoscaling:groupName": "eks-hmnd-ml-p5-dev-eu-west-2-58cda43d-8ee4-71fb-fa78-ac74629fb00b",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "ManagedBy": "Terraform",
              "aws:ec2launchtemplate:version": "1",
              "Project": "HMND-ML",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Region": "eu-west-2",
              "HM_COST_TAG_SERVICE": "ec2-p5-gpu",
              "aws:ec2launchtemplate:id": "lt-06cca66abbae2df90",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned",
              "Name": "hmnd-ml-p5-node-dev-eu-west-2",
              "aws:ec2:fleet-id": "fleet-d4154c3d-802d-6c07-869a-212068c4dd6e",
              "CapacityReservationId": "cr-006a0d2c6e1cf9b81,cr-0d6441b3dffd94160"
            },
            "network_interfaces": [
              {
                "id": "eni-047d32d76f91e3091",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.89.197",
                "public_ip": null,
                "mac": "0a:19:b3:4c:d2:71",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-04c4414bfa41c52fa",
            "name": "hmnd-ml-eks-node-dev-eu-west-2",
            "type": "m5.xlarge",
            "state": "running",
            "private_ip": "10.3.92.103",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "eks:nodegroup-name": "hmnd-ml-nodes-dev-eu-west-2",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned",
              "Project": "HMND-ML",
              "aws:ec2launchtemplate:id": "lt-03de7b583fae2ec30",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Region": "eu-west-2",
              "ManagedBy": "Terraform",
              "aws:ec2launchtemplate:version": "2",
              "aws:autoscaling:groupName": "eks-hmnd-ml-nodes-dev-eu-west-2-8ace04df-611a-f97b-e322-407f0fa45b33",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "Environment": "dev",
              "Name": "hmnd-ml-eks-node-dev-eu-west-2",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "HM_COST_TAG_SERVICE": "ec2-eks-system",
              "aws:ec2:fleet-id": "fleet-dc9feeb5-8227-e4a7-8490-ab0ac12bde5a",
              "Purpose": "ml-compute",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned"
            },
            "network_interfaces": [
              {
                "id": "eni-0fdbba27f0c3b5e61",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.92.103",
                "public_ip": null,
                "mac": "0a:6b:a4:69:1c:9f",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-08d07390ed7831a91",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.86.67",
                "public_ip": null,
                "mac": "0a:7b:b4:53:56:5d",
                "device_index": 1,
                "description": "aws-K8S-i-04c4414bfa41c52fa",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-0382fb539ab2babac",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.86.39",
                "public_ip": null,
                "mac": "0a:96:10:9f:5f:ef",
                "device_index": 2,
                "description": "aws-K8S-i-04c4414bfa41c52fa",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-07e921fd37766a475",
            "name": "hmnd-ml-p5-mig-node-dev-eu-west-2",
            "type": "p5.48xlarge",
            "state": "running",
            "private_ip": "10.3.95.87",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "eks:nodegroup-name": "hmnd-ml-p5-mig-dev-eu-west-2",
              "CapacityReservationId": "cr-006a0d2c6e1cf9b81,cr-0d6441b3dffd94160",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Region": "eu-west-2",
              "aws:ec2:fleet-id": "fleet-d69f64b7-2a05-6c07-a6ba-a1020df9b7a6",
              "ManagedBy": "Terraform",
              "Environment": "dev",
              "Project": "HMND-ML",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:autoscaling:groupName": "eks-hmnd-ml-p5-mig-dev-eu-west-2-18ce931f-0488-d8b4-0d7b-f96175edd2ee",
              "Purpose": "p5-training",
              "aws:ec2launchtemplate:id": "lt-0be899382c1094e62",
              "aws:ec2launchtemplate:version": "11",
              "HM_COST_TAG_SERVICE": "ec2-p5-gpu",
              "Name": "hmnd-ml-p5-mig-node-dev-eu-west-2",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned"
            },
            "network_interfaces": [
              {
                "id": "eni-038fde27abb58bfb7",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.91.130",
                "public_ip": null,
                "mac": "0a:16:d0:27:5f:0d",
                "device_index": 1,
                "description": "aws-K8S-i-07e921fd37766a475",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-060d7e1a6dd0ebe90",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.95.87",
                "public_ip": null,
                "mac": "0a:0a:aa:12:3b:53",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0ae4e22ecab59a30d",
            "name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node",
            "type": "r7i.8xlarge",
            "state": "running",
            "private_ip": "10.3.83.140",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "ec2-cpu-only-capacity",
              "ManagedBy": "Terraform",
              "Purpose": "cpu-only-capacity",
              "InstanceFamily": "general",
              "AvailabilityZone": "",
              "karpenter.sh/nodeclaim": "cpu-only-capacity-v5mgf",
              "CapacityType": "on-demand",
              "aws:ec2launchtemplate:id": "lt-0b07c5036021bcfa9",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "NodeType": "cpu",
              "aws:ec2:fleet-id": "fleet-de3d6e15-a0a5-4ca5-2e98-83a814f7b133",
              "karpenter.k8s.aws/ec2nodeclass": "cpu-only-nodeclass",
              "karpenter.sh/nodepool": "cpu-only-capacity",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "ReservedCapacity": "false",
              "Name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Environment": "dev",
              "Project": "HMND-ML",
              "aws:ec2launchtemplate:version": "1"
            },
            "network_interfaces": [
              {
                "id": "eni-0f7b2825efb7f449f",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.83.140",
                "public_ip": null,
                "mac": "0a:82:9a:e5:85:8b",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0f80333baafc3126c",
            "name": "hmnd-ml-eks-node-dev-eu-west-2",
            "type": "m5.xlarge",
            "state": "running",
            "private_ip": "10.3.105.201",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0b8b4508a7a5e8d1b",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "Name": "hmnd-ml-eks-node-dev-eu-west-2",
              "HM_COST_TAG_SERVICE": "ec2-eks-system",
              "aws:ec2launchtemplate:id": "lt-03de7b583fae2ec30",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Region": "eu-west-2",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "Purpose": "ml-compute",
              "aws:ec2:fleet-id": "fleet-c0975286-3f8f-e6be-0c90-870a4de7934b",
              "aws:ec2launchtemplate:version": "2",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned",
              "eks:nodegroup-name": "hmnd-ml-nodes-dev-eu-west-2",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Project": "HMND-ML",
              "Environment": "dev",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "aws:autoscaling:groupName": "eks-hmnd-ml-nodes-dev-eu-west-2-8ace04df-611a-f97b-e322-407f0fa45b33",
              "ManagedBy": "Terraform"
            },
            "network_interfaces": [
              {
                "id": "eni-0bdb948b8b6944906",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.105.201",
                "public_ip": null,
                "mac": "02:eb:bc:42:13:8b",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-0bf2872b0f068f1d5",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.102.97",
                "public_ip": null,
                "mac": "02:5d:2a:88:35:b1",
                "device_index": 2,
                "description": "aws-K8S-i-0f80333baafc3126c",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-0abaea2897a499aa6",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.107.99",
                "public_ip": null,
                "mac": "02:c0:62:39:3f:73",
                "device_index": 1,
                "description": "aws-K8S-i-0f80333baafc3126c",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0bc57babb5c0ff40d",
            "name": "hmnd-ml-eks-node-dev-eu-west-2",
            "type": "m5.xlarge",
            "state": "running",
            "private_ip": "10.3.70.69",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0379e30a82da9d80f",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "HM_COST_TAG_SERVICE": "ec2-eks-system",
              "aws:ec2:fleet-id": "fleet-68bf5aa6-9785-6c3c-aeba-27a288297e00",
              "Name": "hmnd-ml-eks-node-dev-eu-west-2",
              "Project": "HMND-ML",
              "aws:ec2launchtemplate:version": "2",
              "ManagedBy": "Terraform",
              "aws:ec2launchtemplate:id": "lt-03de7b583fae2ec30",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:autoscaling:groupName": "eks-hmnd-ml-nodes-dev-eu-west-2-8ace04df-611a-f97b-e322-407f0fa45b33",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "Region": "eu-west-2",
              "Purpose": "ml-compute",
              "Environment": "dev",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned",
              "eks:nodegroup-name": "hmnd-ml-nodes-dev-eu-west-2"
            },
            "network_interfaces": [
              {
                "id": "eni-0ba4fd6432fadf392",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.75.195",
                "public_ip": null,
                "mac": "06:73:bc:aa:af:49",
                "device_index": 1,
                "description": "aws-K8S-i-0bc57babb5c0ff40d",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-0252cbd0be9e4b579",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.70.69",
                "public_ip": null,
                "mac": "06:5d:47:13:db:5b",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-02ce1247e335f606c",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node",
            "type": "g7e.2xlarge",
            "state": "running",
            "private_ip": "10.3.73.175",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0379e30a82da9d80f",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "ReservedCapacity": "false",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g7e-2xl-gpu-nodeclass",
              "aws:ec2launchtemplate:version": "1",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "InstanceFamily": "general",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node",
              "aws:ec2launchtemplate:id": "lt-091631a8359fc482d",
              "CapacityType": "on-demand",
              "Purpose": "simulation-g7e-2xl-gpu",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g7e-2xl-gpu",
              "Project": "HMND-ML",
              "NodeType": "gpu",
              "ManagedBy": "Terraform",
              "AvailabilityZone": "",
              "Environment": "dev",
              "aws:ec2:fleet-id": "fleet-42267384-6db4-c99c-043a-8c22c874d010",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodeclaim": "simulation-g7e-2xl-gpu-p8jgr",
              "karpenter.sh/nodepool": "simulation-g7e-2xl-gpu"
            },
            "network_interfaces": [
              {
                "id": "eni-0bc5d777c1db0ae7c",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.73.175",
                "public_ip": null,
                "mac": "06:3b:66:a6:9a:79",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-04e46d32f524f6919",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
            "type": "g6.8xlarge",
            "state": "running",
            "private_ip": "10.3.66.140",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0379e30a82da9d80f",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:ec2:fleet-id": "fleet-60b5d024-bfad-4e3c-2e3a-87886a666e35",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "NodeType": "gpu",
              "Project": "HMND-ML",
              "karpenter.sh/nodepool": "simulation-g6-gpu",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
              "CapacityType": "on-demand",
              "Purpose": "simulation-g6-gpu",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "AvailabilityZone": "",
              "Environment": "dev",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g6-gpu-nodeclass",
              "karpenter.sh/nodeclaim": "simulation-g6-gpu-7h5j8",
              "InstanceFamily": "general",
              "ManagedBy": "Terraform",
              "aws:ec2launchtemplate:version": "1",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g6-gpu",
              "ReservedCapacity": "false",
              "aws:ec2launchtemplate:id": "lt-01b708cf5e7bdc68a"
            },
            "network_interfaces": [
              {
                "id": "eni-0322684aa787ee6eb",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.66.140",
                "public_ip": null,
                "mac": "06:96:73:13:13:25",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-088dfab62dd348017",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
            "type": "g6.8xlarge",
            "state": "running",
            "private_ip": "10.3.64.97",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0379e30a82da9d80f",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "InstanceFamily": "general",
              "ManagedBy": "Terraform",
              "karpenter.sh/nodepool": "simulation-g6-gpu",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g6-gpu-nodeclass",
              "CapacityType": "on-demand",
              "AvailabilityZone": "",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:ec2:fleet-id": "fleet-e286d924-e73c-4b3c-2e92-0ca04208715e",
              "karpenter.sh/nodeclaim": "simulation-g6-gpu-fpk87",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "NodeType": "gpu",
              "Purpose": "simulation-g6-gpu",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "aws:ec2launchtemplate:version": "1",
              "ReservedCapacity": "false",
              "aws:ec2launchtemplate:id": "lt-0b54b217c922b4a46",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Environment": "dev",
              "Project": "HMND-ML",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g6-gpu"
            },
            "network_interfaces": [
              {
                "id": "eni-01d1c41247737f656",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.64.97",
                "public_ip": null,
                "mac": "06:23:ee:40:0f:d1",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0e4797cc42c9c8da4",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node",
            "type": "g7e.2xlarge",
            "state": "running",
            "private_ip": "10.3.64.143",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0379e30a82da9d80f",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "ReservedCapacity": "false",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g7e-2xl-gpu-nodeclass",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodepool": "simulation-g7e-2xl-gpu",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "CapacityType": "on-demand",
              "Purpose": "simulation-g7e-2xl-gpu",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g7e-2xl-gpu",
              "NodeType": "gpu",
              "Project": "HMND-ML",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "AvailabilityZone": "",
              "Environment": "dev",
              "InstanceFamily": "general",
              "ManagedBy": "Terraform",
              "aws:ec2:fleet-id": "fleet-c0a4fb8c-cdbe-eb36-2cba-a42acdd05181",
              "aws:ec2launchtemplate:version": "1",
              "karpenter.sh/nodeclaim": "simulation-g7e-2xl-gpu-t9bq6",
              "aws:ec2launchtemplate:id": "lt-06d12f89e5561e98e"
            },
            "network_interfaces": [
              {
                "id": "eni-0d54c021260b5ef63",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.64.143",
                "public_ip": null,
                "mac": "06:ad:a3:17:b7:47",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-09ea50e7abf9ddd67",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node",
            "type": "g7e.2xlarge",
            "state": "running",
            "private_ip": "10.3.64.123",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0379e30a82da9d80f",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "ReservedCapacity": "false",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g7e-2xl-gpu-nodeclass",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node",
              "aws:ec2:fleet-id": "fleet-4a8ed3a4-c716-c336-8e98-0c805571e739",
              "karpenter.sh/nodeclaim": "simulation-g7e-2xl-gpu-v2sll",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g7e-2xl-gpu",
              "NodeType": "gpu",
              "karpenter.sh/nodepool": "simulation-g7e-2xl-gpu",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "Purpose": "simulation-g7e-2xl-gpu",
              "InstanceFamily": "general",
              "ManagedBy": "Terraform",
              "Project": "HMND-ML",
              "aws:ec2launchtemplate:id": "lt-0645e6f99762e6512",
              "CapacityType": "on-demand",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "Environment": "dev",
              "AvailabilityZone": "",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:ec2launchtemplate:version": "1"
            },
            "network_interfaces": [
              {
                "id": "eni-09320ffe9a857ef9f",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.64.123",
                "public_ip": null,
                "mac": "06:11:c9:5f:7c:69",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-035d3b23d85df765e",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node",
            "type": "g7e.2xlarge",
            "state": "running",
            "private_ip": "10.3.65.146",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0379e30a82da9d80f",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodeclaim": "simulation-g7e-2xl-gpu-lcs98",
              "AvailabilityZone": "",
              "Environment": "dev",
              "InstanceFamily": "general",
              "ManagedBy": "Terraform",
              "aws:ec2launchtemplate:version": "1",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g7e-2xl-gpu-nodeclass",
              "ReservedCapacity": "false",
              "aws:ec2:fleet-id": "fleet-f4bfecbf-800d-6e85-8498-8b0258acee75",
              "aws:ec2launchtemplate:id": "lt-061b6d6c0739f5c43",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g7e-2xl-gpu",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "NodeType": "gpu",
              "Project": "HMND-ML",
              "karpenter.sh/nodepool": "simulation-g7e-2xl-gpu",
              "CapacityType": "on-demand",
              "Purpose": "simulation-g7e-2xl-gpu"
            },
            "network_interfaces": [
              {
                "id": "eni-06b3bb81fb7ef45f8",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.65.146",
                "public_ip": null,
                "mac": "06:6a:08:48:c5:af",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0b9e6b94e2575ff05",
            "name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node",
            "type": "r7i.16xlarge",
            "state": "running",
            "private_ip": "10.3.72.29",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0379e30a82da9d80f",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "ec2-cpu-only-github",
              "Environment": "dev",
              "aws:ec2launchtemplate:version": "1",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodepool": "cpu-only-github",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "AvailabilityZone": "",
              "Name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node",
              "aws:ec2:fleet-id": "fleet-609ff8ac-3f27-6c1c-ae30-8728562721ee",
              "CapacityType": "on-demand",
              "Project": "HMND-ML",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "NodeType": "cpu",
              "karpenter.sh/nodeclaim": "cpu-only-github-flr65",
              "ManagedBy": "Terraform",
              "Purpose": "cpu-only-github",
              "karpenter.k8s.aws/ec2nodeclass": "cpu-only-github-nodeclass",
              "InstanceFamily": "general",
              "ReservedCapacity": "false",
              "aws:ec2launchtemplate:id": "lt-0a1f5bccefb1a9d8c"
            },
            "network_interfaces": [
              {
                "id": "eni-038a2997d527fffe0",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.72.29",
                "public_ip": null,
                "mac": "06:25:24:e3:d2:77",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-038a7302de06fad97",
            "name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node",
            "type": "m6g.4xlarge",
            "state": "running",
            "private_ip": "10.3.74.199",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0379e30a82da9d80f",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "AvailabilityZone": "",
              "karpenter.k8s.aws/ec2nodeclass": "github-arc-arm-nodeclass",
              "InstanceFamily": "general",
              "NodeType": "workload",
              "CapacityType": "on-demand",
              "aws:ec2:fleet-id": "fleet-d41fceb5-00a7-4685-a698-a3a0fa242024",
              "ManagedBy": "Terraform",
              "aws:ec2launchtemplate:id": "lt-059189e6ef21433db",
              "aws:ec2launchtemplate:version": "1",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodeclaim": "github-arc-arm-2njjr",
              "Environment": "dev",
              "Project": "HMND-ML",
              "karpenter.sh/nodepool": "github-arc-arm",
              "Name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node",
              "HM_COST_TAG_SERVICE": "ec2-github-arc-arm",
              "Purpose": "github-arc-arm",
              "ReservedCapacity": "false",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2"
            },
            "network_interfaces": [
              {
                "id": "eni-03aec62fc2cd658f2",
                "subnet_id": "subnet-0379e30a82da9d80f",
                "private_ip": "10.3.74.199",
                "public_ip": null,
                "mac": "06:2a:6b:a9:61:57",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0332a72c4ce7be639",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
            "type": "g6.8xlarge",
            "state": "running",
            "private_ip": "10.3.84.128",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "HM_COST_TAG_SERVICE": "ec2-simulation-g6-gpu",
              "CapacityType": "on-demand",
              "aws:ec2:fleet-id": "fleet-e28ed384-6f9c-cb96-ac1a-0e800e942ca2",
              "InstanceFamily": "general",
              "ManagedBy": "Terraform",
              "karpenter.sh/nodepool": "simulation-g6-gpu",
              "Project": "HMND-ML",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "AvailabilityZone": "",
              "Environment": "dev",
              "aws:ec2launchtemplate:version": "1",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
              "ReservedCapacity": "false",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodeclaim": "simulation-g6-gpu-vqf7l",
              "aws:ec2launchtemplate:id": "lt-04211fdc1c19a92fb",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g6-gpu-nodeclass",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "NodeType": "gpu",
              "Purpose": "simulation-g6-gpu"
            },
            "network_interfaces": [
              {
                "id": "eni-0727005031a0749e1",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.84.128",
                "public_ip": null,
                "mac": "0a:c0:8b:f5:54:ad",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0b9766c5eac5fb78c",
            "name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node",
            "type": "r7i.8xlarge",
            "state": "running",
            "private_ip": "10.3.92.124",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "karpenter.sh/nodepool": "cpu-only-capacity",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "HM_COST_TAG_SERVICE": "ec2-cpu-only-capacity",
              "aws:ec2launchtemplate:id": "lt-0068c66932b5b311f",
              "InstanceFamily": "general",
              "Purpose": "cpu-only-capacity",
              "ManagedBy": "Terraform",
              "aws:ec2:fleet-id": "fleet-4a9f780e-bd05-c6b6-ae9a-a7aa479a6fb6",
              "CapacityType": "on-demand",
              "aws:ec2launchtemplate:version": "1",
              "AvailabilityZone": "",
              "Environment": "dev",
              "Project": "HMND-ML",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodeclaim": "cpu-only-capacity-c8z4b",
              "Name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "ReservedCapacity": "false",
              "karpenter.k8s.aws/ec2nodeclass": "cpu-only-nodeclass",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "NodeType": "cpu"
            },
            "network_interfaces": [
              {
                "id": "eni-01e87b278d2a29361",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.92.124",
                "public_ip": null,
                "mac": "0a:ca:d3:84:d0:9d",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-049fc159d8ccbfae9",
            "name": "hmnd-ml-p5-mig-node-dev-eu-west-2",
            "type": "p5.48xlarge",
            "state": "running",
            "private_ip": "10.3.92.36",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "ManagedBy": "Terraform",
              "aws:ec2launchtemplate:version": "11",
              "Region": "eu-west-2",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:ec2:fleet-id": "fleet-ca8e732c-e5b4-693c-2c92-2682fc231692",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Environment": "dev",
              "Project": "HMND-ML",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned",
              "CapacityReservationId": "cr-006a0d2c6e1cf9b81,cr-0d6441b3dffd94160",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "Name": "hmnd-ml-p5-mig-node-dev-eu-west-2",
              "Purpose": "p5-training",
              "aws:autoscaling:groupName": "eks-hmnd-ml-p5-mig-dev-eu-west-2-18ce931f-0488-d8b4-0d7b-f96175edd2ee",
              "eks:nodegroup-name": "hmnd-ml-p5-mig-dev-eu-west-2",
              "aws:ec2launchtemplate:id": "lt-0be899382c1094e62"
            },
            "network_interfaces": [
              {
                "id": "eni-00b353b613ea9121f",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.92.36",
                "public_ip": null,
                "mac": "0a:a3:0e:67:f4:c3",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-0a4fc22cfb418cabf",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.84.117",
                "public_ip": null,
                "mac": "0a:34:71:1a:be:0f",
                "device_index": 1,
                "description": "aws-K8S-i-049fc159d8ccbfae9",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-08b6f21284791611d",
            "name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node",
            "type": "r7i.8xlarge",
            "state": "running",
            "private_ip": "10.3.80.194",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "karpenter.sh/nodeclaim": "cpu-only-capacity-c6mgq",
              "aws:ec2launchtemplate:id": "lt-05a98f2619674b94b",
              "AvailabilityZone": "",
              "Environment": "dev",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodepool": "cpu-only-capacity",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "aws:ec2:fleet-id": "fleet-6a9ffaa4-9da7-64b6-8c32-8d803383a684",
              "Purpose": "cpu-only-capacity",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "CapacityType": "on-demand",
              "karpenter.k8s.aws/ec2nodeclass": "cpu-only-nodeclass",
              "NodeType": "cpu",
              "Project": "HMND-ML",
              "HM_COST_TAG_SERVICE": "ec2-cpu-only-capacity",
              "ManagedBy": "Terraform",
              "Name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node",
              "aws:ec2launchtemplate:version": "1",
              "ReservedCapacity": "false",
              "InstanceFamily": "general"
            },
            "network_interfaces": [
              {
                "id": "eni-0a17299c69361c055",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.80.194",
                "public_ip": null,
                "mac": "0a:92:a9:75:70:81",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0d7241d53ed95fbe5",
            "name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node",
            "type": "r7i.8xlarge",
            "state": "running",
            "private_ip": "10.3.80.127",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "InstanceFamily": "general",
              "ManagedBy": "Terraform",
              "karpenter.sh/nodepool": "cpu-only-capacity",
              "CapacityType": "on-demand",
              "Environment": "dev",
              "Project": "HMND-ML",
              "AvailabilityZone": "",
              "aws:ec2launchtemplate:id": "lt-024b202f72e488a2c",
              "karpenter.sh/nodeclaim": "cpu-only-capacity-rbmdm",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:ec2:fleet-id": "fleet-5c9d6e1f-a2a5-648d-2612-03287b55f08b",
              "HM_COST_TAG_SERVICE": "ec2-cpu-only-capacity",
              "aws:ec2launchtemplate:version": "1",
              "Name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node",
              "ReservedCapacity": "false",
              "NodeType": "cpu",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "karpenter.k8s.aws/ec2nodeclass": "cpu-only-nodeclass",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "Purpose": "cpu-only-capacity"
            },
            "network_interfaces": [
              {
                "id": "eni-0e0b2a5311ad241bb",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.80.127",
                "public_ip": null,
                "mac": "0a:b4:b6:c6:78:03",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0f3e5a9d69df3230b",
            "name": "hmnd-ml-p5-node-dev-eu-west-2",
            "type": "p5.48xlarge",
            "state": "running",
            "private_ip": "10.3.83.49",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "ManagedBy": "Terraform",
              "eks:nodegroup-name": "hmnd-ml-p5-dev-eu-west-2",
              "Environment": "dev",
              "Purpose": "p5-training",
              "Region": "eu-west-2",
              "eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "CapacityReservationId": "cr-006a0d2c6e1cf9b81,cr-0d6441b3dffd94160",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "aws:ec2launchtemplate:version": "1",
              "aws:ec2launchtemplate:id": "lt-06cca66abbae2df90",
              "Project": "HMND-ML",
              "k8s.io/cluster-autoscaler/hmnd-ml-dev-eu-west-2": "owned",
              "Name": "hmnd-ml-p5-node-dev-eu-west-2",
              "aws:ec2:fleet-id": "fleet-6aaed986-c79e-eb14-0438-8688330b95a3",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "aws:autoscaling:groupName": "eks-hmnd-ml-p5-dev-eu-west-2-58cda43d-8ee4-71fb-fa78-ac74629fb00b"
            },
            "network_interfaces": [
              {
                "id": "eni-0b1e29a523aefb25d",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.83.49",
                "public_ip": null,
                "mac": "0a:08:70:95:dc:3b",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              },
              {
                "id": "eni-05599dbd93b2403cb",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.91.68",
                "public_ip": null,
                "mac": "0a:e2:a8:30:5d:07",
                "device_index": 1,
                "description": "aws-K8S-i-0f3e5a9d69df3230b",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-063ea88eab5bcc75a",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
            "type": "g6.8xlarge",
            "state": "running",
            "private_ip": "10.3.84.253",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "Project": "HMND-ML",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "NodeType": "gpu",
              "CapacityType": "on-demand",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodeclaim": "simulation-g6-gpu-jrsfv",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g6-gpu-nodeclass",
              "karpenter.sh/nodepool": "simulation-g6-gpu",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
              "aws:ec2launchtemplate:id": "lt-0815d17f0937e380f",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "Purpose": "simulation-g6-gpu",
              "aws:ec2:fleet-id": "fleet-5c1fee35-28a7-e68d-2432-21881ef50026",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "AvailabilityZone": "",
              "ReservedCapacity": "false",
              "Environment": "dev",
              "InstanceFamily": "general",
              "aws:ec2launchtemplate:version": "1",
              "ManagedBy": "Terraform",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g6-gpu"
            },
            "network_interfaces": [
              {
                "id": "eni-0dc28dc78541c6cac",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.84.253",
                "public_ip": null,
                "mac": "0a:cb:b7:66:89:a9",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0c6da9e215f25d197",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
            "type": "g6.8xlarge",
            "state": "running",
            "private_ip": "10.3.90.48",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "AvailabilityZone": "",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "ManagedBy": "Terraform",
              "karpenter.sh/nodepool": "simulation-g6-gpu",
              "Environment": "dev",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g6-gpu-nodeclass",
              "CapacityType": "on-demand",
              "NodeType": "gpu",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "Purpose": "simulation-g6-gpu",
              "aws:ec2launchtemplate:version": "1",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "Project": "HMND-ML",
              "aws:ec2:fleet-id": "fleet-ea2efb24-c53c-e13c-8e92-ae2a96f2d5ce",
              "karpenter.sh/nodeclaim": "simulation-g6-gpu-4ns6r",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g6-gpu",
              "ReservedCapacity": "false",
              "aws:ec2launchtemplate:id": "lt-0dcf1ac5d49bd8099",
              "InstanceFamily": "general"
            },
            "network_interfaces": [
              {
                "id": "eni-0887dcc5271c87873",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.90.48",
                "public_ip": null,
                "mac": "0a:02:f5:b0:9b:3b",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-02c86d2f891e7d835",
            "name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node",
            "type": "m6g.4xlarge",
            "state": "running",
            "private_ip": "10.3.80.81",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "ReservedCapacity": "false",
              "NodeType": "workload",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Environment": "dev",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "HM_COST_TAG_SERVICE": "ec2-github-arc-arm",
              "karpenter.k8s.aws/ec2nodeclass": "github-arc-arm-nodeclass",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "CapacityType": "on-demand",
              "ManagedBy": "Terraform",
              "karpenter.sh/nodeclaim": "github-arc-arm-765bn",
              "aws:ec2:fleet-id": "fleet-5e154617-80a5-6427-a438-ab80979ebf0b",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "Project": "HMND-ML",
              "AvailabilityZone": "",
              "Name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node",
              "aws:ec2launchtemplate:id": "lt-0f6bdef36090ea711",
              "karpenter.sh/nodepool": "github-arc-arm",
              "aws:ec2launchtemplate:version": "1",
              "InstanceFamily": "general",
              "Purpose": "github-arc-arm"
            },
            "network_interfaces": [
              {
                "id": "eni-0156d4779d18f36e5",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.80.81",
                "public_ip": null,
                "mac": "0a:5f:f1:5b:5c:31",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-078258bd1917d6a0d",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
            "type": "g6.8xlarge",
            "state": "running",
            "private_ip": "10.3.86.106",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "aws:ec2launchtemplate:version": "1",
              "NodeType": "gpu",
              "Purpose": "simulation-g6-gpu",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
              "ReservedCapacity": "false",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "karpenter.sh/nodepool": "simulation-g6-gpu",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g6-gpu-nodeclass",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g6-gpu",
              "InstanceFamily": "general",
              "aws:ec2launchtemplate:id": "lt-089de0372d828af11",
              "aws:ec2:fleet-id": "fleet-febf44b7-802f-4c0f-2c32-2388dd19a5c3",
              "karpenter.sh/nodeclaim": "simulation-g6-gpu-b997j",
              "CapacityType": "on-demand",
              "ManagedBy": "Terraform",
              "AvailabilityZone": "",
              "Environment": "dev",
              "Project": "HMND-ML",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2"
            },
            "network_interfaces": [
              {
                "id": "eni-077b0d2f1ae5fd3ea",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.86.106",
                "public_ip": null,
                "mac": "0a:13:5e:3a:72:cd",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0c98612f653aead3e",
            "name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node",
            "type": "m6g.4xlarge",
            "state": "running",
            "private_ip": "10.3.84.231",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-00e754e8d43a7de43",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "CapacityType": "on-demand",
              "Project": "HMND-ML",
              "InstanceFamily": "general",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "HM_COST_TAG_SERVICE": "ec2-github-arc-arm",
              "karpenter.sh/nodeclaim": "github-arc-arm-w2qqx",
              "ManagedBy": "Terraform",
              "karpenter.sh/nodepool": "github-arc-arm",
              "Environment": "dev",
              "aws:ec2:fleet-id": "fleet-c82653ae-6d14-c9b4-2c9a-0e02ff5c878e",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "AvailabilityZone": "",
              "NodeType": "workload",
              "ReservedCapacity": "false",
              "aws:ec2launchtemplate:version": "1",
              "karpenter.k8s.aws/ec2nodeclass": "github-arc-arm-nodeclass",
              "Purpose": "github-arc-arm",
              "Name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "aws:ec2launchtemplate:id": "lt-066323642cb1166b7",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2"
            },
            "network_interfaces": [
              {
                "id": "eni-0bbf4e86f425d5b83",
                "subnet_id": "subnet-00e754e8d43a7de43",
                "private_ip": "10.3.84.231",
                "public_ip": null,
                "mac": "0a:8f:d8:42:fc:ff",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0942b7a3d66851edb",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
            "type": "g6.8xlarge",
            "state": "running",
            "private_ip": "10.3.103.146",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0b8b4508a7a5e8d1b",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
              "aws:ec2:fleet-id": "fleet-62aef324-e51e-4b3c-2c1a-0c8ad6a0456f",
              "aws:ec2launchtemplate:version": "1",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "InstanceFamily": "general",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "ReservedCapacity": "false",
              "CapacityType": "on-demand",
              "Project": "HMND-ML",
              "Purpose": "simulation-g6-gpu",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g6-gpu",
              "aws:ec2launchtemplate:id": "lt-0c743cd8d787fc955",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "NodeType": "gpu",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g6-gpu-nodeclass",
              "ManagedBy": "Terraform",
              "karpenter.sh/nodeclaim": "simulation-g6-gpu-6lvnm",
              "karpenter.sh/nodepool": "simulation-g6-gpu",
              "AvailabilityZone": "",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "Environment": "dev"
            },
            "network_interfaces": [
              {
                "id": "eni-0d837c38b854bc77c",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.103.146",
                "public_ip": null,
                "mac": "02:e5:ed:f1:87:b1",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0d77022c43e48e37a",
            "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
            "type": "g6.8xlarge",
            "state": "running",
            "private_ip": "10.3.106.97",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0b8b4508a7a5e8d1b",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "aws:ec2launchtemplate:version": "1",
              "karpenter.sh/nodeclaim": "simulation-g6-gpu-kr6sb",
              "Project": "HMND-ML",
              "NodeType": "gpu",
              "Purpose": "simulation-g6-gpu",
              "CapacityType": "on-demand",
              "Name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "karpenter.k8s.aws/ec2nodeclass": "simulation-g6-gpu-nodeclass",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "Environment": "dev",
              "ManagedBy": "Terraform",
              "karpenter.sh/nodepool": "simulation-g6-gpu",
              "AvailabilityZone": "",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:ec2:fleet-id": "fleet-7e1f6e37-022f-640d-049a-232a2a397e68",
              "ReservedCapacity": "false",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "HM_COST_TAG_SERVICE": "ec2-simulation-g6-gpu",
              "aws:ec2launchtemplate:id": "lt-0af23647a25540b96",
              "InstanceFamily": "general"
            },
            "network_interfaces": [
              {
                "id": "eni-025e38913a5b8f60c",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.106.97",
                "public_ip": null,
                "mac": "02:7e:43:e5:5a:ab",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-013fa413bb64b7393",
            "name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node",
            "type": "m6g.4xlarge",
            "state": "running",
            "private_ip": "10.3.103.75",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0b8b4508a7a5e8d1b",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "ReservedCapacity": "false",
              "aws:ec2launchtemplate:id": "lt-06d26459448a7c1e0",
              "aws:ec2launchtemplate:version": "1",
              "HM_COST_TAG_SERVICE": "ec2-github-arc-arm",
              "Purpose": "github-arc-arm",
              "aws:ec2:fleet-id": "fleet-de1d4c95-2825-6c8d-26b2-01882c11a4a2",
              "Name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node",
              "karpenter.k8s.aws/ec2nodeclass": "github-arc-arm-nodeclass",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "ManagedBy": "Terraform",
              "CapacityType": "on-demand",
              "karpenter.sh/nodeclaim": "github-arc-arm-9vhk9",
              "InstanceFamily": "general",
              "Environment": "dev",
              "karpenter.sh/nodepool": "github-arc-arm",
              "NodeType": "workload",
              "AvailabilityZone": "",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Project": "HMND-ML"
            },
            "network_interfaces": [
              {
                "id": "eni-0213c5d1b66ce5dce",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.103.75",
                "public_ip": null,
                "mac": "02:09:79:76:04:77",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-05ea1e64acb28430e",
            "name": "karpenter-prefect-workload-node",
            "type": "c6i.xlarge",
            "state": "running",
            "private_ip": "10.3.97.208",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0b8b4508a7a5e8d1b",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "Project": "HMND-ML",
              "karpenter.sh/nodeclaim": "prefect-workloads-mhxhg",
              "Name": "karpenter-prefect-workload-node",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "aws:ec2launchtemplate:version": "1",
              "ManagedBy": "Terraform",
              "karpenter.sh/nodepool": "prefect-workloads",
              "aws:ec2launchtemplate:id": "lt-07173f92d415682fe",
              "Environment": "dev",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "aws:ec2:fleet-id": "fleet-5c9f44b7-a085-64af-8410-aba270cc7c70",
              "NodeType": "prefect-workload",
              "karpenter.k8s.aws/ec2nodeclass": "prefect-workload-nodeclass"
            },
            "network_interfaces": [
              {
                "id": "eni-0e4514837c647024a",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.97.208",
                "public_ip": null,
                "mac": "02:3e:bb:66:3f:df",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-04f3148c2f0a0554a",
            "name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node",
            "type": "r7i.8xlarge",
            "state": "running",
            "private_ip": "10.3.106.21",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0b8b4508a7a5e8d1b",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "karpenter.sh/nodepool": "cpu-only-github",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "HM_COST_TAG_SERVICE": "ec2-cpu-only-github",
              "ReservedCapacity": "false",
              "Name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node",
              "AvailabilityZone": "",
              "Environment": "dev",
              "InstanceFamily": "general",
              "ManagedBy": "Terraform",
              "karpenter.k8s.aws/ec2nodeclass": "cpu-only-github-nodeclass",
              "Purpose": "cpu-only-github",
              "aws:ec2launchtemplate:version": "1",
              "Project": "HMND-ML",
              "NodeType": "cpu",
              "aws:ec2launchtemplate:id": "lt-0f351998d85a84716",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "CapacityType": "on-demand",
              "karpenter.sh/nodeclaim": "cpu-only-github-ccvtf",
              "aws:ec2:fleet-id": "fleet-403570ac-9f0d-4cbc-84b8-25829fa56d4b",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned"
            },
            "network_interfaces": [
              {
                "id": "eni-0d6d1759b0733646a",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.106.21",
                "public_ip": null,
                "mac": "02:46:1d:57:49:91",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-042083fece0295de3",
            "name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node",
            "type": "m6g.4xlarge",
            "state": "running",
            "private_ip": "10.3.107.175",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0b8b4508a7a5e8d1b",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "aws:ec2launchtemplate:version": "1",
              "Purpose": "github-arc-arm",
              "Name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node",
              "HM_COST_TAG_SERVICE": "ec2-github-arc-arm",
              "ReservedCapacity": "false",
              "NodeType": "workload",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "karpenter.k8s.aws/ec2nodeclass": "github-arc-arm-nodeclass",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "InstanceFamily": "general",
              "ManagedBy": "Terraform",
              "aws:ec2launchtemplate:id": "lt-059189e6ef21433db",
              "CapacityType": "on-demand",
              "AvailabilityZone": "",
              "karpenter.sh/nodeclaim": "github-arc-arm-kv8kx",
              "aws:ec2:fleet-id": "fleet-42067386-c51c-e91c-0e92-2e882488feb6",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Environment": "dev",
              "Project": "HMND-ML",
              "karpenter.sh/nodepool": "github-arc-arm"
            },
            "network_interfaces": [
              {
                "id": "eni-071c90fcbf1cf41e5",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.107.175",
                "public_ip": null,
                "mac": "02:eb:71:e7:a1:0f",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-03ebfcfa57174205b",
            "name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node",
            "type": "r7i.12xlarge",
            "state": "running",
            "private_ip": "10.3.102.31",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0b8b4508a7a5e8d1b",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "aws:ec2:fleet-id": "fleet-7ebd4c17-288d-e6af-8612-0ba0cccfb797",
              "aws:ec2launchtemplate:version": "1",
              "HM_COST_TAG_SERVICE": "ec2-cpu-only-github",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "ReservedCapacity": "false",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodeclaim": "cpu-only-github-8q246",
              "NodeType": "cpu",
              "Purpose": "cpu-only-github",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
              "karpenter.k8s.aws/ec2nodeclass": "cpu-only-github-nodeclass",
              "InstanceFamily": "general",
              "CapacityType": "on-demand",
              "ManagedBy": "Terraform",
              "Name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node",
              "aws:ec2launchtemplate:id": "lt-055dcbc1ae8148fbe",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "Environment": "dev",
              "Project": "HMND-ML",
              "AvailabilityZone": "",
              "karpenter.sh/nodepool": "cpu-only-github"
            },
            "network_interfaces": [
              {
                "id": "eni-092c3fb2d1b9a4e09",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.102.31",
                "public_ip": null,
                "mac": "02:3a:33:a3:ab:3b",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          },
          {
            "id": "i-0b22ae7e7de06ccda",
            "name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node",
            "type": "r7i.8xlarge",
            "state": "running",
            "private_ip": "10.3.102.208",
            "public_ip": null,
            "vpc_id": "vpc-033eb69021e3deafb",
            "subnet_id": "subnet-0b8b4508a7a5e8d1b",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-037967f6c6f739ef8"
            ],
            "tags": {
              "aws:ec2launchtemplate:version": "1",
              "Name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node",
              "karpenter.sh/nodeclaim": "cpu-only-github-nvq6d",
              "ReservedCapacity": "false",
              "Project": "HMND-ML",
              "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
              "karpenter.sh/nodepool": "cpu-only-github",
              "CapacityType": "on-demand",
              "AvailabilityZone": "",
              "Environment": "dev",
              "ManagedBy": "Terraform",
              "Purpose": "cpu-only-github",
              "karpenter.k8s.aws/ec2nodeclass": "cpu-only-github-nodeclass",
              "InstanceFamily": "general",
              "aws:ec2launchtemplate:id": "lt-08d80136cb1233c12",
              "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned",
              "eks:eks-cluster-name": "hmnd-ml-dev-eu-west-2",
              "HM_COST_TAG_SERVICE": "ec2-cpu-only-github",
              "NodeType": "cpu",
              "aws:ec2:fleet-id": "fleet-f617661d-000d-e627-2eb2-8b2291bbcc4c",
              "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2"
            },
            "network_interfaces": [
              {
                "id": "eni-0ebb6080a55ef5870",
                "subnet_id": "subnet-0b8b4508a7a5e8d1b",
                "private_ip": "10.3.102.208",
                "public_ip": null,
                "mac": "02:53:73:27:56:c3",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-037967f6c6f739ef8"
                ]
              }
            ]
          }
        ],
        "tags": {
          "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "shared",
          "Environment": "dev",
          "Project": "HMND-ML",
          "Name": "hmnd-ml-vpc-dev-eu-west-2",
          "ManagedBy": "Terraform",
          "Region": "eu-west-2",
          "Purpose": "ml-workloads-fsx-lustre"
        }
      },
      {
        "id": "vpc-003033d62c0c872bb",
        "name": "hmnd-runner",
        "cidr": "10.31.0.0/16",
        "region": "eu-west-2",
        "instances": [
          {
            "id": "i-070e9d2aac1d1704b",
            "name": "hb-linux-arm64-ubuntu-2204-action-runner",
            "type": "c6gd.4xlarge",
            "state": "running",
            "private_ip": "10.31.2.55",
            "public_ip": "18.175.207.161",
            "vpc_id": "vpc-003033d62c0c872bb",
            "subnet_id": "subnet-0c5eec9d74d268575",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-0e8063eaa785c01eb"
            ],
            "tags": {
              "aws:ec2launchtemplate:id": "lt-07ee471f15a274c23",
              "ghr:created_by": "scale-up-lambda",
              "aws:ec2launchtemplate:version": "4",
              "ghr:ssm_config_path": "/github-action-runners/hb/linux-arm64-ubuntu-2204/runners/config",
              "ghr:Owner": "HumanoidTeam/hmnd",
              "ghr:Type": "Repo",
              "Name": "hb-linux-arm64-ubuntu-2204-action-runner",
              "ghr:Application": "github-action-runner",
              "ghr:environment": "hb-linux-arm64-ubuntu-2204",
              "ghr:github_runner_id": "20969",
              "ghr:runner_name_prefix": "ubuntu-2204-arm64_",
              "aws:ec2:fleet-id": "fleet-6297d08c-b505-c496-8490-87aacfcb095e"
            },
            "network_interfaces": [
              {
                "id": "eni-07a39108a4aae2512",
                "subnet_id": "subnet-0c5eec9d74d268575",
                "private_ip": "10.31.2.55",
                "public_ip": "18.175.207.161",
                "mac": "0a:34:1c:c1:c2:77",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0e8063eaa785c01eb"
                ]
              }
            ]
          },
          {
            "id": "i-0aa885d4d703044da",
            "name": "hb-linux-arm64-ubuntu-2204-action-runner",
            "type": "c6gd.4xlarge",
            "state": "running",
            "private_ip": "10.31.2.41",
            "public_ip": "51.24.91.143",
            "vpc_id": "vpc-003033d62c0c872bb",
            "subnet_id": "subnet-0c5eec9d74d268575",
            "az": "eu-west-2b",
            "security_groups": [
              "sg-0e8063eaa785c01eb"
            ],
            "tags": {
              "ghr:Application": "github-action-runner",
              "Name": "hb-linux-arm64-ubuntu-2204-action-runner",
              "ghr:ssm_config_path": "/github-action-runners/hb/linux-arm64-ubuntu-2204/runners/config",
              "aws:ec2:fleet-id": "fleet-4a8c53ac-c794-e13e-841a-06084e46c1b6",
              "aws:ec2launchtemplate:version": "4",
              "ghr:Type": "Repo",
              "ghr:created_by": "scale-up-lambda",
              "ghr:Owner": "HumanoidTeam/hmnd",
              "ghr:github_runner_id": "20971",
              "ghr:environment": "hb-linux-arm64-ubuntu-2204",
              "ghr:runner_name_prefix": "ubuntu-2204-arm64_",
              "aws:ec2launchtemplate:id": "lt-07ee471f15a274c23"
            },
            "network_interfaces": [
              {
                "id": "eni-0e7d4ce7b457c252d",
                "subnet_id": "subnet-0c5eec9d74d268575",
                "private_ip": "10.31.2.41",
                "public_ip": "51.24.91.143",
                "mac": "0a:53:a1:78:ee:f9",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0e8063eaa785c01eb"
                ]
              }
            ]
          },
          {
            "id": "i-00d0088a7295a4c83",
            "name": "hb-linux-amd64-ubuntu-2204-action-runner",
            "type": "c6id.4xlarge",
            "state": "running",
            "private_ip": "10.31.3.214",
            "public_ip": "13.40.174.203",
            "vpc_id": "vpc-003033d62c0c872bb",
            "subnet_id": "subnet-0b0c20825e67dab41",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-0b25404a1c0ba5e3d"
            ],
            "tags": {
              "aws:ec2launchtemplate:id": "lt-06fd889f7a76a0c19",
              "ghr:Application": "github-action-runner",
              "ghr:ssm_config_path": "/github-action-runners/hb/linux-amd64-ubuntu-2204/runners/config",
              "ghr:github_runner_id": "20970",
              "aws:ec2launchtemplate:version": "14",
              "aws:ec2:fleet-id": "fleet-c0bf5a06-3fa7-6e9e-0e18-0d0263eb8f37",
              "ghr:Owner": "HumanoidTeam/hmnd",
              "ghr:environment": "hb-linux-amd64-ubuntu-2204",
              "ghr:runner_name_prefix": "ubuntu-2204-amd64_",
              "Name": "hb-linux-amd64-ubuntu-2204-action-runner",
              "ghr:Type": "Repo",
              "ghr:created_by": "scale-up-lambda"
            },
            "network_interfaces": [
              {
                "id": "eni-0e21d35174e28b279",
                "subnet_id": "subnet-0b0c20825e67dab41",
                "private_ip": "10.31.3.214",
                "public_ip": "13.40.174.203",
                "mac": "02:ae:51:66:4e:99",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0b25404a1c0ba5e3d"
                ]
              }
            ]
          },
          {
            "id": "i-041c5f046dc02e819",
            "name": "hb-linux-amd64-ubuntu-2204-action-runner",
            "type": "c6id.4xlarge",
            "state": "running",
            "private_ip": "10.31.3.22",
            "public_ip": "16.61.14.236",
            "vpc_id": "vpc-003033d62c0c872bb",
            "subnet_id": "subnet-0b0c20825e67dab41",
            "az": "eu-west-2c",
            "security_groups": [
              "sg-0b25404a1c0ba5e3d"
            ],
            "tags": {
              "ghr:github_runner_id": "20972",
              "ghr:ssm_config_path": "/github-action-runners/hb/linux-amd64-ubuntu-2204/runners/config",
              "ghr:Type": "Repo",
              "ghr:created_by": "scale-up-lambda",
              "aws:ec2launchtemplate:version": "14",
              "ghr:Owner": "HumanoidTeam/hmnd",
              "Name": "hb-linux-amd64-ubuntu-2204-action-runner",
              "ghr:environment": "hb-linux-amd64-ubuntu-2204",
              "aws:ec2launchtemplate:id": "lt-06fd889f7a76a0c19",
              "ghr:runner_name_prefix": "ubuntu-2204-amd64_",
              "aws:ec2:fleet-id": "fleet-602c7ba4-6596-e1bc-06b0-aea2912e7128",
              "ghr:Application": "github-action-runner"
            },
            "network_interfaces": [
              {
                "id": "eni-0c0c235801764f02b",
                "subnet_id": "subnet-0b0c20825e67dab41",
                "private_ip": "10.31.3.22",
                "public_ip": "16.61.14.236",
                "mac": "02:c8:1e:85:5a:91",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0b25404a1c0ba5e3d"
                ]
              }
            ]
          }
        ],
        "tags": {
          "Name": "hmnd-runner"
        }
      },
      {
        "id": "vpc-07b89576ed160f978",
        "name": "foxglove-poc-vpc",
        "cidr": "10.0.0.0/16",
        "region": "eu-west-2",
        "instances": [
          {
            "id": "i-0b7f4acb77385b672",
            "name": "default-node-group",
            "type": "t3.small",
            "state": "running",
            "private_ip": "10.0.1.187",
            "public_ip": null,
            "vpc_id": "vpc-07b89576ed160f978",
            "subnet_id": "subnet-038e2908634b885f8",
            "az": "eu-west-2a",
            "security_groups": [
              "sg-0e2739bb6d066d3ef"
            ],
            "tags": {
              "eks:nodegroup-name": "default-node-group-20250403122809362400000009",
              "HM_COST_TAG_PROJECT": "foxglove",
              "k8s.io/cluster-autoscaler/foxglove-poc-cluster": "owned",
              "HM_COST_TAG_SERVICE": "foxglove-compute",
              "Name": "default-node-group",
              "aws:autoscaling:groupName": "eks-default-node-group-20250403122809362400000009-c6cafdcf-c11c-2d0a-f5d4-d63c534f398a",
              "aws:ec2launchtemplate:version": "1",
              "aws:ec2:fleet-id": "fleet-603dd2ac-3585-c61e-a438-270a930da29e",
              "kubernetes.io/cluster/foxglove-poc-cluster": "owned",
              "aws:eks:cluster-name": "foxglove-poc-cluster",
              "k8s.io/cluster-autoscaler/enabled": "true",
              "aws:ec2launchtemplate:id": "lt-0bf61d8a908d4bfd9",
              "eks:cluster-name": "foxglove-poc-cluster"
            },
            "network_interfaces": [
              {
                "id": "eni-08b9014c9c647de2c",
                "subnet_id": "subnet-038e2908634b885f8",
                "private_ip": "10.0.1.187",
                "public_ip": null,
                "mac": "06:dd:a6:5e:02:f3",
                "device_index": 0,
                "description": "",
                "security_groups": [
                  "sg-0e2739bb6d066d3ef"
                ]
              },
              {
                "id": "eni-02a1a5fa13fe471a5",
                "subnet_id": "subnet-038e2908634b885f8",
                "private_ip": "10.0.1.81",
                "public_ip": null,
                "mac": "06:72:39:ae:2d:7d",
                "device_index": 1,
                "description": "aws-K8S-i-0b7f4acb77385b672",
                "security_groups": [
                  "sg-0e2739bb6d066d3ef"
                ]
              },
              {
                "id": "eni-05ff5c629ea44cbc3",
                "subnet_id": "subnet-038e2908634b885f8",
                "private_ip": "10.0.1.144",
                "public_ip": null,
                "mac": "06:02:12:99:e4:b9",
                "device_index": 2,
                "description": "aws-K8S-i-0b7f4acb77385b672",
                "security_groups": [
                  "sg-0e2739bb6d066d3ef"
                ]
              }
            ]
          }
        ],
        "tags": {
          "Name": "foxglove-poc-vpc"
        }
      },
      {
        "id": "vpc-0c402fa39d35e019d",
        "name": "eks-vpc",
        "cidr": "10.253.0.0/16",
        "region": "eu-west-2",
        "instances": [],
        "tags": {
          "Name": "eks-vpc"
        }
      },
      {
        "id": "vpc-0c5ed9c2ba56a7808",
        "name": "pintel-vpc",
        "cidr": "10.5.0.0/16",
        "region": "eu-west-2",
        "instances": [],
        "tags": {
          "Name": "pintel-vpc",
          "HM_COST_TAG_PROJECT": "pintel-integration",
          "HM_COST_TAG_GROUP": "data",
          "Purpose": "external-access-for-pintel-cluster",
          "HM_COST_TAG_USER": "general",
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_SERVICE": "pintel-gateway"
        }
      },
      {
        "id": "vpc-0cc93b88905c8eb8d",
        "name": "humanoid-lab-uce-eu-west-2-SPOT_p5-48xlarge-vpc",
        "cidr": "10.131.0.0/16",
        "region": "eu-west-2",
        "instances": [],
        "tags": {
          "Name": "humanoid-lab-uce-eu-west-2-SPOT_p5-48xlarge-vpc",
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_ENV": "production"
        }
      },
      {
        "id": "vpc-08154cc6565a961cb",
        "name": "databricks-WorkerEnvId(workerenv-866715466211721-79b80e6e-62ab-4ef3-8fa6-13962fd76d5b)",
        "cidr": "10.37.0.0/16",
        "region": "eu-west-2",
        "instances": [],
        "tags": {
          "Name": "databricks-WorkerEnvId(workerenv-866715466211721-79b80e6e-62ab-4ef3-8fa6-13962fd76d5b)"
        }
      },
      {
        "id": "vpc-0b7bded913100cf03",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "eu-west-1",
        "instances": [],
        "tags": {},
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-0d005c46bbe380021",
        "name": "skypilot-vpc",
        "cidr": "10.11.0.0/16",
        "region": "eu-west-1",
        "instances": [],
        "tags": {
          "Name": "skypilot-vpc",
          "Environment": "multi-region",
          "Purpose": "ray-cluster-networking",
          "Project": "Skypilot",
          "Region": "eu-west-1"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-03dcd3fb8526165a5",
        "name": "skypilot-vpc",
        "cidr": "10.11.0.0/16",
        "region": "eu-west-1",
        "instances": [],
        "tags": {
          "Environment": "multi-region",
          "Project": "Skypilot",
          "Region": "eu-west-1",
          "Name": "skypilot-vpc",
          "Purpose": "ray-cluster-networking"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-0b3878a56288b18f6",
        "name": "skypilot-vpc",
        "cidr": "10.10.0.0/16",
        "region": "eu-south-2",
        "instances": [],
        "tags": {
          "Name": "skypilot-vpc",
          "Environment": "multi-region",
          "Purpose": "ray-cluster-networking",
          "Region": "eu-south-2",
          "Project": "Skypilot"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-05ae02ab2a2c8450a",
        "name": "skypilot-vpc",
        "cidr": "10.10.0.0/16",
        "region": "eu-south-2",
        "instances": [],
        "tags": {
          "Environment": "multi-region",
          "Name": "skypilot-vpc",
          "Purpose": "ray-cluster-networking",
          "Region": "eu-south-2",
          "Project": "Skypilot"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-0903f04b6dada541f",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "eu-west-3",
        "instances": [],
        "tags": {},
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-04ae6d45027fe22cc",
        "name": "skypilot-vpc",
        "cidr": "10.13.0.0/16",
        "region": "eu-west-3",
        "instances": [],
        "tags": {
          "Environment": "multi-region",
          "Purpose": "ray-cluster-networking",
          "Name": "skypilot-vpc",
          "Project": "Skypilot",
          "Region": "eu-west-3"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-0443d0eea5d42666e",
        "name": "skypilot-vpc",
        "cidr": "10.13.0.0/16",
        "region": "eu-west-3",
        "instances": [],
        "tags": {
          "Name": "skypilot-vpc",
          "Purpose": "ray-cluster-networking",
          "Region": "eu-west-3",
          "Project": "Skypilot",
          "Environment": "multi-region"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-04dcd4e77c1a77ca9",
        "name": "skypilot-vpc",
        "cidr": "10.5.0.0/16",
        "region": "ap-southeast-1",
        "instances": [],
        "tags": {
          "Environment": "multi-region",
          "Purpose": "ray-cluster-networking",
          "Name": "skypilot-vpc",
          "Project": "Skypilot",
          "Region": "ap-southeast-1"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-0c63d1f0439752d4b",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "ap-southeast-1",
        "instances": [],
        "tags": {},
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-029ed14b395eec37d",
        "name": "skypilot-vpc",
        "cidr": "10.5.0.0/16",
        "region": "ap-southeast-1",
        "instances": [],
        "tags": {
          "Name": "skypilot-vpc",
          "Region": "ap-southeast-1",
          "Project": "Skypilot",
          "Environment": "multi-region",
          "Purpose": "ray-cluster-networking"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-01d98f2a15be6ad25",
        "name": "skypilot-vpc",
        "cidr": "10.3.0.0/16",
        "region": "ap-northeast-3",
        "instances": [],
        "tags": {
          "Region": "ap-northeast-3",
          "Name": "skypilot-vpc",
          "Purpose": "ray-cluster-networking",
          "Environment": "multi-region",
          "Project": "Skypilot"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-07f5b5d1455660294",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "ap-northeast-3",
        "instances": [],
        "tags": {},
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-00dc6b8d84c2286c4",
        "name": "skypilot-vpc",
        "cidr": "10.3.0.0/16",
        "region": "ap-northeast-3",
        "instances": [],
        "tags": {
          "Region": "ap-northeast-3",
          "Name": "skypilot-vpc",
          "Purpose": "ray-cluster-networking",
          "Environment": "multi-region",
          "Project": "Skypilot"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-08d13455835728cd0",
        "name": "skypilot-vpc",
        "cidr": "10.2.0.0/16",
        "region": "ap-northeast-2",
        "instances": [],
        "tags": {
          "Project": "Skypilot",
          "Environment": "multi-region",
          "Name": "skypilot-vpc",
          "Purpose": "ray-cluster-networking",
          "Region": "ap-northeast-2"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-05524f5b0a77763f1",
        "name": "skypilot-vpc",
        "cidr": "10.2.0.0/16",
        "region": "ap-northeast-2",
        "instances": [],
        "tags": {
          "Environment": "multi-region",
          "Purpose": "ray-cluster-networking",
          "Region": "ap-northeast-2",
          "Name": "skypilot-vpc",
          "Project": "Skypilot"
        },
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      },
      {
        "id": "vpc-0d339569d8545169f",
        "name": "",
        "cidr": "172.31.0.0/16",
        "region": "ap-northeast-2",
        "instances": [],
        "tags": {},
        "stale": true,
        "stale_since": "2026-07-25T07:21:51.633117+00:00"
      }
    ],
    "route53_zones": [
      {
        "id": "Z0180778XBY51KG341AF",
        "name": "lab.hmnd.ai",
        "private": false,
        "record_count": 14,
        "records": [
          {
            "name": "lab.hmnd.ai",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-357.awsdns-44.com.",
              "ns-600.awsdns-11.net.",
              "ns-1354.awsdns-41.org.",
              "ns-1756.awsdns-27.co.uk."
            ]
          },
          {
            "name": "lab.hmnd.ai",
            "type": "SOA",
            "ttl": 900,
            "values": [
              "ns-357.awsdns-44.com. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "\\052.eks-ext.lab.hmnd.ai",
            "type": "CNAME",
            "ttl": 300,
            "values": [
              "k8s-kubesyst-ingressn-1c5f68f136-5f2d6788a0a7f69f.elb.eu-west-2.amazonaws.com"
            ]
          },
          {
            "name": "\\052.eks.lab.hmnd.ai",
            "type": "CNAME",
            "ttl": 300,
            "values": [
              "k8s-kubesyst-ingressn-4ac888c826-cb58cf16b744ff57.elb.eu-west-2.amazonaws.com"
            ]
          },
          {
            "name": "\\052.fleet.lab.hmnd.ai",
            "type": "A",
            "ttl": 300,
            "values": [
              "35.177.129.5"
            ]
          },
          {
            "name": "kamino-dev.lab.hmnd.ai",
            "type": "A",
            "alias": "hmnd-ml-kamino-dev-eu-west-2-523453658.eu-west-2.elb.amazonaws.com"
          },
          {
            "name": "_8b5eecfc951152115cb4da88e0cd5d4b.kamino-dev.lab.hmnd.ai",
            "type": "CNAME",
            "ttl": 60,
            "values": [
              "_8e3313c07d0589aaad8798c2aa06268b.jkddzztszm.acm-validations.aws."
            ]
          },
          {
            "name": "kamino.lab.hmnd.ai",
            "type": "A",
            "alias": "hmnd-ml-kamino-dev-eu-west-2-523453658.eu-west-2.elb.amazonaws.com"
          },
          {
            "name": "_e458d265ec6efa79aef0b916c8526486.kamino.lab.hmnd.ai",
            "type": "CNAME",
            "ttl": 60,
            "values": [
              "_ee53ba2525e8411ca6fd7b6a0e643385.jkddzztszm.acm-validations.aws."
            ]
          },
          {
            "name": "\\052.pintel.lab.hmnd.ai",
            "type": "A",
            "ttl": 300,
            "values": [
              "176.56.202.1",
              "176.56.202.2",
              "176.56.202.3"
            ]
          },
          {
            "name": "robots.lab.hmnd.ai",
            "type": "A",
            "alias": "dtjrqq5wkl0uu.cloudfront.net"
          },
          {
            "name": "_52d9056ed97f5dd957d05f1a1e176dd4.robots.lab.hmnd.ai",
            "type": "CNAME",
            "ttl": 60,
            "values": [
              "_05280d0eadf4a9b98dacb202130c0895.jkddzztszm.acm-validations.aws."
            ]
          },
          {
            "name": "streams.robots.lab.hmnd.ai",
            "type": "A",
            "alias": "infra-dashboard-streams-354431436.eu-west-2.elb.amazonaws.com"
          },
          {
            "name": "_23e3a506a04a48d2242bbe1fc37ac437.streams.robots.lab.hmnd.ai",
            "type": "CNAME",
            "ttl": 60,
            "values": [
              "_608677ec5873d91096af331c60072060.jkddzztszm.acm-validations.aws."
            ]
          }
        ]
      },
      {
        "id": "Z09479371TAU0BC18MX6L",
        "name": "ext.hmnd.ai",
        "private": false,
        "record_count": 7,
        "records": [
          {
            "name": "ext.hmnd.ai",
            "type": "A",
            "alias": "d9b9oidbv76cg.cloudfront.net"
          },
          {
            "name": "ext.hmnd.ai",
            "type": "AAAA",
            "alias": "d9b9oidbv76cg.cloudfront.net"
          },
          {
            "name": "ext.hmnd.ai",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-1525.awsdns-62.org.",
              "ns-830.awsdns-39.net.",
              "ns-110.awsdns-13.com.",
              "ns-1912.awsdns-47.co.uk."
            ]
          },
          {
            "name": "ext.hmnd.ai",
            "type": "SOA",
            "ttl": 900,
            "values": [
              "ns-1525.awsdns-62.org. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "_26ff76b09a4273220275d71922be350a.ext.hmnd.ai",
            "type": "CNAME",
            "ttl": 60,
            "values": [
              "_da40a0da145fdef95e881885fabe0609.jkddzztszm.acm-validations.aws."
            ]
          },
          {
            "name": "hq.ext.hmnd.ai",
            "type": "A",
            "alias": "d9b9oidbv76cg.cloudfront.net"
          },
          {
            "name": "hq.ext.hmnd.ai",
            "type": "AAAA",
            "alias": "d9b9oidbv76cg.cloudfront.net"
          }
        ]
      },
      {
        "id": "Z06621483LCLI8CN4T25",
        "name": "foxglove.thehumanoid.ai",
        "private": false,
        "record_count": 3,
        "records": [
          {
            "name": "foxglove.thehumanoid.ai",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-1502.awsdns-59.org.",
              "ns-1946.awsdns-51.co.uk.",
              "ns-366.awsdns-45.com.",
              "ns-631.awsdns-14.net."
            ]
          },
          {
            "name": "foxglove.thehumanoid.ai",
            "type": "SOA",
            "ttl": 900,
            "values": [
              "ns-1502.awsdns-59.org. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "_c8f3a683c268d56e3982bdde3e2f064d.foxglove.thehumanoid.ai",
            "type": "CNAME",
            "ttl": 300,
            "values": [
              "_acb821db62e1a04a3872cc4508853371.xlfgrmvvlj.acm-validations.aws."
            ]
          }
        ]
      },
      {
        "id": "Z0965155S5I1OGX9L1YW",
        "name": "internal.hmnd.ai",
        "private": false,
        "record_count": 5,
        "records": [
          {
            "name": "internal.hmnd.ai",
            "type": "A",
            "alias": "d369bwj5g5xrp2.cloudfront.net"
          },
          {
            "name": "internal.hmnd.ai",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-521.awsdns-01.net.",
              "ns-1394.awsdns-46.org.",
              "ns-439.awsdns-54.com.",
              "ns-1801.awsdns-33.co.uk."
            ]
          },
          {
            "name": "internal.hmnd.ai",
            "type": "SOA",
            "ttl": 900,
            "values": [
              "ns-521.awsdns-01.net. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "\\052.internal.hmnd.ai",
            "type": "A",
            "alias": "hmnd-internal-svc-90256221.eu-west-2.elb.amazonaws.com"
          },
          {
            "name": "_6ba681f988d3f13785bc2a2d4cbb4f49.internal.hmnd.ai",
            "type": "CNAME",
            "ttl": 60,
            "values": [
              "_be064a42f96adb89a6fedbb9d21f0b8d.jkddzztszm.acm-validations.aws."
            ]
          }
        ]
      },
      {
        "id": "Z0749558298B75NDZRVCV",
        "name": "ic.hmnd.ai",
        "private": false,
        "record_count": 47,
        "records": [
          {
            "name": "ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "ic.hmnd.ai",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-1466.awsdns-55.org.",
              "ns-160.awsdns-20.com.",
              "ns-701.awsdns-23.net.",
              "ns-1772.awsdns-29.co.uk."
            ]
          },
          {
            "name": "ic.hmnd.ai",
            "type": "SOA",
            "ttl": 900,
            "values": [
              "ns-1466.awsdns-55.org. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "100.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "100.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "_345a10ac1f69cb008398b806a8595058.ic.hmnd.ai",
            "type": "CNAME",
            "ttl": 60,
            "values": [
              "_1c1816ec2f1f7b4ed2e51823326f631e.jkddzztszm.acm-validations.aws."
            ]
          },
          {
            "name": "apps.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "apps.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "auth-docs.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "auth-docs.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "backbone.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "backbone.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "bion.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "bion.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "console.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "console.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "ctrl3.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "ctrl3.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "design.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "design.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "dimsim.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "dimsim.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "dnsdocs.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "dnsdocs.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "findmy.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "findmy.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "fleetmgmt.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "fleetmgmt.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "hq.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "hq.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "melts-docs.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "melts-docs.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "melts.ic.hmnd.ai",
            "type": "A",
            "alias": "melts-grafana-1590403369.eu-west-2.elb.amazonaws.com"
          },
          {
            "name": "_b7ab4eab381fc280a7272521b85737ba.melts.ic.hmnd.ai",
            "type": "CNAME",
            "ttl": 60,
            "values": [
              "_5045aa5769e4c6224f9cbae24c98a6ef.jkddzztszm.acm-validations.aws."
            ]
          },
          {
            "name": "qwen-robotsuite.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "qwen-robotsuite.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "sockpuppet.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "sockpuppet.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "teleop-study.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "teleop-study.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "thorious.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "thorious.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "tldr.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "tldr.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "tobias.ic.hmnd.ai",
            "type": "A",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          },
          {
            "name": "tobias.ic.hmnd.ai",
            "type": "AAAA",
            "alias": "d2h1g2rnazmjra.cloudfront.net"
          }
        ]
      },
      {
        "id": "Z0843494QQHALA69EIET",
        "name": "robots.hmnd.ai",
        "private": true,
        "record_count": 19,
        "records": [
          {
            "name": "robots.hmnd.ai",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-1536.awsdns-00.co.uk.",
              "ns-0.awsdns-00.com.",
              "ns-1024.awsdns-00.org.",
              "ns-512.awsdns-00.net."
            ]
          },
          {
            "name": "robots.hmnd.ai",
            "type": "SOA",
            "ttl": 900,
            "values": [
              "ns-1536.awsdns-00.co.uk. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "ab1.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.44.10.99"
            ]
          },
          {
            "name": "ab2.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.51.102"
            ]
          },
          {
            "name": "ab3.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.51.103"
            ]
          },
          {
            "name": "ab4.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.44.10.114"
            ]
          },
          {
            "name": "aw1.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.101"
            ]
          },
          {
            "name": "aw10.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.110"
            ]
          },
          {
            "name": "aw11.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.111"
            ]
          },
          {
            "name": "aw12.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.112"
            ]
          },
          {
            "name": "aw2.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.102"
            ]
          },
          {
            "name": "aw3.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.103"
            ]
          },
          {
            "name": "aw4.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.104"
            ]
          },
          {
            "name": "aw5.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.105"
            ]
          },
          {
            "name": "aw6.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.106"
            ]
          },
          {
            "name": "aw7.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.107"
            ]
          },
          {
            "name": "aw8.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.108"
            ]
          },
          {
            "name": "aw9.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.109"
            ]
          },
          {
            "name": "orin1.robots.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.50.150"
            ]
          }
        ]
      },
      {
        "id": "Z04513903BG86UCJIWATX",
        "name": "lan.thehumanoid.cloud",
        "private": true,
        "record_count": 3,
        "records": [
          {
            "name": "lan.thehumanoid.cloud",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-1536.awsdns-00.co.uk.",
              "ns-0.awsdns-00.com.",
              "ns-1024.awsdns-00.org.",
              "ns-512.awsdns-00.net."
            ]
          },
          {
            "name": "lan.thehumanoid.cloud",
            "type": "SOA",
            "ttl": 900,
            "values": [
              "ns-1536.awsdns-00.co.uk. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "\\052.lan.thehumanoid.cloud",
            "type": "A",
            "alias": "dualstack.internal-humanoid-ops-alb-302952472.eu-west-2.elb.amazonaws.com"
          }
        ]
      },
      {
        "id": "Z02459692CFTYCU9HWO74",
        "name": "thehumanoid.cloud",
        "private": true,
        "record_count": 4,
        "records": [
          {
            "name": "thehumanoid.cloud",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-1536.awsdns-00.co.uk.",
              "ns-0.awsdns-00.com.",
              "ns-1024.awsdns-00.org.",
              "ns-512.awsdns-00.net."
            ]
          },
          {
            "name": "thehumanoid.cloud",
            "type": "SOA",
            "ttl": 900,
            "values": [
              "ns-1536.awsdns-00.co.uk. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "\\052.thehumanoid.cloud",
            "type": "A",
            "alias": "internal-k8s-hmndsharedalb-64839e4820-1256242229.eu-west-2.elb.amazonaws.com"
          },
          {
            "name": "enroll.thehumanoid.cloud",
            "type": "A",
            "alias": "dualstack.vpn-alb-707004360.eu-west-2.elb.amazonaws.com"
          }
        ]
      },
      {
        "id": "Z01993492J28XY1UA4E5Y",
        "name": "hmnd-console.local",
        "private": true,
        "record_count": 8,
        "records": [
          {
            "name": "hmnd-console.local",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-1536.awsdns-00.co.uk.",
              "ns-0.awsdns-00.com.",
              "ns-1024.awsdns-00.org.",
              "ns-512.awsdns-00.net."
            ]
          },
          {
            "name": "hmnd-console.local",
            "type": "SOA",
            "ttl": 15,
            "values": [
              "ns-1536.awsdns-00.co.uk. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "backend.hmnd-console.local",
            "type": "A",
            "ttl": 10,
            "values": [
              "172.31.17.96"
            ]
          },
          {
            "name": "backend.hmnd-console.local",
            "type": "A",
            "ttl": 10,
            "values": [
              "172.31.26.140"
            ]
          },
          {
            "name": "backend.hmnd-console.local",
            "type": "A",
            "ttl": 10,
            "values": [
              "172.31.23.165"
            ]
          },
          {
            "name": "frontend.hmnd-console.local",
            "type": "A",
            "ttl": 10,
            "values": [
              "172.31.23.168"
            ]
          },
          {
            "name": "frontend.hmnd-console.local",
            "type": "A",
            "ttl": 10,
            "values": [
              "172.31.17.123"
            ]
          },
          {
            "name": "frontend.hmnd-console.local",
            "type": "A",
            "ttl": 10,
            "values": [
              "172.31.18.195"
            ]
          }
        ]
      },
      {
        "id": "Z0668989PLCE4UMYF4U3",
        "name": "lan.thehumanoid.ai",
        "private": true,
        "record_count": 20,
        "records": [
          {
            "name": "lan.thehumanoid.ai",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-1536.awsdns-00.co.uk.",
              "ns-0.awsdns-00.com.",
              "ns-1024.awsdns-00.org.",
              "ns-512.awsdns-00.net."
            ]
          },
          {
            "name": "lan.thehumanoid.ai",
            "type": "SOA",
            "ttl": 900,
            "values": [
              "ns-1536.awsdns-00.co.uk. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "\\052.lan.thehumanoid.ai",
            "type": "A",
            "alias": "dualstack.internal-humanoid-ops-alb-302952472.eu-west-2.elb.amazonaws.com"
          },
          {
            "name": "\\052.alphaclaw.lan.thehumanoid.ai",
            "type": "CNAME",
            "ttl": 300,
            "values": [
              "k8s-kubesyst-ingressn-4ac888c826-cb58cf16b744ff57.elb.eu-west-2.amazonaws.com"
            ]
          },
          {
            "name": "\\052.eks-euw2.lan.thehumanoid.ai",
            "type": "CNAME",
            "ttl": 300,
            "values": [
              "k8s-kubesyst-ingressn-4ac888c826-cb58cf16b744ff57.elb.eu-west-2.amazonaws.com"
            ]
          },
          {
            "name": "fg.lan.thehumanoid.ai",
            "type": "A",
            "alias": "k8s-foxglove-site-7e93365eda-1891462357.eu-west-2.elb.amazonaws.com"
          },
          {
            "name": "grafana-eks.lan.thehumanoid.ai",
            "type": "A",
            "alias": "k8s-monitori-kubeprom-52019cd956-59d2382548806f32.elb.eu-west-2.amazonaws.com"
          },
          {
            "name": "h100-01.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.101"
            ]
          },
          {
            "name": "\\052.h100-01.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.101"
            ]
          },
          {
            "name": "h100-02.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.102"
            ]
          },
          {
            "name": "\\052.h100-02.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.102"
            ]
          },
          {
            "name": "hmnd-console.lan.thehumanoid.ai",
            "type": "A",
            "alias": "internal-humanoid-ops-alb-302952472.eu-west-2.elb.amazonaws.com"
          },
          {
            "name": "mumbai-01.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 300,
            "values": [
              "3.110.31.221"
            ]
          },
          {
            "name": "\\052.mumbai-01.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 300,
            "values": [
              "3.110.31.221"
            ]
          },
          {
            "name": "\\052.pintel.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 300,
            "values": [
              "176.56.202.1",
              "176.56.202.2",
              "176.56.202.3"
            ]
          },
          {
            "name": "ray-gpu.lan.thehumanoid.ai",
            "type": "A",
            "alias": "dualstack.internal-hmndsharedml-2052276583.eu-west-2.elb.amazonaws.com"
          },
          {
            "name": "saudi-01.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 300,
            "values": [
              "158.252.119.42"
            ]
          },
          {
            "name": "\\052.saudi-01.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 300,
            "values": [
              "158.252.119.42"
            ]
          },
          {
            "name": "spark-01.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 300,
            "values": [
              "10.44.11.12"
            ]
          },
          {
            "name": "\\052.spark-01.lan.thehumanoid.ai",
            "type": "A",
            "ttl": 300,
            "values": [
              "10.44.11.12"
            ]
          }
        ]
      },
      {
        "id": "Z027018432N049F3MK321",
        "name": "infra.hmnd.ai",
        "private": true,
        "record_count": 25,
        "records": [
          {
            "name": "infra.hmnd.ai",
            "type": "NS",
            "ttl": 172800,
            "values": [
              "ns-1536.awsdns-00.co.uk.",
              "ns-0.awsdns-00.com.",
              "ns-1024.awsdns-00.org.",
              "ns-512.awsdns-00.net."
            ]
          },
          {
            "name": "infra.hmnd.ai",
            "type": "SOA",
            "ttl": 900,
            "values": [
              "ns-1536.awsdns-00.co.uk. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"
            ]
          },
          {
            "name": "4090.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.103"
            ]
          },
          {
            "name": "ctrl1.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.44.11.160"
            ]
          },
          {
            "name": "ctrl2.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.163"
            ]
          },
          {
            "name": "ctrl3.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.165"
            ]
          },
          {
            "name": "h1001.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.101"
            ]
          },
          {
            "name": "h1002.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.102"
            ]
          },
          {
            "name": "pi5-deploy-02-1.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.44.11.81"
            ]
          },
          {
            "name": "spark1.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.135"
            ]
          },
          {
            "name": "spark2.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.136"
            ]
          },
          {
            "name": "spark3.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.137"
            ]
          },
          {
            "name": "spark4.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.138"
            ]
          },
          {
            "name": "thor1.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.44.11.209"
            ]
          },
          {
            "name": "thor10.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.118"
            ]
          },
          {
            "name": "thor11.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.219"
            ]
          },
          {
            "name": "thor2.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.40.148"
            ]
          },
          {
            "name": "thor3.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.111"
            ]
          },
          {
            "name": "thor4.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.44.11.222"
            ]
          },
          {
            "name": "thor5.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.113"
            ]
          },
          {
            "name": "thor6.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.114"
            ]
          },
          {
            "name": "thor7.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.115"
            ]
          },
          {
            "name": "thor8.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.216"
            ]
          },
          {
            "name": "thor9.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.10.60.117"
            ]
          },
          {
            "name": "umi1.infra.hmnd.ai",
            "type": "A",
            "ttl": 60,
            "values": [
              "10.44.10.86"
            ]
          }
        ]
      }
    ],
    "route_tables": [
      {
        "id": "rtb-0c94e14442916f56f",
        "vpc_id": "vpc-03c6dac4b77bd22a5",
        "name": "",
        "routes": [
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-0592b230114c52d7e",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-043e43d4d2ab463fe",
        "vpc_id": "vpc-00e7b72129f9e7a2c",
        "name": "",
        "routes": [
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-0c80e994737985baf",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0e6747672d6bb3d11",
        "vpc_id": "vpc-00613666bbf826344",
        "name": "",
        "routes": [
          {
            "destination": "10.96.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0ca7dda349ee1e45d",
        "vpc_id": "vpc-05b5920e463e9a82b",
        "name": "",
        "routes": [
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-01f06de554db92d13",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-018e5a6cb213989fa",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "name": "lab-eu-north-1-private-rt-3",
        "routes": [
          {
            "destination": "10.4.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-014774cfd9d93d97e",
            "state": "active"
          },
          {
            "destination": "pl-c3aa4faa",
            "target": "vpce-04828a36f70ab9764",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-02f92d8130ec497c1",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-026e65820752048f8",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "name": "lab-eu-north-1-private-rt-2",
        "routes": [
          {
            "destination": "192.168.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.4.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-0acaaa1e843411c74",
            "state": "active"
          },
          {
            "destination": "pl-c3aa4faa",
            "target": "vpce-04828a36f70ab9764",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0bb3305ae8a590421",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-030edbdf753c2ade4",
        "vpc_id": "vpc-00613666bbf826344",
        "name": "",
        "routes": [
          {
            "destination": "10.96.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-01909f255712f7b6c",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0d086f1229b152a53",
            "main": false
          },
          {
            "subnet_id": "subnet-04b7b1e8d0badf966",
            "main": false
          },
          {
            "subnet_id": "subnet-0e2a7585d17835b7f",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0dbc9c1fb7ddaeae7",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "name": "",
        "routes": [
          {
            "destination": "10.4.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-02f5627da482a6386",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "name": "lab-eu-north-1-public-rt",
        "routes": [
          {
            "destination": "10.4.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-04160209574e51fad",
            "state": "active"
          },
          {
            "destination": "pl-c3aa4faa",
            "target": "vpce-04828a36f70ab9764",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-09344ae80abe2f7f8",
            "main": false
          },
          {
            "subnet_id": "subnet-07f4b58d1fce3588e",
            "main": false
          },
          {
            "subnet_id": "subnet-0c66af127a310a161",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-02a2e41701ed2ea92",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "name": "lab-eu-north-1-private-rt-1",
        "routes": [
          {
            "destination": "10.4.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-0eae4f52f7abdd9fb",
            "state": "active"
          },
          {
            "destination": "pl-c3aa4faa",
            "target": "vpce-04828a36f70ab9764",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-06789308551e0a4b0",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0dfd84ae2b25a6499",
        "vpc_id": "vpc-0da7cd54df9b385e4",
        "name": "packer-vpc-public-rt",
        "routes": [
          {
            "destination": "10.1.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-0411f11168fe86d3e",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0ae1e532b48195510",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-043be5cf680416757",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "name": "lab-us-west-2-rtb-private1-us-west-2a",
        "routes": [
          {
            "destination": "10.0.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.1.0.0/16",
            "target": "pcx-087e9d12089f65bf8",
            "state": "blackhole"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-0c6485ae67556a875",
            "state": "active"
          },
          {
            "destination": "pl-0fe0cdcf59bd5725a",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "pl-68a54001",
            "target": "vpce-00fc8d7ab0990caf0",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0af74d62382d09be1",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-051249053b54f0c2a",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "name": "",
        "routes": [
          {
            "destination": "10.0.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "pl-0fe0cdcf59bd5725a",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0b1b77ac110abaff0",
        "vpc_id": "vpc-028c5f171f9b93e38",
        "name": "",
        "routes": [
          {
            "destination": "10.246.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-0a0343ae1ab902a57",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-05e877abd62404693",
            "main": false
          },
          {
            "subnet_id": "subnet-0545a53e2c31f119f",
            "main": false
          },
          {
            "subnet_id": "subnet-0c89282c76c64465c",
            "main": false
          },
          {
            "subnet_id": "subnet-05c1536cc696af6ea",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-058bf45429da5a085",
        "vpc_id": "vpc-028c5f171f9b93e38",
        "name": "",
        "routes": [
          {
            "destination": "10.246.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0897e223744959875",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "name": "lab-us-west-2-rtb-public",
        "routes": [
          {
            "destination": "10.0.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.1.0.0/16",
            "target": "pcx-087e9d12089f65bf8",
            "state": "blackhole"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-0b97b50fde53a2996",
            "state": "active"
          },
          {
            "destination": "pl-0fe0cdcf59bd5725a",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0317c297ae1bea2a3",
            "main": false
          },
          {
            "subnet_id": "subnet-0e13946587ef076ae",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-09db0df7dc5a372bc",
        "vpc_id": "vpc-0da7cd54df9b385e4",
        "name": "",
        "routes": [
          {
            "destination": "10.1.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-02fd1f49320fe2746",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "name": "lab-us-west-2-rtb-private2-us-west-2b",
        "routes": [
          {
            "destination": "10.0.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.1.0.0/16",
            "target": "pcx-087e9d12089f65bf8",
            "state": "blackhole"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-0c6485ae67556a875",
            "state": "active"
          },
          {
            "destination": "pl-0fe0cdcf59bd5725a",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "pl-68a54001",
            "target": "vpce-00fc8d7ab0990caf0",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-059ac2925c9259837",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0a19ce2e72620ee0a",
        "vpc_id": "vpc-006b54fa0165dba13",
        "name": "",
        "routes": [
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-05a9e6cda6f7e0ba3",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0b0cc4b55ea2baa4b",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "name": "hmnd-ml-rt-private-dev-us-west-1-2",
        "routes": [
          {
            "destination": "192.168.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.1.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-0b89584b1ead7e6dd",
            "state": "active"
          },
          {
            "destination": "pl-6ba54002",
            "target": "vpce-0ad67f9d7889db950",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-06162af46f40935b2",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0d8653ddfd3cac6d0",
        "vpc_id": "vpc-0843dca91e5e4b27e",
        "name": "",
        "routes": [
          {
            "destination": "10.134.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0e0d0553bce025aea",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "name": "hmnd-ml-rt-private-dev-us-west-1-1",
        "routes": [
          {
            "destination": "192.168.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.1.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-096cb21ff631a477c",
            "state": "active"
          },
          {
            "destination": "pl-6ba54002",
            "target": "vpce-0ad67f9d7889db950",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-06f02c2f719778af6",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-04b8ed1552ae5c5e6",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "name": "",
        "routes": [
          {
            "destination": "192.168.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.1.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0bf93ea647680c123",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "name": "hmnd-ml-rt-public-dev-us-west-1",
        "routes": [
          {
            "destination": "192.168.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.1.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-079f945c93c6b83a2",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0d511fb1c52512d00",
            "main": false
          },
          {
            "subnet_id": "subnet-028efb33ad3d62f9b",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-01a831ecb02b0c559",
        "vpc_id": "vpc-0843dca91e5e4b27e",
        "name": "",
        "routes": [
          {
            "destination": "10.134.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-09b0fd4b02c815590",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0990b6b00d4d8de4c",
            "main": false
          },
          {
            "subnet_id": "subnet-0275d0dd04474da3b",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-09283274a7782f8e1",
        "vpc_id": "vpc-08154cc6565a961cb",
        "name": "",
        "routes": [
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.37.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-07a6d7b9e8c6cf8a5",
            "state": "active"
          },
          {
            "destination": "pl-7ca54015",
            "target": "vpce-09ddec37b1778f251",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-06bb7669a689e27ad",
        "vpc_id": "vpc-094933326926cea6e",
        "name": "",
        "routes": [
          {
            "destination": "10.53.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0728bdc59fc744da1",
        "vpc_id": "vpc-033eb69021e3deafb",
        "name": "hmnd-ml-rt-private-dev-eu-west-2-3",
        "routes": [
          {
            "destination": "192.168.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.3.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-0c90fb0ff14d9321f",
            "state": "active"
          },
          {
            "destination": "pl-7ca54015",
            "target": "vpce-0df49730ca97cbb6e",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0b8b4508a7a5e8d1b",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0a683cd122b3275e2",
        "vpc_id": "vpc-07b89576ed160f978",
        "name": "foxglove-poc-vpc-private",
        "routes": [
          {
            "destination": "10.0.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-0653a7dd4b57f9800",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-038e2908634b885f8",
            "main": false
          },
          {
            "subnet_id": "subnet-0b73bba9dd22c666a",
            "main": false
          },
          {
            "subnet_id": "subnet-04ac92ef08cc1abee",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-08dfdbfbe3fc8b987",
        "vpc_id": "vpc-033eb69021e3deafb",
        "name": "hmnd-ml-rt-private-dev-eu-west-2-1",
        "routes": [
          {
            "destination": "192.168.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.3.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-09421b06835e1e09b",
            "state": "active"
          },
          {
            "destination": "pl-7ca54015",
            "target": "vpce-0df49730ca97cbb6e",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0379e30a82da9d80f",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0ba45fb199d067075",
        "vpc_id": "vpc-033eb69021e3deafb",
        "name": "hmnd-ml-rt-public-dev-eu-west-2",
        "routes": [
          {
            "destination": "192.168.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.3.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-09cc3aa133a400be3",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0d1bad752714c7c53",
            "main": false
          },
          {
            "subnet_id": "subnet-03ad7c51850183978",
            "main": false
          },
          {
            "subnet_id": "subnet-05e3b850ac2203676",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-03d86d278d95103b6",
        "vpc_id": "vpc-0c5ed9c2ba56a7808",
        "name": "",
        "routes": [
          {
            "destination": "10.5.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0513217d4fc262bc3",
        "vpc_id": "vpc-0cc93b88905c8eb8d",
        "name": "",
        "routes": [
          {
            "destination": "10.131.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-03c78fe862e42f695",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-017574f1c6d199320",
            "main": false
          },
          {
            "subnet_id": "subnet-0f73acfdaf352a436",
            "main": false
          },
          {
            "subnet_id": "subnet-04d153ded5e820579",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-09f0c5df94f066c8b",
        "vpc_id": "vpc-003033d62c0c872bb",
        "name": "hmnd-runner-public",
        "routes": [
          {
            "destination": "10.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-01327e8ae524448af",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0eaa697fcd89b5e1e",
            "main": false
          },
          {
            "subnet_id": "subnet-0c5eec9d74d268575",
            "main": false
          },
          {
            "subnet_id": "subnet-0b0c20825e67dab41",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-046a7ea3939c7c4e6",
        "vpc_id": "vpc-08154cc6565a961cb",
        "name": "nat-gateway-route-table",
        "routes": [
          {
            "destination": "172.31.0.0/16",
            "target": "pcx-0486458dc0fb0467e",
            "state": "active"
          },
          {
            "destination": "10.37.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-0f2b8ab931e2dca3f",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0cb8e82f47c42ccbb",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-08151567bde75d235",
        "vpc_id": "vpc-033eb69021e3deafb",
        "name": "",
        "routes": [
          {
            "destination": "10.3.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-007de7a46ca14f210",
        "vpc_id": "vpc-094933326926cea6e",
        "name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksNatRouteTable",
        "routes": [
          {
            "destination": "10.53.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-003c226316c93df3e",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-05dd478c41aa47262",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0ee8eec210545ec83",
        "vpc_id": "vpc-07b89576ed160f978",
        "name": "foxglove-poc-vpc-public",
        "routes": [
          {
            "destination": "10.0.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-0a0dba5d36e8da4fd",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0c4332b64cda245cf",
            "main": false
          },
          {
            "subnet_id": "subnet-0bfd43f20795ec311",
            "main": false
          },
          {
            "subnet_id": "subnet-0751e069031e96b7c",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0450e352bee32e61b",
        "vpc_id": "vpc-003033d62c0c872bb",
        "name": "hmnd-runner-default",
        "routes": [
          {
            "destination": "10.31.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-08335c265c1f16e04",
        "vpc_id": "vpc-064b86b11d9115a70",
        "name": "external-rt",
        "routes": [
          {
            "destination": "192.168.123.0/24",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "224.0.0.0/24",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "10.255.255.0/24",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "10.254.0.0/23",
            "target": "i-068dcf84dc6ee7a7d",
            "state": "active"
          },
          {
            "destination": "10.128.0.0/22",
            "target": "pcx-0f27a140a0105c914",
            "state": "active"
          },
          {
            "destination": "192.168.80.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.0.0/20",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "10.44.48.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.64.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.80.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.112.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.128.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.144.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.160.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "192.168.0.0/16",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "10.3.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.4.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.5.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/11",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-008ffec316eede56d",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-004aaae93f1c2bf12",
            "main": false
          },
          {
            "subnet_id": "subnet-0d4bc346d7c22cff6",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-04ea1b76429a56d00",
        "vpc_id": "vpc-033eb69021e3deafb",
        "name": "hmnd-ml-rt-private-dev-eu-west-2-2",
        "routes": [
          {
            "destination": "192.168.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.3.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-06d3faaa4f8184e87",
            "state": "active"
          },
          {
            "destination": "pl-7ca54015",
            "target": "vpce-0df49730ca97cbb6e",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-00e754e8d43a7de43",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0ea0ef865291c921b",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "name": "",
        "routes": [
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.253.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0174faf57b5c95f83",
        "vpc_id": "vpc-094933326926cea6e",
        "name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksPrivateRouteTable",
        "routes": [
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.53.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-0146540a2ea5f89ae",
            "state": "active"
          },
          {
            "destination": "pl-00e6c6e1782ff8ced",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "pl-7ca54015",
            "target": "vpce-0ce215e0b9356a2aa",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0eddc3ba335418a31",
            "main": false
          },
          {
            "subnet_id": "subnet-028a26ab98353ce33",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-021209cc64fa3c9ed",
        "vpc_id": "vpc-064b86b11d9115a70",
        "name": "internal-rt",
        "routes": [
          {
            "destination": "224.0.0.0/24",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "239.255.0.0/24",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "10.255.255.0/24",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "10.254.0.0/23",
            "target": "i-068dcf84dc6ee7a7d",
            "state": "active"
          },
          {
            "destination": "10.128.0.0/22",
            "target": "pcx-0f27a140a0105c914",
            "state": "active"
          },
          {
            "destination": "192.168.80.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.0.0/20",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "10.44.48.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.64.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.80.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.112.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.128.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.144.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.160.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "192.168.0.0/16",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "10.3.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.4.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.5.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.53.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/11",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "nat-0e395df8f49f6c3ad",
            "state": "active"
          },
          {
            "destination": "pl-7ca54015",
            "target": "vpce-07806b525c0cde314",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-06c6dd49ea348c9fa",
            "main": false
          },
          {
            "subnet_id": "subnet-0c51c31bf9a006642",
            "main": false
          },
          {
            "subnet_id": "subnet-001b02f4ac035399e",
            "main": false
          },
          {
            "subnet_id": "subnet-0068f0b99d020a06b",
            "main": false
          },
          {
            "subnet_id": "subnet-00bfbc041b7ac4e95",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0cff72ffd2f8ce3ef",
        "vpc_id": "vpc-0cc93b88905c8eb8d",
        "name": "",
        "routes": [
          {
            "destination": "10.131.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0797130663edb5557",
        "vpc_id": "vpc-064b86b11d9115a70",
        "name": "default-rt",
        "routes": [
          {
            "destination": "10.254.0.0/23",
            "target": "i-068dcf84dc6ee7a7d",
            "state": "active"
          },
          {
            "destination": "192.168.80.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.0.0/20",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "10.44.48.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.64.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.80.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.112.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.128.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.144.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.44.160.0/20",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.4.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.5.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.37.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.53.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.255.0.0/16",
            "target": "i-02fb1bbb84b197ef5",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/11",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-008ffec316eede56d",
            "state": "active"
          },
          {
            "destination": "pl-7ca54015",
            "target": "vpce-07806b525c0cde314",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          },
          {
            "subnet_id": "subnet-084b8d7b32a6b36a2",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-037d7aeb3c70575f0",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "name": "eks-vpc-public-rt",
        "routes": [
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.253.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-0bef5007a689b424d",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-056a270c9cb1ab8be",
            "main": false
          },
          {
            "subnet_id": "subnet-05a52e047704ecf1c",
            "main": false
          },
          {
            "subnet_id": "subnet-08fd3e96ecc9e773c",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0008ee16cda991034",
        "vpc_id": "vpc-07b89576ed160f978",
        "name": "foxglove-poc-vpc-default",
        "routes": [
          {
            "destination": "10.0.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": null,
            "main": true
          }
        ]
      },
      {
        "id": "rtb-0b75a1c1f69e28f34",
        "vpc_id": "vpc-0c5ed9c2ba56a7808",
        "name": "pintel-vpc-public-rt",
        "routes": [
          {
            "destination": "192.168.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.5.0.0/16",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "172.16.0.0/12",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "10.0.0.0/8",
            "target": "local",
            "state": "active"
          },
          {
            "destination": "0.0.0.0/0",
            "target": "igw-0ec45c206ecb01dc1",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-07305d9f47cbf9994",
            "main": false
          },
          {
            "subnet_id": "subnet-043aebf49d674359b",
            "main": false
          }
        ]
      },
      {
        "id": "rtb-0f9d4049092d5080f",
        "vpc_id": "vpc-064b86b11d9115a70",
        "name": "ic-observatory-api-alb-private",
        "routes": [
          {
            "destination": "172.31.0.0/16",
            "target": "local",
            "state": "active"
          }
        ],
        "associations": [
          {
            "subnet_id": "subnet-0e306421c3f6aa130",
            "main": false
          },
          {
            "subnet_id": "subnet-04512e3b6941f8ab2",
            "main": false
          }
        ]
      }
    ],
    "security_groups": [
      {
        "id": "sg-08778a4ed02ce05a1",
        "name": "saas-probe-20260319071658466600000001",
        "description": "SaaS probe: all outbound for network testing, no inbound",
        "vpc_id": "vpc-03c6dac4b77bd22a5",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_PROJECT": "saas-probe",
          "Region": "eu-central-1",
          "Team": "infra",
          "Name": "saas-probe-eu-central-1",
          "Purpose": "saas-probe",
          "ManagedBy": "terraform",
          "TerraformDomain": "hmnd-network/saas-probe",
          "Environment": "production",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_SERVICE": "saas-probe",
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_USER": "general"
        }
      },
      {
        "id": "sg-0c238e45f99cfd69e",
        "name": "tjac-g6-ssh",
        "description": "SSH access for tjac g6 instance",
        "vpc_id": "vpc-03c6dac4b77bd22a5",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "195.167.128.42/32"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 47995,
            "to_port": 48012,
            "sources": [
              "195.167.128.42/32"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8899,
            "to_port": 8899,
            "sources": [
              "195.167.128.42/32"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8211,
            "to_port": 8211,
            "sources": [
              "195.167.128.42/32"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8011,
            "to_port": 8011,
            "sources": [
              "195.167.128.42/32"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-01cf02f75b4a8e829",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-03c6dac4b77bd22a5",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-008b75f9f5d901bca",
        "name": "launch-wizard-2",
        "description": "launch-wizard-2 created 2025-11-21T10:29:01.301Z",
        "vpc_id": "vpc-00e7b72129f9e7a2c",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0571b6cd7b7c48336",
        "name": "launch-wizard-3",
        "description": "launch-wizard-3 created 2025-11-21T11:10:53.183Z",
        "vpc_id": "vpc-00e7b72129f9e7a2c",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 6443,
            "to_port": 6443,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 10250,
            "to_port": 10250,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 2379,
            "to_port": 2379,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 0,
            "to_port": 65535,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 2380,
            "to_port": 2380,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0a0233f6295e80835",
        "name": "launch-wizard-1",
        "description": "launch-wizard-1 created 2025-11-20T16:26:33.138Z",
        "vpc_id": "vpc-00e7b72129f9e7a2c",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-09f1996e9a115b988",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-00e7b72129f9e7a2c",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0b3527e6d1eaf3071",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0d699aada404b8edc",
        "name": "sky-sg-ubuntu-a330",
        "description": "Auto-created security group for Ray workers",
        "vpc_id": "vpc-05b5920e463e9a82b",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-05709247507f96540",
        "name": "launch-wizard-1",
        "description": "launch-wizard-1 created 2025-07-03T10:18:42.407Z",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "icmp",
            "from_port": -1,
            "to_port": -1,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-023aa7fb746c098fa",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-00613666bbf826344",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0afa29ec8beaf69d1",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-05b5920e463e9a82b",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0d009a70d3e5c1dd8",
        "name": "humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-sg",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-00613666bbf826344",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_USER": "dmac",
          "Name": "humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-sg"
        }
      },
      {
        "id": "sg-003fe6d1f25dc15bb",
        "name": "yellowdog-sg",
        "description": "yellow dog agent security group",
        "vpc_id": "vpc-00613666bbf826344",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-04ced24acde5a9dfd",
        "name": "packer_686aba9f-ff9b-e03b-fdd3-a7870b60cc31",
        "description": "Temporary group for Packer",
        "vpc_id": "vpc-0da7cd54df9b385e4",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-090fac64a9805c493",
        "name": "launch-wizard-4",
        "description": "launch-wizard-4 created 2025-03-21T19:20:35.885Z",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0427273f73d62a8f8",
        "name": "launch-wizard-7",
        "description": "launch-wizard-7 created 2025-06-30T15:12:42.661Z",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-022c91aef9d1e1acb",
        "name": "launch-wizard-6",
        "description": "launch-wizard-6 created 2025-06-14T11:35:49.892Z",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0cb1bde0ad1326c85",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-028c5f171f9b93e38",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0c620fb83f5b3c119",
        "name": "launch-wizard-3",
        "description": "launch-wizard-3 created 2025-03-21T17:58:17.854Z",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "icmp",
            "from_port": -1,
            "to_port": -1,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0d4b450216bf89298",
        "name": "launch-wizard-2",
        "description": "launch-wizard-2 created 2025-03-21T17:50:43.634Z",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "icmp",
            "from_port": -1,
            "to_port": -1,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0b75e464e4a0f6d3b",
        "name": "launch-wizard-5",
        "description": "launch-wizard-5 created 2025-03-24T09:51:32.922Z",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0d21b80963feb47cc",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-0da7cd54df9b385e4",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-01d6f22f87e359d94",
        "name": "workspace-shared-sg",
        "description": "workspace-shared-sg",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-033102ad0fc17ff00",
        "name": "packer_686aba9f-25af-f09d-3739-c347abc3ed7f",
        "description": "Temporary group for Packer",
        "vpc_id": "vpc-0da7cd54df9b385e4",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-075e28bc6cf6c063f",
        "name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-sg",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-028c5f171f9b93e38",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_SERVICE": "prefect",
          "Name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-sg",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_PROJECT": "general-development"
        }
      },
      {
        "id": "sg-0a476a1ec92b4924d",
        "name": "launch-wizard-1",
        "description": "launch-wizard-1 created 2025-03-14T15:17:58.573Z",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "icmp",
            "from_port": -1,
            "to_port": -1,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-05de8793f1b282f6a",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-03be744b483e1ac89",
        "name": "yellowdog-sg",
        "description": "Yellow dog workers SG ",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-06748b3982c40ab58",
        "name": "hmnd-ml-vpce-dev-us-west-1-20260129165054721400000001",
        "description": "Security group for VPC interface endpoints",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "10.1.0.0/16"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "ManagedBy": "Terraform",
          "Environment": "dev",
          "Name": "hmnd-ml-sg-vpce-dev-us-west-1",
          "Project": "HMND-ML",
          "Region": "us-west-1"
        }
      },
      {
        "id": "sg-0b92a2463eafa9537",
        "name": "k8s-default-cfilsshs-9db1f62fcb",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/cfil-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1"
        }
      },
      {
        "id": "sg-05c9b399310ac42ec",
        "name": "k8s-default-testuser-3c9307ec0e",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1",
          "service.k8s.aws/stack": "default/testuser-dev-1gpu-ssh-service"
        }
      },
      {
        "id": "sg-06a175707bf5c7488",
        "name": "sky-sg-ubuntu-a330",
        "description": "Auto-created security group for Ray workers",
        "vpc_id": "vpc-006b54fa0165dba13",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-02e5325fa38bf1244",
        "name": "hmnd-ml-fsx-lustre-dev-us-west-1-20250921115609365200000001",
        "description": "FSx for Lustre access",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 988,
            "to_port": 988,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 1018,
            "to_port": 1023,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Project": "HMND-ML",
          "Region": "us-west-1",
          "ManagedBy": "Terraform",
          "Environment": "dev",
          "Name": "hmnd-ml-sg-fsx-dev-us-west-1"
        }
      },
      {
        "id": "sg-0bad283d9e8fb257a",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-096ec5b2694f81753",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-0843dca91e5e4b27e",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0eba2cfd5c63c24ff",
        "name": "humanoid-lab-uce-us-west-1-SPOT_p5-48xlarge-sg",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-0843dca91e5e4b27e",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_SERVICE": "prefect",
          "Name": "humanoid-lab-uce-us-west-1-SPOT_p5-48xlarge-sg"
        }
      },
      {
        "id": "sg-0eb9f9a619038eeac",
        "name": "k8s-default-dmacsshs-29b6c587ee",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/dmac-ssh-service"
        }
      },
      {
        "id": "sg-0029201c90c0d16d9",
        "name": "k8s-default-ismadev2-032612f58a",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/isma-dev-2gpu-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1"
        }
      },
      {
        "id": "sg-063566d0137773a12",
        "name": "dmac-ec2-ssh-access",
        "description": "SSH access for dmac EC2 instance",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "179.221.75.121/32",
              "191.35.173.98/32",
              "167.249.65.28/32",
              "177.130.116.53/32",
              "152.37.118.125/32",
              "82.163.196.114/32",
              "143.58.132.168/32"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0efc691bbfbde62aa",
        "name": "hmnd-ml-eks-cluster-dev-us-west-1-20250921115101807300000001",
        "description": "Security group for EKS cluster control plane",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "192.168.0.0/16",
              "172.16.0.0/12",
              "10.0.0.0/8"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "ManagedBy": "Terraform",
          "Name": "hmnd-ml-sg-eks-cluster-dev-us-west-1",
          "Region": "us-west-1",
          "Project": "HMND-ML",
          "Environment": "dev"
        }
      },
      {
        "id": "sg-011bd8cf21e74594b",
        "name": "k8s-default-ccoptrai-9ec4347dbe",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1",
          "service.k8s.aws/stack": "default/ccop-training-8gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0408ba2ac800a2f1d",
        "name": "k8s-default-byandev8-baa16d1240",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1",
          "service.k8s.aws/stack": "default/byan-dev-8gpu-ssh-service"
        }
      },
      {
        "id": "sg-039167064d47ff179",
        "name": "hmndsharedml-backend-sg",
        "description": "Backend SecurityGroup for Shared ALB for EKS ML services",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "192.168.0.0/16",
              "172.16.0.0/12",
              "10.0.0.0/8"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Environment": "dev",
          "Project": "HMND-ML",
          "ManagedBy": "Terraform",
          "elbv2.k8s.aws/resource": "backend-sg",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1"
        }
      },
      {
        "id": "sg-09a0d5aaaed83009d",
        "name": "hmnd-ml-eks-nodes-dev-us-west-1-20250921115106943400000003",
        "description": "Security group for EKS worker nodes - ML optimized",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "udp",
            "from_port": 1024,
            "to_port": 65535,
            "sources": [
              "10.1.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": [
              "172.16.0.0/12",
              "10.0.0.0/8",
              "192.168.0.0/16"
            ]
          },
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "172.16.0.0/12",
              "192.168.0.0/16",
              "10.3.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 32549,
            "sources": []
          },
          {
            "protocol": "udp",
            "from_port": 0,
            "to_port": 65535,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 1024,
            "to_port": 65535,
            "sources": [
              "10.1.0.0/16"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Project": "HMND-ML",
          "Environment": "dev",
          "Region": "us-west-1",
          "ManagedBy": "Terraform",
          "karpenter.sh/discovery": "hmnd-ml-dev-us-west-1",
          "Purpose": "ml-compute-optimized",
          "Name": "hmnd-ml-sg-eks-nodes-dev-us-west-1"
        }
      },
      {
        "id": "sg-0c557c266ae76f087",
        "name": "k8s-default-ccoptrai-fa0953c985",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/ccoptraining-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0507e2491b7ee9eb8",
        "name": "k8s-default-testheal-44123aa14d",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/testhealth-dev-1gpu-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-092b10a6cfdbf6e9c",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-006b54fa0165dba13",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-070cc2cd061e1b90b",
        "name": "k8s-default-ccop8gpu-d5d47fd4da",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/ccop8gpu-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0e41ffb6c1bd64b78",
        "name": "k8s-default-dalm2ssh-e6ea7c9d78",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1",
          "service.k8s.aws/stack": "default/dalm2-ssh-service"
        }
      },
      {
        "id": "sg-08a0c73597c3a6bda",
        "name": "eks-cluster-sg-hmnd-ml-dev-us-west-1-219639886",
        "description": "EKS created security group applied to ENI that is attached to EKS Control Plane master nodes, as well as any managed workloads.",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "eks-cluster-sg-hmnd-ml-dev-us-west-1-219639886",
          "aws:eks:cluster-name": "hmnd-ml-dev-us-west-1",
          "kubernetes.io/cluster/hmnd-ml-dev-us-west-1": "owned"
        }
      },
      {
        "id": "sg-040dce8fdcd314abd",
        "name": "hmndsharedml-frontend-sg",
        "description": "Frontend SecurityGroup for Shared ALB for EKS ML services",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "172.16.0.0/12",
              "10.0.0.0/8",
              "192.168.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "172.16.0.0/12",
              "192.168.0.0/16",
              "10.0.0.0/8"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Environment": "dev",
          "ingress.k8s.aws/stack": "hmnd-shared-ml",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1",
          "ManagedBy": "Terraform",
          "Project": "HMND-ML",
          "ingress.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0002e7f0156210781",
        "name": "k8s-default-dmacdev2-6786e5c9b0",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/dmac-dev-2gpu-ssh-service"
        }
      },
      {
        "id": "sg-0d9a0df64cf6fe526",
        "name": "k8s-default-cfildev1-dfb65bcbcf",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/cfil-dev-1gpu-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-us-west-1"
        }
      },
      {
        "id": "sg-0ed6f5299b0e71761",
        "name": "hmnd-eks-cluster-alb-ingress",
        "description": "Security group for ALB to allow inbound traffic from TGW-connected networks",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "10.0.0.0/8",
              "172.31.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "172.31.0.0/16",
              "10.0.0.0/8"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "hmnd-eks-cluster-alb-ingress",
          "Team": "shared",
          "ManagedBy": "terraform",
          "Purpose": "alb-security-group",
          "Environment": "production",
          "Region": "eu-west-2"
        }
      },
      {
        "id": "sg-045fd656ca8161a72",
        "name": "hmnd-ml-eks-cluster-dev-eu-west-2-20250917140056449100000001",
        "description": "Security group for EKS cluster control plane",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "192.168.0.0/16",
              "172.16.0.0/12",
              "10.0.0.0/8"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Region": "eu-west-2",
          "ManagedBy": "Terraform",
          "Environment": "dev",
          "Project": "HMND-ML",
          "Name": "hmnd-ml-sg-eks-cluster-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0f059a73507854862",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-0c5ed9c2ba56a7808",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-085c3608e0eb89b5b",
        "name": "infra-dashboard-collector-20260222170233736300000001",
        "description": "Infra dashboard collector: outbound HTTPS + DNS only",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 6443,
            "to_port": 6443,
            "destinations": [
              "3.110.31.221/32",
              "158.252.119.42/32",
              "10.44.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Region": "eu-west-2",
          "Team": "infra",
          "HM_COST_TAG_PROJECT": "infra-dashboard",
          "Purpose": "infra-dashboard",
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_USER": "general",
          "Name": "infra-dashboard-collector",
          "HM_COST_TAG_SERVICE": "infra-dashboard",
          "TerraformDomain": "hmnd-network/infra-dashboard",
          "ManagedBy": "terraform",
          "Environment": "production",
          "HM_COST_TAG_GROUP": "infra"
        }
      },
      {
        "id": "sg-04662ec0f5e1723f7",
        "name": "k8s-monitori-kubeprom-1a0f47e114",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "monitoring/kube-prometheus-stack-grafana"
        }
      },
      {
        "id": "sg-0979357ec29940975",
        "name": "batch_compute_sg",
        "description": "Access to batch jobs",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 2049,
            "to_port": 2049,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-038086629e7b1b9ff",
        "name": "cursor-agent-ssm-relay",
        "description": "Cursor Cloud SSM relay - outbound HTTPS only for SSM agent",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "cursor-agent-ssm-relay",
          "Purpose": "cursor-cloud-ssm-relay",
          "ManagedBy": "cli",
          "Team": "infra"
        }
      },
      {
        "id": "sg-0968388d2224b98d7",
        "name": "coolify_sg",
        "description": "Coolify SG",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0c7c64b2aac3c7d4c",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-094933326926cea6e",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0b7983efe55b00845",
        "name": "k8s-default-gcerdevc-86ff32ed3f",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/gcer-dev-cpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-0278dc5bcf175ffaf",
        "name": "efs_security_group",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 2049,
            "to_port": 2049,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Policy": "protected",
          "Name": "efs_security_group",
          "Type": "workstation"
        }
      },
      {
        "id": "sg-0aa008fd3f716dd20",
        "name": "k8s-default-dmshdev4-fa82eadb2e",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/dmsh-dev4-eks-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-00a481410295e1f1c",
        "name": "internal-svc-task-20260326115051760400000003",
        "description": "Internal service tasks: inbound from ALB only, outbound HTTPS + DNS",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "destinations": [
              "10.0.0.0/8"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "ManagedBy": "terraform",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_SERVICE": "internal-apps",
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_USER": "general",
          "HM_COST_TAG_PROJECT": "internal-apps",
          "TerraformDomain": "hmnd-network/internal-apps"
        }
      },
      {
        "id": "sg-09f35f98eb92eca27",
        "name": "infra-streams-task-20260223092538573100000001",
        "description": "go2rtc: inbound from ALB on 1984, outbound RTSP/RTSPS to NVRs",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 7441,
            "to_port": 7441,
            "destinations": [
              "10.44.0.0/20",
              "10.44.64.0/20"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 7447,
            "to_port": 7447,
            "destinations": [
              "10.44.64.0/20",
              "10.44.0.0/20"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Purpose": "infra-dashboard",
          "Name": "infra-streams-task",
          "HM_COST_TAG_PROJECT": "infra-dashboard",
          "Region": "eu-west-2",
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_USER": "general",
          "TerraformDomain": "hmnd-network/infra-dashboard",
          "HM_COST_TAG_SERVICE": "infra-dashboard",
          "Team": "infra",
          "Environment": "production",
          "HM_COST_TAG_GROUP": "infra",
          "ManagedBy": "terraform"
        }
      },
      {
        "id": "sg-0092a5c71e06b44d8",
        "name": "k8s-default-maprdev1-458c83a541",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/mapr-dev-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-08e58ae125f4875ff",
        "name": "dns-test-sg",
        "description": "Temporary security group for DNS testing",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0a4b85ca084d3c8a9",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0a55e348ea025ab87",
        "name": "humanoid-lab-uce-eu-west-2-SPOT_p5-48xlarge-sg",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-0cc93b88905c8eb8d",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac",
          "Name": "humanoid-lab-uce-eu-west-2-SPOT_p5-48xlarge-sg"
        }
      },
      {
        "id": "sg-0b25404a1c0ba5e3d",
        "name": "hb-linux-amd64-ubuntu-2204-github-actions-runner-sg20250702111553086800000001",
        "description": "Github Actions Runner security group",
        "vpc_id": "vpc-003033d62c0c872bb",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "ghr:environment": "hb-linux-amd64-ubuntu-2204",
          "ghr:ssm_config_path": "/github-action-runners/hb/linux-amd64-ubuntu-2204/runners/config",
          "Name": "hb-linux-amd64-ubuntu-2204-action-runner"
        }
      },
      {
        "id": "sg-0fd168fe0a3c8e876",
        "name": "launch-wizard-24",
        "description": "launch-wizard-24 created 2026-03-12T17:28:02.499Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-097080d370322d8d5",
        "name": "launch-wizard-16",
        "description": "launch-wizard-16 created 2025-09-02T12:06:28.512Z",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0567547f25ea0bdf2",
        "name": "k8s-default-dgradeve-ff5066491d",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 7777,
            "to_port": 7777,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 5173,
            "to_port": 5173,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/dgra-dev-eks-cpu-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0f39bb73aadef2468",
        "name": "k8s-default-dgratrai-3dbf0f6093",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/dgra-training2-8gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0e2739bb6d066d3ef",
        "name": "eks-cluster-sg-foxglove-poc-cluster-1663664370",
        "description": "EKS created security group applied to ENI that is attached to EKS Control Plane master nodes, as well as any managed workloads.",
        "vpc_id": "vpc-07b89576ed160f978",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": []
          },
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "aws:eks:cluster-name": "foxglove-poc-cluster",
          "kubernetes.io/cluster/foxglove-poc-cluster": "owned",
          "Name": "eks-cluster-sg-foxglove-poc-cluster-1663664370"
        }
      },
      {
        "id": "sg-067b95608d640a1ac",
        "name": "launch-wizard-25",
        "description": "launch-wizard-25 created 2026-04-10T09:45:20.477Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0011c63a9f8e2bf73",
        "name": "k8s-default-dgradeve-1889fb0001",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/dgra-dev-eks-1gpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0859a0d8c50dbf227",
        "name": "k8s-default-atindeve-bf9c1d358d",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8000,
            "to_port": 8000,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/atin-dev-eks-2gpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0a362a3da4ea5b3fb",
        "name": "k8s-default-dalminfe-dca08fa022",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/dalm-inference-1gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-07b9c5821207e6c2a",
        "name": "launch-wizard-2",
        "description": "launch-wizard-2 created 2024-09-27T17:22:59.560Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0e08ffd40762fc74d",
        "name": "security-group-for-outbound-nfs-d-efyj3ylggjnx",
        "description": "[DO NOT DELETE] Security Group that allows outbound NFS traffic for SageMaker Notebooks Domain [d-efyj3ylggjnx]",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 988,
            "to_port": 988,
            "destinations": []
          },
          {
            "protocol": "tcp",
            "from_port": 1018,
            "to_port": 1023,
            "destinations": []
          },
          {
            "protocol": "tcp",
            "from_port": 2049,
            "to_port": 2049,
            "destinations": []
          }
        ],
        "tags": {
          "ManagedByAmazonSageMakerResource": "arn:aws:sagemaker:eu-west-2:767828728064:domain/d-efyj3ylggjnx"
        }
      },
      {
        "id": "sg-013d7d9a38431eb35",
        "name": "k8s-kubesyst-ingressn-a665c339b6",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "176.56.202.0/24",
              "176.56.204.0/24",
              "192.222.48.0/24",
              "38.32.107.76/30",
              "64.124.32.124/30",
              "89.124.37.245/32",
              "89.124.38.242/32"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "176.56.202.0/24",
              "176.56.204.0/24",
              "192.222.48.0/24",
              "38.32.107.76/30",
              "64.124.32.124/30",
              "89.124.37.245/32",
              "89.124.38.242/32"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "kube-system/ingress-nginx-external-controller",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0f0954f6fdc524933",
        "name": "launch-wizard-4",
        "description": "launch-wizard-4 created 2024-10-09T17:46:47.107Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-04979ec0df71a5a6c",
        "name": "k8s-default-byandevn-3b6eb79606",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/byan-dev-new-4gpu-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-06e8a0c032ebfa88b",
        "name": "hmnd-eks-cluster-cluster-20250813185549336300000001",
        "description": "Security group for EKS cluster",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "172.31.0.0/16",
              "10.0.0.0/8"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 31102,
            "to_port": 32753,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Purpose": "eks-cluster",
          "Environment": "production",
          "kubernetes.io/cluster/hmnd-eks-cluster": "shared",
          "ManagedBy": "terraform",
          "Team": "shared",
          "Name": "hmnd-eks-cluster-cluster-sg",
          "Region": "eu-west-2"
        }
      },
      {
        "id": "sg-0d56cc5e1ab0904a5",
        "name": "hmnd-ml-kamino-dev-eu-west-2-alb-20260706161118728400000002",
        "description": "Public ALB security group for Kamino",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Region": "eu-west-2",
          "ManagedBy": "Terraform",
          "Name": "hmnd-ml-kamino-dev-eu-west-2-alb",
          "Project": "HMND-ML",
          "Environment": "dev",
          "Service": "kamino"
        }
      },
      {
        "id": "sg-074252a5fcdce9ce7",
        "name": "launch-wizard-21",
        "description": "launch-wizard-21 created 2025-11-05T13:01:12.493Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0d1682ea6e20d82ce",
        "name": "RDS from local",
        "description": "RDS from all private networks",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 5432,
            "to_port": 5432,
            "sources": [
              "10.0.0.0/8",
              "172.16.0.0/12",
              "192.168.0.0/16"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0bd0bd756dcec9e87",
        "name": "k8s-ops-ubuntuvn-2bce49ebe0",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-eks-cluster",
          "Environment": "production",
          "ManagedBy": "terraform",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "ops/ubuntu-vnc"
        }
      },
      {
        "id": "sg-0120bef45ab4b005b",
        "name": "github-runner-sg",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "github-runner-sg"
        }
      },
      {
        "id": "sg-02f5c1c0ccd0d8f0b",
        "name": "dbe-worker-866715466211721-1738596334886",
        "description": "Managed security group for worker with prefix dbe-worker-866715466211721-1738596334886 in vpc-08154cc6565a961cb",
        "vpc_id": "vpc-08154cc6565a961cb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "18.134.65.240/28",
              "3.10.112.150/32",
              "18.168.134.254/32"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 5555,
            "to_port": 5556,
            "sources": [
              "18.134.65.240/28",
              "18.168.134.254/32",
              "3.10.112.150/32"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 0,
            "to_port": 65535,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 5557,
            "to_port": 5557,
            "sources": [
              "18.134.65.240/28",
              "18.168.134.254/32",
              "3.10.112.150/32"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0da5b1cd17eded7a6",
        "name": "k8s-default-eulypi07-86ed7a7418",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/euly-pi07-serve-0625-eks-1gpu-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-083faaae2cd052a4d",
        "name": "k8s-default-ccopinfe-266955a202",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8888,
            "to_port": 8888,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 6006,
            "to_port": 6006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8000,
            "to_port": 8000,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 7777,
            "to_port": 7777,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9087,
            "to_port": 9087,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9007,
            "to_port": 9007,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9876,
            "to_port": 9876,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/ccop-infe2-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-071f7692d80d00713",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "10.0.0.0/8",
              "192.168.0.0/16",
              "172.16.0.0/12",
              "10.44.14.241/32",
              "10.44.14.166/32"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "all private networks"
        }
      },
      {
        "id": "sg-08f764d5435895c32",
        "name": "k8s-vlmproxy-vlmproxy-c7e64b3364",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "vlm-proxy-dev/vlm-proxy"
        }
      },
      {
        "id": "sg-0e7027b0307c563b4",
        "name": "launch-wizard-26",
        "description": "launch-wizard-26 created 2026-04-10T09:57:50.747Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0599c964d9c5ead04",
        "name": "k8s-default-dmshdev3-6c012da0b6",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/dmsh-dev3-eks-1gpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0921ccff4a5bc5838",
        "name": "eks-cluster-sg-hmnd-ml-dev-eu-west-2-1735206403",
        "description": "EKS created security group applied to ENI that is attached to EKS Control Plane master nodes, as well as any managed workloads.",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "aws:eks:cluster-name": "hmnd-ml-dev-eu-west-2",
          "Name": "eks-cluster-sg-hmnd-ml-dev-eu-west-2-1735206403",
          "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "owned"
        }
      },
      {
        "id": "sg-0e56ef8f10b7789d3",
        "name": "k8s-default-byandev1-6f58516d0b",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/byan-dev-1gpu-4-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0afb220eff7dcb1ea",
        "name": "internal-svc-alb-20260326115051760200000002",
        "description": "Internal services ALB: inbound HTTPS from internet, outbound to tasks",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "destinations": []
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_USER": "general",
          "ManagedBy": "terraform",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_SERVICE": "internal-apps",
          "TerraformDomain": "hmnd-network/internal-apps",
          "HM_COST_TAG_PROJECT": "internal-apps"
        }
      },
      {
        "id": "sg-0fad1cb4d95224bf7",
        "name": "launch-wizard-20",
        "description": "launch-wizard-20 created 2025-10-03T10:56:01.514Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-050d1a67a282cef34",
        "name": "launch-wizard-15",
        "description": "launch-wizard-15 created 2025-06-27T10:27:31.012Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "82.163.196.114/32"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0e16329c951355109",
        "name": "k8s-default-maprdeve-b4d9ce485a",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/mapr-dev-eks-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-024ff3b184e54984e",
        "name": "sky-sg-ubuntu-a330",
        "description": "Auto-created security group for Ray workers",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-00e15893612402eee",
        "name": "launch-wizard-12",
        "description": "launch-wizard-12 created 2025-05-01T21:54:52.768Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0c3a1ce2de1901ea2",
        "name": "k8s-default-dalmconv-c383307936",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/dalm-conveyor-inference-1gpu-ssh-service"
        }
      },
      {
        "id": "sg-0ee9a3d106783c293",
        "name": "melts-grafana-alb-20260617155017868500000001",
        "description": "melts.ic.hmnd.ai ALB - public 443/80",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Project": "hmnd-network",
          "Module": "melts-grafana",
          "ManagedBy": "terraform"
        }
      },
      {
        "id": "sg-0f11c995d69de61e6",
        "name": "k8s-default-joejeffc-6fb240ba37",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/joe-jeffcock-dev-eks-cpu-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0042aa09a56eb8d8e",
        "name": "k8s-default-olsiagen-d3a43480e5",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/olsi-agentui-eks-cpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0f1484778eed1e70d",
        "name": "k8s-default-dmshdev5-f833daa492",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/dmsh-dev5-eks-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-00eb5968c6d7cc5c8",
        "name": "k8s-default-byandev8-ad282de6a3",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/byan-dev-8gpu-ssh-service"
        }
      },
      {
        "id": "sg-066a3bf374ee525bd",
        "name": "launch-wizard-28",
        "description": "launch-wizard-28 created 2026-06-10T15:36:23.495Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-05eb501182681db5c",
        "name": "k8s-default-ashudev0-99f03d0a25",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/ashu-dev-0gpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-01b675fb1bf4eebc0",
        "name": "k8s-default-jamodev8-aecbc4316e",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/jamo-dev-8gpu-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-033764e35578cdaf9",
        "name": "k8s-default-triggera-13c377b627",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-eks-cluster",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/trigger-alb-creation-nginx",
          "Environment": "production",
          "ManagedBy": "terraform"
        }
      },
      {
        "id": "sg-023f193030815f8cd",
        "name": "mata-workstation-sg",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9000,
            "to_port": 9000,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Policy": "protected",
          "Type": "workstation",
          "Name": "mata-workstation-sg",
          "Owner": "mata"
        }
      },
      {
        "id": "sg-09a9313089a546f1a",
        "name": "k8s-default-dgrachev-67c30d8737",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/dgrachev-dev-eks-cpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-01d130f74ea5f3af6",
        "name": "hmnd-ml-kamino-dev-eu-west-2-dev-webrtc-20260715144655017400000001",
        "description": "Kamino WebRTC media NLB security group (dev)",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "udp",
            "from_port": 47998,
            "to_port": 48027,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "hmnd-ml-kamino-dev-eu-west-2-dev-webrtc",
          "Region": "eu-west-2",
          "ManagedBy": "Terraform",
          "Project": "HMND-ML",
          "Environment": "dev",
          "Service": "kamino"
        }
      },
      {
        "id": "sg-0715faf3049437790",
        "name": "k8s-traffic-foxglovepoccluster-ed318f0d13",
        "description": "[k8s] Shared Backend SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-07b89576ed160f978",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/resource": "backend-sg",
          "elbv2.k8s.aws/cluster": "foxglove-poc-cluster"
        }
      },
      {
        "id": "sg-0a13b87824a011a78",
        "name": "k8s-foxglove-site-ffe88b87ec",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-07b89576ed160f978",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "foxglove-poc-cluster",
          "ingress.k8s.aws/stack": "foxglove/site",
          "ingress.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0b7d0f8750bb78aab",
        "name": "k8s-default-jamoinf1-1e09ae663f",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9009,
            "to_port": 9009,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9007,
            "to_port": 9007,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/jamo-inf-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-02726cf9ff151ca24",
        "name": "poc_vpn_gw",
        "description": "poc_vpn_gw",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "50",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 500,
            "to_port": 500,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 4500,
            "to_port": 4500,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "poc_vpn_gw"
        }
      },
      {
        "id": "sg-087a9e3a217f9ad21",
        "name": "k8s-default-cfildev1-bcb3099b89",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9010,
            "to_port": 9010,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/cfil-dev-1gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0d922475429d75881",
        "name": "k8s-default-byandev1-23683432de",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/byan-dev-1gpu-ssh-service"
        }
      },
      {
        "id": "sg-0a59a64deae81c98f",
        "name": "eic-endpoint-sg",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "eic-endpoint-sg"
        }
      },
      {
        "id": "sg-04a4710a75984c8f9",
        "name": "k8s-default-jamodev1-da88f3c205",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/jamo-dev-1gpu-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-028f319ebdca02498",
        "name": "launch-wizard-27",
        "description": "launch-wizard-27 created 2026-04-15T12:55:21.257Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-02ecccfb760888b43",
        "name": "k8s-default-dalmdata-8b0a1f949f",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/dalm-data-tests-no-mnt-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-0fcbacb7d24a2a6e8",
        "name": "security-group-for-inbound-nfs-d-efyj3ylggjnx",
        "description": "[DO NOT DELETE] Security Group that allows inbound NFS traffic for SageMaker Notebooks Domain [d-efyj3ylggjnx]",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 988,
            "to_port": 988,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 1018,
            "to_port": 1023,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 2049,
            "to_port": 2049,
            "sources": []
          }
        ],
        "egress": [],
        "tags": {
          "ManagedByAmazonSageMakerResource": "arn:aws:sagemaker:eu-west-2:767828728064:domain/d-efyj3ylggjnx"
        }
      },
      {
        "id": "sg-0d398c8000a52c949",
        "name": "hmnd-eks-cluster-cluster-20250706184201185200000001",
        "description": "Security group for EKS cluster",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "172.31.0.0/16",
              "10.0.0.0/8"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 31719,
            "to_port": 32753,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "hmnd-eks-cluster-cluster-sg",
          "Team": "shared",
          "Region": "eu-west-2",
          "Environment": "production",
          "Purpose": "eks-cluster",
          "ManagedBy": "terraform"
        }
      },
      {
        "id": "sg-0ab6d2f79668baf6e",
        "name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DBSWorkspaceSG",
        "description": "Allow access from within the same security group",
        "vpc_id": "vpc-094933326926cea6e",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": []
          },
          {
            "protocol": "udp",
            "from_port": 0,
            "to_port": 65535,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "destinations": []
          },
          {
            "protocol": "tcp",
            "from_port": 5432,
            "to_port": 5432,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 0,
            "to_port": 65535,
            "destinations": []
          },
          {
            "protocol": "tcp",
            "from_port": 3306,
            "to_port": 3306,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8451,
            "destinations": [
              "18.134.65.240/28"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "aws:cloudformation:stack-name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71",
          "Name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DBSWorkspaceSG",
          "Vendor": "Databricks",
          "aws:cloudformation:logical-id": "DBSWorkspaceSecurityGroup",
          "aws:cloudformation:stack-id": "arn:aws:cloudformation:eu-west-2:767828728064:stack/AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71/2072bcd0-f805-11ef-bda0-0202abced499"
        }
      },
      {
        "id": "sg-095f138e44e795319",
        "name": "hmnd-console-staging-db-sg-20260218112529762800000001",
        "description": "Security group for hmnd-console staging Postgres",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 5432,
            "to_port": 5432,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_USER": "general",
          "HM_COST_TAG_PROJECT": "humanoid-console",
          "Name": "hmnd-console-staging-db-sg",
          "HM_COST_TAG_SERVICE": "humanoid-console-rds",
          "HM_COST_TAG_GROUP": "data",
          "HM_COST_TAG_ENV": "staging"
        }
      },
      {
        "id": "sg-028cc31b1eca0b7b8",
        "name": "k8s-default-sfeddeve-ac35c37140",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/sfed-dev-eks-cpu-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0a53c6016eb5b4804",
        "name": "infra-dashboard-probe-20260226084006790200000001",
        "description": "Network probe: ICMP + TCP/UDP to site subnets, HTTPS for S3/SSM/CW",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [],
        "egress": [
          {
            "protocol": "udp",
            "from_port": 1,
            "to_port": 65535,
            "destinations": [
              "10.44.64.0/20",
              "10.44.96.0/20",
              "10.44.0.0/20",
              "10.44.48.0/20",
              "10.44.80.0/20"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 1,
            "to_port": 65535,
            "destinations": [
              "10.44.64.0/20",
              "10.44.96.0/20",
              "10.44.48.0/20",
              "10.44.0.0/20",
              "10.44.80.0/20"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "icmp",
            "from_port": -1,
            "to_port": -1,
            "destinations": [
              "10.44.48.0/20",
              "10.44.64.0/20",
              "10.44.80.0/20",
              "10.44.96.0/20",
              "10.44.0.0/20"
            ]
          }
        ],
        "tags": {
          "TerraformDomain": "hmnd-network/infra-dashboard",
          "HM_COST_TAG_PROJECT": "infra-dashboard",
          "Environment": "production",
          "Name": "infra-dashboard-probe",
          "Region": "eu-west-2",
          "HM_COST_TAG_GROUP": "infra",
          "Purpose": "infra-dashboard",
          "HM_COST_TAG_ENV": "prod",
          "ManagedBy": "terraform",
          "HM_COST_TAG_USER": "general",
          "Team": "infra",
          "HM_COST_TAG_SERVICE": "infra-dashboard"
        }
      },
      {
        "id": "sg-0d3c8933e79a56d1b",
        "name": "k8s-default-joejeffc-4fa31ddd78",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/joe-jeffcock-dev2-eks-1gpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0cd9a193f22eb1712",
        "name": "k8s-default-gwadloco-311ec20167",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/gwad-loco-training-4gpu-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0d8f5f1b504428a25",
        "name": "k8s-default-artpermi-6a30bfb19b",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/artpermiakov-dev-eks-cpu-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0cca1d2c1a1374331",
        "name": "launch-wizard-10",
        "description": "launch-wizard-10 created 2025-03-27T13:17:44.270Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0d90fbdcf25f9d3ee",
        "name": "launch-wizard-14",
        "description": "launch-wizard-14 created 2025-05-09T07:53:07.984Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "icmp",
            "from_port": -1,
            "to_port": -1,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0aa66275661d3a334",
        "name": "k8s-default-dgrainfe-a80c008f92",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/dgra-inference-1gpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-048569daa1257001e",
        "name": "k8s-traffic-hmndekscluster-4fca70ddda",
        "description": "[k8s] Shared Backend SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Environment": "production",
          "ManagedBy": "terraform",
          "elbv2.k8s.aws/cluster": "hmnd-eks-cluster",
          "elbv2.k8s.aws/resource": "backend-sg"
        }
      },
      {
        "id": "sg-0df552868f3f0ac81",
        "name": "NVIDIA Omniverse GPU-Optimized AMI-1.3.6-AutogenByAWSMP--1",
        "description": "NVIDIA Omniverse GPU-Optimized AMI-1.3.6-AutogenByAWSMP--1 created 2025-02-24T12:33:13.855Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "10.0.0.0/8"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0e8063eaa785c01eb",
        "name": "hb-linux-arm64-ubuntu-2204-github-actions-runner-sg20250703121140658800000001",
        "description": "Github Actions Runner security group",
        "vpc_id": "vpc-003033d62c0c872bb",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "ghr:environment": "hb-linux-arm64-ubuntu-2204",
          "Name": "hb-linux-arm64-ubuntu-2204-action-runner",
          "ghr:ssm_config_path": "/github-action-runners/hb/linux-arm64-ubuntu-2204/runners/config"
        }
      },
      {
        "id": "sg-089909575aa6c8a51",
        "name": "metastore-sg",
        "description": "sg for the rds used as metastore",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 5432,
            "to_port": 5432,
            "sources": [
              "85.240.205.45/32",
              "194.74.136.231/32",
              "172.31.0.0/16",
              "10.37.0.0/16",
              "10.37.0.143/32",
              "35.177.177.208/32"
            ]
          },
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "67.218.252.46/32",
              "194.74.136.231/32",
              "187.20.20.4/32",
              "217.35.235.115/32",
              "82.135.83.186/32",
              "10.37.0.0/16",
              "10.255.255.7/32",
              "10.44.14.0/24",
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 0,
            "sources": [
              "10.255.255.7/32",
              "172.31.9.238/32",
              "35.178.237.19/32"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0bac3a0b41a599d9a",
        "name": "k8s-default-dalmdev1-fe8ecb803a",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9008,
            "to_port": 9008,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9010,
            "to_port": 9010,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/dalm-dev-1gpu-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0cd54f116e8664d4b",
        "name": "k8s-default-ismadev2-b881f09d7e",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/isma-dev2-eks-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-0c9cd52a537afbd57",
        "name": "k8s-default-ismadev3-7de0ef88f9",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/isma-dev3-4gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-09bad4369406e481e",
        "name": "k8s-default-sepradev-7a96e946b6",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/sepra-dev4-eks-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-022fd132233cb52aa",
        "name": "k8s-default-atindeve-83d2033702",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/atin-dev-eks-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-022847b8efea99594",
        "name": "codex-sg",
        "description": "Codex god-mode box (codex)",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8090,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-05d37813275630752",
        "name": "schaeffler-poc-sg",
        "description": "Security group for schaeffler-poc EC2",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0c9e10471313cf4e7",
        "name": "NVIDIA Omniverse GPU-Optimized AMI-1.3.6-AutogenByAWSMP--2",
        "description": "NVIDIA Omniverse GPU-Optimized AMI-1.3.6-AutogenByAWSMP--2 created 2025-02-24T13:05:10.492Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "10.0.0.0/8",
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "10.0.0.0/8"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "isaac-poc"
        }
      },
      {
        "id": "sg-03e5d3e9fa7f8cdac",
        "name": "infra-dns-collector-20260329120815005500000003",
        "description": "Infra DNS collector: outbound HTTPS + DNS only",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "ManagedBy": "terraform",
          "HM_COST_TAG_GROUP": "infra",
          "TerraformDomain": "hmnd-network/infra-dns",
          "Name": "infra-dns-collector",
          "HM_COST_TAG_SERVICE": "infra-dns",
          "HM_COST_TAG_PROJECT": "infra-dns",
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_USER": "general"
        }
      },
      {
        "id": "sg-04cf4b8ee86aeb9e4",
        "name": "codg-sim-testing",
        "description": "simulation",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 7777,
            "to_port": 7777,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-046209222fca4bca8",
        "name": "hmnd-eks-cluster-efs-access",
        "description": "Security group for EFS access from EKS cluster",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 2049,
            "to_port": 2049,
            "sources": [
              "10.0.0.0/8"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Team": "shared",
          "Region": "eu-west-2",
          "Name": "hmnd-eks-cluster-efs-access",
          "Purpose": "efs-security-group",
          "ManagedBy": "terraform",
          "Environment": "production"
        }
      },
      {
        "id": "sg-0433a559fb96e7360",
        "name": "k8s-default-sepradev-f5f350fd5c",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/sepra-dev5-eks-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-091dc0dd9c0733e12",
        "name": "launch-wizard-19",
        "description": "launch-wizard-19 created 2025-10-01T14:58:16.656Z",
        "vpc_id": "vpc-094933326926cea6e",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-00880577cdc40fd85",
        "name": "k8s-default-ilzirl1g-d41059e259",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/ilzi-rl-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-04211f0b7a3c2e464",
        "name": "k8s-default-ilzitest-e320f95b0d",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/ilzi-test-rl-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-0b046cc98324a06cb",
        "name": "humanoid-ops-alb-sg",
        "description": "Humanoid Ops ALB SG",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0",
              "10.5.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8001,
            "to_port": 8001,
            "sources": [
              "0.0.0.0/0",
              "10.5.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8888,
            "to_port": 8888,
            "sources": [
              "0.0.0.0/0",
              "10.5.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9090,
            "to_port": 9090,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0",
              "10.5.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8081,
            "to_port": 8081,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-020aa7bcc801d5f4a",
        "name": "k8s-default-cfilmeta-c914b30b11",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/cfil-metadata-eks-cpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-0016fb19e706d10fb",
        "name": "k8s-default-dgradev0-9cdfa76634",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/dgra-dev-0gpu-ssh-service"
        }
      },
      {
        "id": "sg-05f607a715ca978ea",
        "name": "k8s-default-joejeffc-ae8f2b9a43",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/joe-jeffcock-dev-eks-1gpu-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0ef01093dde51aaf1",
        "name": "launch-wizard-23",
        "description": "launch-wizard-23 created 2026-01-23T10:43:09.688Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0a924e90dec16e681",
        "name": "eks-cluster-sg-hmnd-eks-cluster-1654538088",
        "description": "EKS created security group applied to ENI that is attached to EKS Control Plane master nodes, as well as any managed workloads.",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 8001,
            "to_port": 8001,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 8888,
            "to_port": 8888,
            "sources": []
          },
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "10.0.0.0/8",
              "172.31.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "eks-cluster-sg-hmnd-eks-cluster-1654538088",
          "kubernetes.io/cluster/hmnd-eks-cluster": "owned",
          "aws:eks:cluster-name": "hmnd-eks-cluster"
        }
      },
      {
        "id": "sg-0b6c19f0f10d4fb4f",
        "name": "launch-wizard-17",
        "description": "launch-wizard-17 created 2025-10-01T14:47:44.815Z",
        "vpc_id": "vpc-094933326926cea6e",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0dd052e012cbe785c",
        "name": "hmnd-ml-fsx-lustre-dev-eu-west-2-20250917140306610800000008",
        "description": "FSx for Lustre access",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 988,
            "to_port": 988,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 1018,
            "to_port": 1023,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Region": "eu-west-2",
          "Environment": "dev",
          "Project": "HMND-ML",
          "ManagedBy": "Terraform",
          "Name": "hmnd-ml-sg-fsx-dev-eu-west-2"
        }
      },
      {
        "id": "sg-04b89e888f467f903",
        "name": "hmndsharedml-backend-sg",
        "description": "Backend SecurityGroup for Shared ALB for EKS ML services",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "192.168.0.0/16",
              "172.16.0.0/12",
              "10.0.0.0/8"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Project": "HMND-ML",
          "Environment": "dev",
          "ManagedBy": "Terraform",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "elbv2.k8s.aws/resource": "backend-sg"
        }
      },
      {
        "id": "sg-01868995589a46897",
        "name": "hmnd-ml-efs-dev-eu-west-2-20251224114922666400000001",
        "description": "EFS access for EKS pods",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 2049,
            "to_port": 2049,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "ManagedBy": "Terraform",
          "Region": "eu-west-2",
          "Project": "HMND-ML",
          "Environment": "dev",
          "Name": "hmnd-ml-sg-efs-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0a9ee5d3332a39bfd",
        "name": "unitree-tunnel-sg",
        "description": "launch-wizard-5 created 2024-11-04T17:04:24.983Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "10.0.0.0/8",
              "172.31.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0d5541d8b0e707af3",
        "name": "hb-linux-arm64-ubuntu-2404-github-actions-runner-sg20250814171731926300000001",
        "description": "Github Actions Runner security group",
        "vpc_id": "vpc-003033d62c0c872bb",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "ghr:ssm_config_path": "/github-action-runners/hb/linux-arm64-ubuntu-2404/runners/config",
          "Name": "hb-linux-arm64-ubuntu-2404-action-runner",
          "ghr:environment": "hb-linux-arm64-ubuntu-2404"
        }
      },
      {
        "id": "sg-055152bf77cac0bd3",
        "name": "k8s-default-olafdev1-21e4aaca38",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9000,
            "to_port": 9000,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9011,
            "to_port": 9011,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9009,
            "to_port": 9009,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9010,
            "to_port": 9010,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/olaf-dev-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-013d0d2acf8d0e419",
        "name": "k8s-default-dalm2tra-828b0bbc4f",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/dalm2-training-8gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0b2118ccfa07e300e",
        "name": "pintel-alb-sg",
        "description": "Security group for Pintel ALB",
        "vpc_id": "vpc-0c5ed9c2ba56a7808",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "176.56.202.0/24",
              "176.56.204.0/24",
              "38.32.107.76/30",
              "64.124.32.124/30",
              "192.222.48.0/24",
              "89.124.38.242/32",
              "89.124.37.245/32"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "176.56.202.0/24",
              "176.56.204.0/24",
              "38.32.107.76/30",
              "64.124.32.124/30",
              "192.222.48.0/24",
              "89.124.38.242/32",
              "89.124.37.245/32"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "pintel-alb-sg"
        }
      },
      {
        "id": "sg-0f3e7612c72438a07",
        "name": "launch-wizard-6",
        "description": "launch-wizard-6 created 2025-03-13T09:35:35.579Z",
        "vpc_id": "vpc-094933326926cea6e",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0c2a7801c154df644",
        "name": "coder-sg",
        "description": "Coder v2-2.12.0-AutogenByAWSMP--1 created 2025-01-21T11:48:11.844Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "coder-sg"
        }
      },
      {
        "id": "sg-0ce0a5ec5792806ee",
        "name": "infra-streams-task-20260223093232170800000001",
        "description": "go2rtc: inbound from ALB on 1984, outbound RTSP/RTSPS to NVRs",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 7441,
            "to_port": 7441,
            "destinations": [
              "10.44.64.0/20",
              "10.44.0.0/20"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 7447,
            "to_port": 7447,
            "destinations": [
              "10.44.64.0/20",
              "10.44.0.0/20"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_SERVICE": "infra-dashboard",
          "HM_COST_TAG_USER": "general",
          "Team": "infra",
          "Name": "infra-streams-task",
          "Region": "eu-west-2",
          "ManagedBy": "terraform",
          "Purpose": "infra-dashboard",
          "Environment": "production",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_PROJECT": "infra-dashboard",
          "HM_COST_TAG_ENV": "prod",
          "TerraformDomain": "hmnd-network/infra-dashboard"
        }
      },
      {
        "id": "sg-00d00dcf8a3e9d635",
        "name": "k8s-default-dgradev1-be191b3975",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 7777,
            "to_port": 7777,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9016,
            "to_port": 9016,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8765,
            "to_port": 8765,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/dgra-dev1-1gpu-ssh-service"
        }
      },
      {
        "id": "sg-000e65c4e1c741e2c",
        "name": "k8s-kubesyst-ingressn-b3d8187f55",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "kube-system/ingress-nginx-controller",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-03de489a0d094fe87",
        "name": "k8s-default-olafdev1-02f57f6e19",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/olaf-dev-1gpu-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-09273d5066a3bc6c8",
        "name": "vpn-inbound-dns-sg",
        "description": "vpn-inbound-dns-sg",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 53,
            "to_port": 53,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 53,
            "to_port": 53,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-04bc829996b25d2a7",
        "name": "authentik-sg",
        "description": "Authentik sg",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-039183fd84ecae7fd",
        "name": "coder-workspace-sg",
        "description": "SG for the coder workspaces",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "coder-workspace-sg"
        }
      },
      {
        "id": "sg-0d37b117a6238550f",
        "name": "k8s-default-ilzidev1-3ac4eb1a2c",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/ilzi-dev-1gpu-ssh-service"
        }
      },
      {
        "id": "sg-0b91283991b2eef2b",
        "name": "k8s-default-ccopdev1-a2605f4a8c",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8888,
            "to_port": 8888,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 6006,
            "to_port": 6006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8000,
            "to_port": 8000,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 7777,
            "to_port": 7777,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9087,
            "to_port": 9087,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9876,
            "to_port": 9876,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/ccop-dev-1gpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0f0a12596eecd6421",
        "name": "k8s-default-jamodeve-1511ffe743",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/jamo-dev-eks-1gpu-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0f075fb48f6dc2a03",
        "name": "launch-wizard-22",
        "description": "launch-wizard-22 created 2025-12-05T16:10:05.931Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0e5a8b04b0f46655f",
        "name": "k8s-default-jamodeve-5bc62bd9d7",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/jamo-dev-eks-cpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-0aca4e3a69a68c5b4",
        "name": "route53-resolver-inbound-20260302142347248000000001",
        "description": "Route53 Resolver Inbound: DNS from VPN-connected deploy sites and lab VPC",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 53,
            "to_port": 53,
            "sources": [
              "172.31.0.0/16",
              "10.44.0.0/16",
              "192.168.80.0/20",
              "10.10.0.0/16"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 53,
            "to_port": 53,
            "sources": [
              "10.44.0.0/16",
              "172.31.0.0/16",
              "192.168.80.0/20",
              "10.10.0.0/16"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "TerraformDomain": "hmnd-network/route53-resolver",
          "Name": "route53-resolver-inbound",
          "HM_COST_TAG_USER": "general",
          "HM_COST_TAG_PROJECT": "route53-resolver",
          "HM_COST_TAG_SERVICE": "route53-resolver",
          "HM_COST_TAG_GROUP": "infra",
          "ManagedBy": "terraform",
          "HM_COST_TAG_ENV": "prod"
        }
      },
      {
        "id": "sg-07434605a3e148af4",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-07b89576ed160f978",
        "ingress": [],
        "egress": [],
        "tags": {
          "Name": "foxglove-poc-vpc-default"
        }
      },
      {
        "id": "sg-0dd57778deccaecf7",
        "name": "launch-wizard-1",
        "description": "launch-wizard-1 created 2024-09-23T16:43:29.425Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "172.31.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 5432,
            "to_port": 5432,
            "sources": [
              "187.20.20.4/32"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 57571,
            "to_port": 57571,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 50555,
            "to_port": 50555,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 53,
            "to_port": 53,
            "sources": [
              "10.0.0.0/8",
              "172.16.0.0/12"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "172.31.0.0/16"
            ]
          },
          {
            "protocol": "icmp",
            "from_port": -1,
            "to_port": -1,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 50555,
            "to_port": 50555,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": [
              "172.16.0.0/12"
            ]
          },
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "172.31.0.0/16",
              "10.0.0.0/8",
              "172.32.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8000,
            "to_port": 8000,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9500,
            "to_port": 9500,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 53,
            "to_port": 53,
            "sources": [
              "0.0.0.0/8"
            ]
          },
          {
            "protocol": "50",
            "from_port": null,
            "to_port": null,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 3000,
            "to_port": 3000,
            "sources": [
              "193.57.139.219/32"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 500,
            "to_port": 500,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 4500,
            "to_port": 4500,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 5380,
            "to_port": 5380,
            "sources": [
              "10.0.0.0/8"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "gateway-2a-sg"
        }
      },
      {
        "id": "sg-076bb6fbd852171bd",
        "name": "k8s-default-sepradev-939d5fc40d",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/sepra-dev6-eks-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-0fa983c5f00668f9d",
        "name": "k8s-default-gwadloco-c3b51a8c0e",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/gwad-locomotion-8gpu-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0b293017d0f742a10",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0c1ac048058f11bf9",
        "name": "cfil-workstation-sg",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "cfil-workstation-sg",
          "Owner": "cfil",
          "Policy": "protected",
          "Type": "workstation"
        }
      },
      {
        "id": "sg-0b3b1b2d9a1c13c9c",
        "name": "ic-observatory-api-alb",
        "description": "Internal ALB for the IC observatory API",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "172.31.0.0/16"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 8000,
            "to_port": 8000,
            "destinations": [
              "172.31.97.0/24",
              "172.31.96.0/24"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_GROUP": "infra",
          "ManagedBy": "terraform",
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_USER": "general",
          "Name": "ic-observatory-api-alb",
          "HM_COST_TAG_PROJECT": "ic-platform",
          "HM_COST_TAG_SERVICE": "ic-platform-api",
          "TerraformDomain": "hmnd-network/ic-platform-api"
        }
      },
      {
        "id": "sg-0f2f258bed2f7e337",
        "name": "k8s-default-jamoinfh-3e20118d01",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9011,
            "to_port": 9011,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9009,
            "to_port": 9009,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9008,
            "to_port": 9008,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9010,
            "to_port": 9010,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/jamo-inf-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0094c415ab978c2f0",
        "name": "k8s-default-ezahdev2-ace75769d2",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/ezah-dev-2gpu-helm-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0a0131cfe3493ee8e",
        "name": "ikot-workstation-sg",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Type": "workstation",
          "Owner": "ikot",
          "Name": "ikot-workstation-sg",
          "Policy": "protected"
        }
      },
      {
        "id": "sg-0a9082da517f0b8a2",
        "name": "dmac-workstation-sg",
        "description": "Managed by Terraform",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "85.240.205.45/32",
              "187.20.20.4/32"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Name": "dmac-workstation-sg",
          "Type": "workstation",
          "Owner": "dmac",
          "Policy": "protected"
        }
      },
      {
        "id": "sg-04794927201e51d67",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-003033d62c0c872bb",
        "ingress": [],
        "egress": [],
        "tags": {
          "Name": "hmnd-runner-default"
        }
      },
      {
        "id": "sg-099e28705e81dddce",
        "name": "k8s-default-ashu2dev-6a3f0ec139",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/ashu2-dev-1gpu-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-037a3332de818a442",
        "name": "ic-observatory-api-task",
        "description": "IC observatory API tasks",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8000,
            "to_port": 8000,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 9000,
            "to_port": 9010,
            "destinations": [
              "10.44.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_GROUP": "infra",
          "ManagedBy": "terraform",
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_USER": "general",
          "HM_COST_TAG_SERVICE": "ic-platform-api",
          "Name": "ic-observatory-api-task",
          "HM_COST_TAG_PROJECT": "ic-platform",
          "TerraformDomain": "hmnd-network/ic-platform-api"
        }
      },
      {
        "id": "sg-081069662e7cd5be0",
        "name": "melts-grafana-task-20260617155020434400000002",
        "description": "melts.ic.hmnd.ai Grafana task",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 3000,
            "to_port": 3000,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Project": "hmnd-network",
          "ManagedBy": "terraform",
          "Module": "melts-grafana"
        }
      },
      {
        "id": "sg-086d3d00fa24cdd38",
        "name": "launch-wizard-3",
        "description": "launch-wizard-3 created 2024-10-09T17:14:02.028Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-02c45aca1d56fbe92",
        "name": "dbe-worker-866715466211721-1738596334886-unmanaged",
        "description": "Unmanaged security group for worker with prefix dbe-worker-866715466211721-1738596334886 in vpc-08154cc6565a961cb",
        "vpc_id": "vpc-08154cc6565a961cb",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-00f786ad4a41dabe8",
        "name": "hmndsharedml-frontend-sg",
        "description": "Frontend SecurityGroup for Shared ALB for EKS ML services",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "192.168.0.0/16",
              "172.16.0.0/12",
              "10.0.0.0/8"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "172.16.0.0/12",
              "192.168.0.0/16",
              "10.0.0.0/8"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "ingress.k8s.aws/stack": "hmnd-shared-ml",
          "ingress.k8s.aws/resource": "ManagedLBSecurityGroup",
          "Environment": "dev",
          "Project": "HMND-ML",
          "ManagedBy": "Terraform",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-00465e41f98b9cf94",
        "name": "vpn-alb-sg",
        "description": "VPN Load Balancer SG",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8000,
            "to_port": 8000,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0d55436d8a9358798",
        "name": "infra-streams-alb-20260222190814536300000003",
        "description": "Camera streams ALB: inbound HTTPS, outbound to go2rtc",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 1984,
            "to_port": 1984,
            "destinations": []
          }
        ],
        "tags": {
          "TerraformDomain": "hmnd-network/infra-dashboard",
          "HM_COST_TAG_SERVICE": "infra-dashboard",
          "HM_COST_TAG_PROJECT": "infra-dashboard",
          "HM_COST_TAG_USER": "general",
          "HM_COST_TAG_ENV": "prod",
          "Region": "eu-west-2",
          "ManagedBy": "terraform",
          "Name": "infra-streams-alb",
          "Purpose": "infra-dashboard",
          "HM_COST_TAG_GROUP": "infra",
          "Team": "infra",
          "Environment": "production"
        }
      },
      {
        "id": "sg-0bf880e000c8e77bc",
        "name": "k8s-default-dmshdev2-356f54dc6f",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/dmsh-dev2-eks-1gpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-026e928fb96ae08ee",
        "name": "k8s-default-ericdeve-62d0cf96f6",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/eric-dev-eks-cpu-hmnd-interactive-base-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0e1ebbb1ca07eb5b6",
        "name": "infra-streams-task-20260223094523724400000001",
        "description": "go2rtc: inbound from ALB on 1984, outbound RTSP/RTSPS to NVRs",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 1984,
            "to_port": 1984,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "tcp",
            "from_port": 7441,
            "to_port": 7441,
            "destinations": [
              "10.44.64.0/20",
              "10.44.0.0/20",
              "10.44.48.0/20"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 7447,
            "to_port": 7447,
            "destinations": [
              "10.44.64.0/20",
              "10.44.0.0/20",
              "10.44.48.0/20"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 53,
            "to_port": 53,
            "destinations": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "HM_COST_TAG_GROUP": "infra",
          "Purpose": "infra-dashboard",
          "Name": "infra-streams-task",
          "Environment": "production",
          "Team": "infra",
          "ManagedBy": "terraform",
          "TerraformDomain": "hmnd-network/infra-dashboard",
          "HM_COST_TAG_SERVICE": "infra-dashboard",
          "HM_COST_TAG_USER": "general",
          "Region": "eu-west-2",
          "HM_COST_TAG_PROJECT": "infra-dashboard",
          "HM_COST_TAG_ENV": "prod"
        }
      },
      {
        "id": "sg-0cb5a54ceb71e8fb4",
        "name": "k8s-default-ismadev1-47af029d4e",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/isma-dev-1gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0fdf0800b8d80750e",
        "name": "launch-wizard-8",
        "description": "launch-wizard-8 created 2025-03-19T16:04:16.881Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-069f1f92e3f1c90df",
        "name": "hb-linux-amd64-ubuntu-2404-github-actions-runner-sg20250814171731929500000002",
        "description": "Github Actions Runner security group",
        "vpc_id": "vpc-003033d62c0c872bb",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "ghr:ssm_config_path": "/github-action-runners/hb/linux-amd64-ubuntu-2404/runners/config",
          "Name": "hb-linux-amd64-ubuntu-2404-action-runner",
          "ghr:environment": "hb-linux-amd64-ubuntu-2404"
        }
      },
      {
        "id": "sg-0679c60cdc571238f",
        "name": "k8s-default-byandev2-cab0821a57",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/byan-dev2-1gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0d6390ab256ff044d",
        "name": "codg-sim",
        "description": "simulation dev for codg",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 7777,
            "to_port": 7777,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-06a4d2cf35471df4b",
        "name": "launch-wizard-18",
        "description": "launch-wizard-18 created 2025-10-01T14:54:56.707Z",
        "vpc_id": "vpc-094933326926cea6e",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0a91bb8e928a0af14",
        "name": "k8s-default-ashudev1-cd6d48f554",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/ashu-dev-1gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0eddab3669ff98718",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-08154cc6565a961cb",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0c39a69c5d0c06fd3",
        "name": "k8s-default-ismadev3-a9f1cd1559",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/isma-dev3-1gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0296a19c1d7230a4a",
        "name": "k8s-default-jamodevc-88d85a37ee",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/jamo-dev-cpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-030a55ed2c3f5c1d0",
        "name": "k8s-default-jamodev2-c534f4dfe0",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/jamo-dev2-1gpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-031e7780d5cfe661b",
        "name": "sky-sg-root-1d07",
        "description": "Auto-created security group for Ray workers",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0854bfc4742e2d7bc",
        "name": "k8s-default-ismadev2-7689f5a815",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/isma-dev-2gpu-ssh-service"
        }
      },
      {
        "id": "sg-09bd1dd3acfe39079",
        "name": "launch-wizard-9",
        "description": "launch-wizard-9 created 2025-03-27T08:36:58.992Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-012ca2b3ca5b420fb",
        "name": "CloudFront-VPCOrigins-Service-SG",
        "description": "CloudFront configured SecurityGroup",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "aws.cloudfront.vpcorigin": "enabled"
        }
      },
      {
        "id": "sg-037967f6c6f739ef8",
        "name": "hmnd-ml-eks-nodes-dev-eu-west-2-20250917140102098500000003",
        "description": "Security group for EKS worker nodes - ML optimized",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 30669,
            "to_port": 30669,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 32688,
            "to_port": 32688,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 32392,
            "to_port": 32392,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "icmp",
            "from_port": 3,
            "to_port": 4,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 31699,
            "to_port": 31699,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 30917,
            "to_port": 30917,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": [
              "172.16.0.0/12",
              "192.168.0.0/16",
              "10.3.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 31791,
            "to_port": 31791,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 7777,
            "to_port": 7777,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 49100,
            "to_port": 49129,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 30578,
            "to_port": 30578,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 32556,
            "to_port": 32556,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 1024,
            "to_port": 65535,
            "sources": [
              "10.3.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 20000,
            "to_port": 20000,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 8443,
            "to_port": 8443,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 31307,
            "to_port": 31307,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 32528,
            "to_port": 32528,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 30854,
            "to_port": 30854,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 1024,
            "to_port": 65535,
            "sources": [
              "10.3.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 32649,
            "to_port": 32649,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": [
              "172.16.0.0/12",
              "10.0.0.0/8",
              "192.168.0.0/16"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 32171,
            "to_port": 32171,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 30448,
            "to_port": 30448,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 47998,
            "to_port": 48027,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 30247,
            "to_port": 30247,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 31308,
            "to_port": 31308,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "udp",
            "from_port": 0,
            "to_port": 65535,
            "sources": []
          },
          {
            "protocol": "tcp",
            "from_port": 31491,
            "to_port": 31491,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 32762,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Project": "HMND-ML",
          "Environment": "dev",
          "Region": "eu-west-2",
          "Purpose": "ml-compute-optimized",
          "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
          "Name": "hmnd-ml-sg-eks-nodes-dev-eu-west-2",
          "ManagedBy": "Terraform"
        }
      },
      {
        "id": "sg-0396c55ff1cd373fd",
        "name": "launch-wizard-5",
        "description": "launch-wizard-5 created 2025-03-10T11:43:33.642Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-05d52080ff5725938",
        "name": "k8s-default-sepradev-0b6572bf5c",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/sepra-dev1-eks-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-04ea773be7a6f7092",
        "name": "default",
        "description": "default VPC security group",
        "vpc_id": "vpc-0cc93b88905c8eb8d",
        "ingress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "sources": []
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-06fda71ae26f9f464",
        "name": "launch-wizard-11",
        "description": "launch-wizard-11 created 2025-05-01T21:03:50.899Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-0ccda0636355c1c3e",
        "name": "k8s-default-bdeldeve-53ea2dbd20",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/stack": "default/bdel-dev-eks-cpu-hmnd-interactive-base-ssh-service",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-0b7f3bf20edd18c9b",
        "name": "k8s-default-dgratrai-93ffc03f6b",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9005,
            "to_port": 9005,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/dgra-training1-8gpu-ssh-service",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup"
        }
      },
      {
        "id": "sg-019fc0a9d1de77302",
        "name": "launch-wizard-7",
        "description": "launch-wizard-7 created 2025-03-13T16:22:12.093Z",
        "vpc_id": "vpc-094933326926cea6e",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "icmp",
            "from_port": -1,
            "to_port": -1,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-06f0ad3c9e46ecbb3",
        "name": "k8s-default-byandev4-2fe48d6e6d",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/byan-dev-4gpu-ssh-service"
        }
      },
      {
        "id": "sg-0dea1110605ed1794",
        "name": "launch-wizard-13",
        "description": "launch-wizard-13 created 2025-05-07T12:59:26.054Z",
        "vpc_id": "vpc-064b86b11d9115a70",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 80,
            "to_port": 80,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 0,
            "to_port": 65535,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {}
      },
      {
        "id": "sg-03f3e9c8d720b11b5",
        "name": "k8s-default-ismadeve-4d85e5fc27",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 9006,
            "to_port": 9006,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 9007,
            "to_port": 9007,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/stack": "default/isma-dev-eks-1gpu-hmnd-interactive-base-ssh-service"
        }
      },
      {
        "id": "sg-04d79fee4328a1f25",
        "name": "hmnd-ml-vpce-dev-eu-west-2-20260129165044331200000001",
        "description": "Security group for VPC interface endpoints",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 443,
            "to_port": 443,
            "sources": [
              "10.3.0.0/16"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "Region": "eu-west-2",
          "Project": "HMND-ML",
          "ManagedBy": "Terraform",
          "Environment": "dev",
          "Name": "hmnd-ml-sg-vpce-dev-eu-west-2"
        }
      },
      {
        "id": "sg-0c5c7257a5a7c0815",
        "name": "k8s-default-atindeve-b9a44ce406",
        "description": "[k8s] Managed SecurityGroup for LoadBalancer",
        "vpc_id": "vpc-033eb69021e3deafb",
        "ingress": [
          {
            "protocol": "tcp",
            "from_port": 8080,
            "to_port": 8080,
            "sources": [
              "0.0.0.0/0"
            ]
          },
          {
            "protocol": "tcp",
            "from_port": 22,
            "to_port": 22,
            "sources": [
              "0.0.0.0/0"
            ]
          }
        ],
        "egress": [
          {
            "protocol": "-1",
            "from_port": null,
            "to_port": null,
            "destinations": [
              "0.0.0.0/0"
            ]
          }
        ],
        "tags": {
          "elbv2.k8s.aws/cluster": "hmnd-ml-dev-eu-west-2",
          "service.k8s.aws/resource": "ManagedLBSecurityGroup",
          "service.k8s.aws/stack": "default/atin-dev-eks-cpu-hmnd-interactive-base-ssh-service"
        }
      }
    ],
    "internet_gateways": [
      {
        "id": "igw-0592b230114c52d7e",
        "name": "",
        "vpc_ids": [
          "vpc-03c6dac4b77bd22a5"
        ]
      },
      {
        "id": "igw-0c80e994737985baf",
        "name": "",
        "vpc_ids": [
          "vpc-00e7b72129f9e7a2c"
        ]
      },
      {
        "id": "igw-01909f255712f7b6c",
        "name": "",
        "vpc_ids": [
          "vpc-00613666bbf826344"
        ]
      },
      {
        "id": "igw-01f06de554db92d13",
        "name": "",
        "vpc_ids": [
          "vpc-05b5920e463e9a82b"
        ]
      },
      {
        "id": "igw-04160209574e51fad",
        "name": "lab-eu-north-1-igw",
        "vpc_ids": [
          "vpc-0f7272f2c99faf857"
        ]
      },
      {
        "id": "igw-0411f11168fe86d3e",
        "name": "packer-vpc-igw",
        "vpc_ids": [
          "vpc-0da7cd54df9b385e4"
        ]
      },
      {
        "id": "igw-0a0343ae1ab902a57",
        "name": "",
        "vpc_ids": [
          "vpc-028c5f171f9b93e38"
        ]
      },
      {
        "id": "igw-0b97b50fde53a2996",
        "name": "lab-us-west-2-igw",
        "vpc_ids": [
          "vpc-0aab0c7ab152bce5b"
        ]
      },
      {
        "id": "igw-05a9e6cda6f7e0ba3",
        "name": "",
        "vpc_ids": [
          "vpc-006b54fa0165dba13"
        ]
      },
      {
        "id": "igw-079f945c93c6b83a2",
        "name": "hmnd-ml-igw-dev-us-west-1",
        "vpc_ids": [
          "vpc-018c61725c49d5d9a"
        ]
      },
      {
        "id": "igw-09b0fd4b02c815590",
        "name": "",
        "vpc_ids": [
          "vpc-0843dca91e5e4b27e"
        ]
      },
      {
        "id": "igw-003c226316c93df3e",
        "name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksVpcIgw",
        "vpc_ids": [
          "vpc-094933326926cea6e"
        ]
      },
      {
        "id": "igw-008ffec316eede56d",
        "name": "default-igw",
        "vpc_ids": [
          "vpc-064b86b11d9115a70"
        ]
      },
      {
        "id": "igw-01327e8ae524448af",
        "name": "hmnd-runner",
        "vpc_ids": [
          "vpc-003033d62c0c872bb"
        ]
      },
      {
        "id": "igw-03c78fe862e42f695",
        "name": "",
        "vpc_ids": [
          "vpc-0cc93b88905c8eb8d"
        ]
      },
      {
        "id": "igw-09cc3aa133a400be3",
        "name": "hmnd-ml-igw-dev-eu-west-2",
        "vpc_ids": [
          "vpc-033eb69021e3deafb"
        ]
      },
      {
        "id": "igw-0a0dba5d36e8da4fd",
        "name": "foxglove-poc-vpc",
        "vpc_ids": [
          "vpc-07b89576ed160f978"
        ]
      },
      {
        "id": "igw-0bef5007a689b424d",
        "name": "eks-vpc-igw",
        "vpc_ids": [
          "vpc-0c402fa39d35e019d"
        ]
      },
      {
        "id": "igw-0ec45c206ecb01dc1",
        "name": "pintel-vpc-igw",
        "vpc_ids": [
          "vpc-0c5ed9c2ba56a7808"
        ]
      },
      {
        "id": "igw-0f2b8ab931e2dca3f",
        "name": "",
        "vpc_ids": [
          "vpc-08154cc6565a961cb"
        ]
      }
    ],
    "vpn_gateways": [],
    "vpc_peerings": [
      {
        "id": "pcx-0f27a140a0105c914",
        "name": "lab-to-it-peer",
        "status": "active",
        "requester_vpc": "vpc-064b86b11d9115a70",
        "accepter_vpc": "vpc-077735b0bd27422e8"
      },
      {
        "id": "pcx-0d549ba0db54def53",
        "name": "marketplace_databricks-to-rds-peering",
        "status": "active",
        "requester_vpc": "vpc-094933326926cea6e",
        "accepter_vpc": "vpc-064b86b11d9115a70"
      },
      {
        "id": "pcx-0486458dc0fb0467e",
        "name": "databricks-to-rds-peering",
        "status": "active",
        "requester_vpc": "vpc-08154cc6565a961cb",
        "accepter_vpc": "vpc-064b86b11d9115a70"
      }
    ],
    "volumes": [
      {
        "id": "vol-02082136e7214b83e",
        "size_gb": 256,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-central-1",
        "attached_instance": "i-07859e779955a7a9e",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0934391ba260c439b",
        "size_gb": 8,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-central-1",
        "attached_instance": "i-041321f96c2df4a01",
        "attached_device": "/dev/xvda",
        "name": ""
      },
      {
        "id": "vol-07ad51ce46086722f",
        "size_gb": 200,
        "state": "in-use",
        "type": "gp3",
        "region": "me-central-1",
        "attached_instance": "i-04fa8793a83150d82",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0432ec5683a0c6480",
        "size_gb": 200,
        "state": "in-use",
        "type": "gp3",
        "region": "me-central-1",
        "attached_instance": "i-0051850e41b26678a",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-093f7c05b2c81c633",
        "size_gb": 200,
        "state": "in-use",
        "type": "gp3",
        "region": "me-central-1",
        "attached_instance": "i-0c0f3ad485a00d603",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0cc3407336adf5d88",
        "size_gb": 60,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-north-1",
        "attached_instance": "i-0d2f02a42192c0b5c",
        "attached_device": "/dev/xvda",
        "name": ""
      },
      {
        "id": "vol-04caee4099c514478",
        "size_gb": 498,
        "state": "in-use",
        "type": "gp3",
        "region": "us-west-2",
        "attached_instance": "i-0f81908e2826c92d4",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-082f09b35f00fd6ef",
        "size_gb": 20,
        "state": "in-use",
        "type": "gp3",
        "region": "us-west-1",
        "attached_instance": "i-064e682e46737b245",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-eks-node-volume-dev-us-west-1"
      },
      {
        "id": "vol-0f35635a4b9470b8a",
        "size_gb": 512,
        "state": "in-use",
        "type": "gp3",
        "region": "us-west-1",
        "attached_instance": "i-0e0af99120980ddcc",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-017c75175f8f3588d",
        "size_gb": 20,
        "state": "in-use",
        "type": "gp3",
        "region": "us-west-1",
        "attached_instance": "i-0b50770b0b655f1c4",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-eks-node-volume-dev-us-west-1"
      },
      {
        "id": "vol-01bcd3e6f8b03a0b4",
        "size_gb": 2000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0bc57babb5c0ff40d",
        "attached_device": "/dev/xvdaa",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-fdc41819-6854-4de8-9de2-257e37008789"
      },
      {
        "id": "vol-07ec38f1c71516836",
        "size_gb": 2000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-049fc159d8ccbfae9",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-p5-mig-node-volume-dev-eu-west-2"
      },
      {
        "id": "vol-0a7fda86f75bd0025",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0860eef0f57df8db5",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-04f83a116a9607f1a",
        "size_gb": 1000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-021416757cf1a71b8",
        "attached_device": "/dev/sda1",
        "name": "mata-workstation-volume"
      },
      {
        "id": "vol-051d75e5b7754b5fc",
        "size_gb": 50,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-05ea1e64acb28430e",
        "attached_device": "/dev/xvda",
        "name": "karpenter-prefect-workload-node"
      },
      {
        "id": "vol-094a0b35a22908751",
        "size_gb": 40,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-02f391b85215101b5",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0ae59d2a9f3fccc50",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0d77022c43e48e37a",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node"
      },
      {
        "id": "vol-054be725331153ab3",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0f80333baafc3126c",
        "attached_device": "/dev/xvdab",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-9d2a4497-d844-4aff-85f3-b9f06a16ed88"
      },
      {
        "id": "vol-0e5f0cbbe2342da87",
        "size_gb": 2000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-064dc61bf24f1138c",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-p5-node-volume-dev-eu-west-2"
      },
      {
        "id": "vol-0e0b24c824f6d96ee",
        "size_gb": 50,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0e5ec3d743d5645f2",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-03bf0f54f890cd931",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-04c4414bfa41c52fa",
        "attached_device": "/dev/xvdad",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-faf70b6d-67cb-49e5-a769-2fcff843591f"
      },
      {
        "id": "vol-06b2d13830c03eded",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-063ea88eab5bcc75a",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node"
      },
      {
        "id": "vol-058fc19a634903d20",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0ae4e22ecab59a30d",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node"
      },
      {
        "id": "vol-0ce73f62000591238",
        "size_gb": 2000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0db434d79b2d845f4",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-p5-node-volume-dev-eu-west-2"
      },
      {
        "id": "vol-0b1e49b9f5ea1a086",
        "size_gb": 600,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0b22ae7e7de06ccda",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node"
      },
      {
        "id": "vol-0fd53b5011a187918",
        "size_gb": 600,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0b9e6b94e2575ff05",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node"
      },
      {
        "id": "vol-0b144058b8796324f",
        "size_gb": 20,
        "state": "in-use",
        "type": "gp2",
        "region": "eu-west-2",
        "attached_instance": "i-0b7f4acb77385b672",
        "attached_device": "/dev/xvda",
        "name": "default-node-group"
      },
      {
        "id": "vol-051b686effc2cd80f",
        "size_gb": 250,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-05f627ad041baf6fb",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0d49331df07a9d5bf",
        "size_gb": 150,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0afc6185c8111c8cc",
        "attached_device": "/dev/xvdb",
        "name": "workerenv-2982982158993688-afae1ccb-3b35-4f1d-afd7-5e90d6a3adfc-worker"
      },
      {
        "id": "vol-0d0039d88e96ac077",
        "size_gb": 250,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-078ee976b6ca00ec2",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0e70893eb79f3c321",
        "size_gb": 500,
        "state": "available",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "",
        "attached_device": "",
        "name": "schaeffler-poc-ssd"
      },
      {
        "id": "vol-0aedce35ceb7e981e",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-097e3890a52be33df",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-015687733c1696a5c",
        "size_gb": 2000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-03d16003896fc29b1",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-p5-node-volume-dev-eu-west-2"
      },
      {
        "id": "vol-0227574fd7e25fe75",
        "size_gb": 100,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-02c86d2f891e7d835",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node"
      },
      {
        "id": "vol-0a8e96a9d1eecc0a5",
        "size_gb": 2000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0f3e5a9d69df3230b",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-p5-node-volume-dev-eu-west-2"
      },
      {
        "id": "vol-00173bddfd29293c1",
        "size_gb": 2000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-06411d2201629f66e",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-p5-node-volume-dev-eu-west-2"
      },
      {
        "id": "vol-0cbf8f4bfa5403ffa",
        "size_gb": 8,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-07f91b7ab8d6b3c88",
        "attached_device": "/dev/xvda",
        "name": ""
      },
      {
        "id": "vol-090a7c0ec6cb1dd2e",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-088dfab62dd348017",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node"
      },
      {
        "id": "vol-014c3134d5231fa7d",
        "size_gb": 2000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-07e921fd37766a475",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-p5-mig-node-volume-dev-eu-west-2"
      },
      {
        "id": "vol-0856cd3b23963b6f7",
        "size_gb": 8,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0541168f0ea1966dd",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0736af754c1db9257",
        "size_gb": 100,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0b9766c5eac5fb78c",
        "attached_device": "/dev/xvdaa",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-8d1d3371-9536-459e-944b-d14dc2f7cd5f"
      },
      {
        "id": "vol-01f8774f8e21bc703",
        "size_gb": 512,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0140351e4d1cbaaf2",
        "attached_device": "/dev/xvdf",
        "name": "hmnd-ml-grafana-traces-dev-eu-west-2"
      },
      {
        "id": "vol-055fb83a6a7d08942",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0f96df12419e4ceba",
        "attached_device": "/dev/sda1",
        "name": "dmac-workstation-volume"
      },
      {
        "id": "vol-0fc42d978beb63b1b",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0b9766c5eac5fb78c",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node"
      },
      {
        "id": "vol-08c56f54983ef1d87",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0e20c3a8659baef80",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-031a9b81b24e6ad04",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-078258bd1917d6a0d",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node"
      },
      {
        "id": "vol-09bd67b7ba0adbc22",
        "size_gb": 8,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0ac76b402587550db",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-064f84658b0e38f05",
        "size_gb": 40,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-055d0db437dc441ec",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-09c77840d9a330995",
        "size_gb": 8,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0d1a929ebdb62aa31",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-02e98cf8beb3f3942",
        "size_gb": 1000,
        "state": "in-use",
        "type": "st1",
        "region": "eu-west-2",
        "attached_instance": "i-02fb1bbb84b197ef5",
        "attached_device": "/dev/xvdbo",
        "name": "short term FTP"
      },
      {
        "id": "vol-0da7d3937320df455",
        "size_gb": 100,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0afc6185c8111c8cc",
        "attached_device": "/dev/xvdc",
        "name": "workerenv-2982982158993688-afae1ccb-3b35-4f1d-afd7-5e90d6a3adfc-worker"
      },
      {
        "id": "vol-0ee8e8fb6c9ec715b",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-02bc8fd9140692c82",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0e9fa7cc3a88a9eca",
        "size_gb": 10098,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-092808f97fea6a003",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0d0449b980955869b",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0ac77ea2e09183905",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-088ebe46cf035e622",
        "size_gb": 600,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-03ebfcfa57174205b",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node"
      },
      {
        "id": "vol-0c61463ecba14d9a1",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0ae4e22ecab59a30d",
        "attached_device": "/dev/xvdaa",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-7395c1b6-6e6f-45ed-8c7f-31da80e58378"
      },
      {
        "id": "vol-062adc2b935204923",
        "size_gb": 20,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-04c4414bfa41c52fa",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-eks-node-volume-dev-eu-west-2"
      },
      {
        "id": "vol-0f57983a697b82f8d",
        "size_gb": 20,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-004d4658ce58d5be3",
        "attached_device": "/dev/xvda",
        "name": ""
      },
      {
        "id": "vol-03da18375c568e0d9",
        "size_gb": 2000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0b71e35c35d688665",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0c06c05880e74b19d",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-035d3b23d85df765e",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node"
      },
      {
        "id": "vol-04f8b6bc832df9520",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0c6da9e215f25d197",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node"
      },
      {
        "id": "vol-0de1e15a2a0fce31e",
        "size_gb": 8,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-04321a612a96a54ac",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0c6789b85c699aa70",
        "size_gb": 100,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0c98612f653aead3e",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node"
      },
      {
        "id": "vol-0403854d7ce9514d2",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-09ea50e7abf9ddd67",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node"
      },
      {
        "id": "vol-093555ad5ee9f47db",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0d7241d53ed95fbe5",
        "attached_device": "/dev/xvdac",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-51fdca62-e0db-4179-9a91-b1161be0b0ac"
      },
      {
        "id": "vol-0d437ac415cc4ad6b",
        "size_gb": 10,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0bc57babb5c0ff40d",
        "attached_device": "/dev/xvdab",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-dd11caf2-363d-420d-ab83-fb7942c5a621"
      },
      {
        "id": "vol-04827632966667215",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-08b6f21284791611d",
        "attached_device": "/dev/xvdaa",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-ac61ff45-63bb-4317-afa5-18d0337d6181"
      },
      {
        "id": "vol-03d4f3be9ff1f17fe",
        "size_gb": 600,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-04f3148c2f0a0554a",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-cpu-only-github-node"
      },
      {
        "id": "vol-01ac8235102be0d5e",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0e4797cc42c9c8da4",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node"
      },
      {
        "id": "vol-063a8d6b06ec44451",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-08b6f21284791611d",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node"
      },
      {
        "id": "vol-0600c913fd4dbeec7",
        "size_gb": 8,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-070e9d2aac1d1704b",
        "attached_device": "/dev/sda1",
        "name": "hb-linux-arm64-ubuntu-2204-action-runner"
      },
      {
        "id": "vol-0475a5a6e67572dc1",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0d7241d53ed95fbe5",
        "attached_device": "/dev/xvdab",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-462dd60a-d199-4457-8a99-0265f1b02212"
      },
      {
        "id": "vol-0c0f864ba4819d924",
        "size_gb": 100,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-01f2d86c8307e483c",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0d4ff256fae94dba4",
        "size_gb": 8,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-037dd778153e59690",
        "attached_device": "/dev/xvda",
        "name": ""
      },
      {
        "id": "vol-04a56ae0c0b6ffac5",
        "size_gb": 5,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0f3e5a9d69df3230b",
        "attached_device": "/dev/xvdaa",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-3860d45f-f909-45eb-b001-5b4c8d2fa6e0"
      },
      {
        "id": "vol-0f9803b7f21165a88",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0942b7a3d66851edb",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node"
      },
      {
        "id": "vol-0a0831fa8710a1e97",
        "size_gb": 100,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-013fa413bb64b7393",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node"
      },
      {
        "id": "vol-0da23c4831c9fb32e",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0f80333baafc3126c",
        "attached_device": "/dev/xvdac",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-5500cd24-dfdf-4967-8f78-04912904453f"
      },
      {
        "id": "vol-0e847c1246832a902",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0e91b1967135afa02",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-05dccffc53b882d38",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-089066d3a739240dc",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-056aa39998191bc8b",
        "size_gb": 64,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-041c5f046dc02e819",
        "attached_device": "/dev/sda1",
        "name": "hb-linux-amd64-ubuntu-2204-action-runner"
      },
      {
        "id": "vol-021a34ac80bb65b24",
        "size_gb": 500,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-098b5e0ef90c866d7",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-00b7d5d10cbd52fc2",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0e88e65b9a03364fc",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0e18b7d2f24acda9f",
        "size_gb": 40,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0d76ac7dffa3b9c8c",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-07623d68d43ea0a41",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-04e46d32f524f6919",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node"
      },
      {
        "id": "vol-051b1378ae3d6aba8",
        "size_gb": 50,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-02fb1bbb84b197ef5",
        "attached_device": "/dev/sda1",
        "name": "gateway-2a-ebs"
      },
      {
        "id": "vol-081d105671d8733d5",
        "size_gb": 64,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-00d0088a7295a4c83",
        "attached_device": "/dev/sda1",
        "name": "hb-linux-amd64-ubuntu-2204-action-runner"
      },
      {
        "id": "vol-006ec2069d5b4b657",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0d7241d53ed95fbe5",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-cpu-only-capacity-node"
      },
      {
        "id": "vol-0d2b4d3ba71ccacb4",
        "size_gb": 8,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0e4e797be4cf80fa2",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0c4b42c42c9c7a623",
        "size_gb": 30,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0140351e4d1cbaaf2",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0033493f68323ba95",
        "size_gb": 250,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0a2a8a74b519c6d26",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0443184fd02ef7ff7",
        "size_gb": 50,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-08ac57710dd02b529",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-005fddf89a944aea2",
        "size_gb": 500,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-06beb2fd0bd784401",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-087d2c920c2c4ef8b",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-08b6f21284791611d",
        "attached_device": "/dev/xvdac",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-b70d4f80-310e-47cf-a597-2635438c4182"
      },
      {
        "id": "vol-09a71c7d8e513e83a",
        "size_gb": 8,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0aa885d4d703044da",
        "attached_device": "/dev/sda1",
        "name": "hb-linux-arm64-ubuntu-2204-action-runner"
      },
      {
        "id": "vol-0ab3460d63fc8afbd",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-08b6f21284791611d",
        "attached_device": "/dev/xvdab",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-52c332a7-d825-4a16-9fdc-cebd9f579355"
      },
      {
        "id": "vol-078fd3cd0ccde9ebf",
        "size_gb": 100,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0f3614107edcc719b",
        "attached_device": "/dev/sda1",
        "name": "isaac-poc"
      },
      {
        "id": "vol-0a0def66b9b6e9b30",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0d7241d53ed95fbe5",
        "attached_device": "/dev/xvdaa",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-d73a0208-7638-4835-88c1-218ee3f13f07"
      },
      {
        "id": "vol-0c39dffb2492b2a5f",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0332a72c4ce7be639",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g6-gpu-node"
      },
      {
        "id": "vol-0100a3b7661e364e3",
        "size_gb": 2,
        "state": "available",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "",
        "attached_device": "",
        "name": "hmnd-eks-cluster-dynamic-pvc-ff1e7137-3a48-4247-b8d3-d6e1b4ac8c08"
      },
      {
        "id": "vol-092b3ac20af71fcf0",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-03bfe8e5a9773ce7e",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-0eda157947222448b",
        "size_gb": 10,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0f80333baafc3126c",
        "attached_device": "/dev/xvdaa",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-5a705d2f-94e2-4127-9715-ee09b71762b4"
      },
      {
        "id": "vol-08d2b852313ddfd5d",
        "size_gb": 50,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0512f93e09b46e2f8",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-00eed366c58edab36",
        "size_gb": 100,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-042083fece0295de3",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node"
      },
      {
        "id": "vol-04b00e53a3e16197f",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0767ed5e9d8bfb664",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-013eba98c6fa46e07",
        "size_gb": 50,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-068dcf84dc6ee7a7d",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-08097d28011c3192d",
        "size_gb": 20,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0bc57babb5c0ff40d",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-eks-node-volume-dev-eu-west-2"
      },
      {
        "id": "vol-02874d87fd21e81dd",
        "size_gb": 100,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-038a7302de06fad97",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-github-arc-arm-node"
      },
      {
        "id": "vol-025ae3bd0ca3e84e9",
        "size_gb": 200,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0c6da9e215f25d197",
        "attached_device": "/dev/xvdaa",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-3e22af4f-0356-4a80-90d1-6a36d0a53eab"
      },
      {
        "id": "vol-0aeb3fc2f6d9b706e",
        "size_gb": 300,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-02ce1247e335f606c",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-dev-eu-west-2-simulation-g7e-2xl-gpu-node"
      },
      {
        "id": "vol-04d829b9ddcdeaf98",
        "size_gb": 30,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0afc6185c8111c8cc",
        "attached_device": "/dev/sda1",
        "name": "workerenv-2982982158993688-afae1ccb-3b35-4f1d-afd7-5e90d6a3adfc-worker"
      },
      {
        "id": "vol-080c9841445c33ee5",
        "size_gb": 20,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-0f80333baafc3126c",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-eks-node-volume-dev-eu-west-2"
      },
      {
        "id": "vol-073c2b52785665db7",
        "size_gb": 1,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-04c4414bfa41c52fa",
        "attached_device": "/dev/xvdac",
        "name": "hmnd-ml-dev-eu-west-2-dynamic-pvc-80f80d36-1724-438e-b3ce-d3bce5019774"
      },
      {
        "id": "vol-0491981db7db807b7",
        "size_gb": 60,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-01c32ebddb96c3f34",
        "attached_device": "/dev/sda1",
        "name": ""
      },
      {
        "id": "vol-02af7dec2c6a23c7d",
        "size_gb": 2000,
        "state": "in-use",
        "type": "gp3",
        "region": "eu-west-2",
        "attached_instance": "i-03ca9483e16daccf4",
        "attached_device": "/dev/xvda",
        "name": "hmnd-ml-p5-node-volume-dev-eu-west-2"
      }
    ],
    "rds_instances": [
      {
        "id": "database-1",
        "engine": "postgres",
        "engine_version": "16.13",
        "class": "db.t4g.xlarge",
        "status": "available",
        "storage_gb": 100,
        "multi_az": false,
        "vpc_id": "vpc-064b86b11d9115a70",
        "region": "eu-west-2"
      },
      {
        "id": "hmnd-console-staging-db",
        "engine": "postgres",
        "engine_version": "16.13",
        "class": "db.t4g.small",
        "status": "available",
        "storage_gb": 20,
        "multi_az": false,
        "vpc_id": "vpc-064b86b11d9115a70",
        "region": "eu-west-2"
      }
    ],
    "eks_clusters": [
      {
        "name": "hmnd-ml-dev-us-west-1",
        "status": "ACTIVE",
        "version": "1.33",
        "region": "us-west-1"
      },
      {
        "name": "foxglove-poc-cluster",
        "status": "ACTIVE",
        "version": "1.30",
        "region": "eu-west-2"
      },
      {
        "name": "hmnd-eks-cluster",
        "status": "ACTIVE",
        "version": "1.33",
        "region": "eu-west-2"
      },
      {
        "name": "hmnd-ml-dev-eu-west-2",
        "status": "ACTIVE",
        "version": "1.33",
        "region": "eu-west-2"
      }
    ],
    "subnets": [
      {
        "id": "subnet-0a1269543b3f5d4f5",
        "vpc_id": "vpc-03c6dac4b77bd22a5",
        "az": "eu-central-1a",
        "cidr": "172.31.16.0/20",
        "name": "",
        "available_ips": 4090,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-02301c046d91d6cf6",
        "vpc_id": "vpc-03c6dac4b77bd22a5",
        "az": "eu-central-1c",
        "cidr": "172.31.0.0/20",
        "name": "",
        "available_ips": 4091,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-0a1729292e87705b7",
        "vpc_id": "vpc-03c6dac4b77bd22a5",
        "az": "eu-central-1b",
        "cidr": "172.31.32.0/20",
        "name": "",
        "available_ips": 4090,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-0badd49fc724f76c6",
        "vpc_id": "vpc-00e7b72129f9e7a2c",
        "az": "me-central-1a",
        "cidr": "172.31.32.0/20",
        "name": "",
        "available_ips": 4088,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-083d922a7800746c2",
        "vpc_id": "vpc-00e7b72129f9e7a2c",
        "az": "me-central-1c",
        "cidr": "172.31.0.0/20",
        "name": "",
        "available_ips": 4091,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-0108bec2ce4a3e413",
        "vpc_id": "vpc-00e7b72129f9e7a2c",
        "az": "me-central-1b",
        "cidr": "172.31.16.0/20",
        "name": "",
        "available_ips": 4091,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-0e2a7585d17835b7f",
        "vpc_id": "vpc-00613666bbf826344",
        "az": "eu-north-1b",
        "cidr": "10.96.1.0/24",
        "name": "humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-subnet-1",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_GROUP": "infra",
          "Name": "humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-subnet-1",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_USER": "dmac"
        }
      },
      {
        "id": "subnet-0bb3305ae8a590421",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "az": "eu-north-1b",
        "cidr": "10.4.144.0/20",
        "name": "lab-eu-north-1-private-subnet-2",
        "available_ips": 4090,
        "map_public_ip": false,
        "tags": {
          "Environment": "production",
          "Project": "network-infrastructure",
          "Tier": "Private",
          "Terraform": "true",
          "Name": "lab-eu-north-1-private-subnet-2"
        }
      },
      {
        "id": "subnet-0749ab2dbf479c7b7",
        "vpc_id": "vpc-05b5920e463e9a82b",
        "az": "eu-north-1c",
        "cidr": "172.31.0.0/20",
        "name": "",
        "available_ips": 4091,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-0c66af127a310a161",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "az": "eu-north-1b",
        "cidr": "10.4.16.0/20",
        "name": "lab-eu-north-1-public-subnet-2",
        "available_ips": 4090,
        "map_public_ip": true,
        "tags": {
          "Terraform": "true",
          "Project": "network-infrastructure",
          "Environment": "production",
          "Tier": "Public",
          "Name": "lab-eu-north-1-public-subnet-2"
        }
      },
      {
        "id": "subnet-0d086f1229b152a53",
        "vpc_id": "vpc-00613666bbf826344",
        "az": "eu-north-1a",
        "cidr": "10.96.0.0/24",
        "name": "humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-subnet-0",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "Name": "humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-subnet-0",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_SERVICE": "prefect"
        }
      },
      {
        "id": "subnet-09344ae80abe2f7f8",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "az": "eu-north-1c",
        "cidr": "10.4.32.0/20",
        "name": "lab-eu-north-1-public-subnet-3",
        "available_ips": 4089,
        "map_public_ip": true,
        "tags": {
          "Project": "network-infrastructure",
          "Environment": "production",
          "Terraform": "true",
          "Name": "lab-eu-north-1-public-subnet-3",
          "Tier": "Public"
        }
      },
      {
        "id": "subnet-0db8041f55ae9d40f",
        "vpc_id": "vpc-05b5920e463e9a82b",
        "az": "eu-north-1a",
        "cidr": "172.31.16.0/20",
        "name": "",
        "available_ips": 4091,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-02f92d8130ec497c1",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "az": "eu-north-1c",
        "cidr": "10.4.160.0/20",
        "name": "lab-eu-north-1-private-subnet-3",
        "available_ips": 4090,
        "map_public_ip": false,
        "tags": {
          "Tier": "Private",
          "Environment": "production",
          "Terraform": "true",
          "Project": "network-infrastructure",
          "Name": "lab-eu-north-1-private-subnet-3"
        }
      },
      {
        "id": "subnet-04b7b1e8d0badf966",
        "vpc_id": "vpc-00613666bbf826344",
        "az": "eu-north-1c",
        "cidr": "10.96.2.0/24",
        "name": "humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-subnet-2",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_PROJECT": "general-development",
          "Name": "humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-subnet-2",
          "HM_COST_TAG_SERVICE": "prefect"
        }
      },
      {
        "id": "subnet-0d2696c73e432a778",
        "vpc_id": "vpc-05b5920e463e9a82b",
        "az": "eu-north-1b",
        "cidr": "172.31.32.0/20",
        "name": "",
        "available_ips": 4091,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-06789308551e0a4b0",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "az": "eu-north-1a",
        "cidr": "10.4.128.0/20",
        "name": "lab-eu-north-1-private-subnet-1",
        "available_ips": 4090,
        "map_public_ip": false,
        "tags": {
          "Project": "network-infrastructure",
          "Environment": "production",
          "Terraform": "true",
          "Name": "lab-eu-north-1-private-subnet-1",
          "Tier": "Private"
        }
      },
      {
        "id": "subnet-07f4b58d1fce3588e",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "az": "eu-north-1a",
        "cidr": "10.4.0.0/20",
        "name": "lab-eu-north-1-public-subnet-1",
        "available_ips": 4090,
        "map_public_ip": true,
        "tags": {
          "Terraform": "true",
          "Project": "network-infrastructure",
          "Tier": "Public",
          "Environment": "production",
          "Name": "lab-eu-north-1-public-subnet-1"
        }
      },
      {
        "id": "subnet-05e877abd62404693",
        "vpc_id": "vpc-028c5f171f9b93e38",
        "az": "us-west-2a",
        "cidr": "10.246.0.0/24",
        "name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-subnet-0",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_ENV": "production",
          "Name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-subnet-0",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_SERVICE": "prefect"
        }
      },
      {
        "id": "subnet-0545a53e2c31f119f",
        "vpc_id": "vpc-028c5f171f9b93e38",
        "az": "us-west-2b",
        "cidr": "10.246.1.0/24",
        "name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-subnet-1",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_SERVICE": "prefect",
          "Name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-subnet-1",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_ENV": "production"
        }
      },
      {
        "id": "subnet-0af74d62382d09be1",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "az": "us-west-2a",
        "cidr": "10.0.128.0/20",
        "name": "lab-us-west-2-subnet-private1-us-west-2a",
        "available_ips": 4087,
        "map_public_ip": false,
        "tags": {
          "Name": "lab-us-west-2-subnet-private1-us-west-2a"
        }
      },
      {
        "id": "subnet-059ac2925c9259837",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "az": "us-west-2b",
        "cidr": "10.0.144.0/20",
        "name": "lab-us-west-2-subnet-private2-us-west-2b",
        "available_ips": 4089,
        "map_public_ip": false,
        "tags": {
          "Name": "lab-us-west-2-subnet-private2-us-west-2b"
        }
      },
      {
        "id": "subnet-0ae1e532b48195510",
        "vpc_id": "vpc-0da7cd54df9b385e4",
        "az": "us-west-2a",
        "cidr": "10.1.0.0/24",
        "name": "vpc-0da7cd54df9b385e4-us-west-2a",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "Name": "vpc-0da7cd54df9b385e4-us-west-2a"
        }
      },
      {
        "id": "subnet-0317c297ae1bea2a3",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "az": "us-west-2a",
        "cidr": "10.0.0.0/20",
        "name": "lab-us-west-2-subnet-public1-us-west-2a",
        "available_ips": 4090,
        "map_public_ip": false,
        "tags": {
          "Name": "lab-us-west-2-subnet-public1-us-west-2a"
        }
      },
      {
        "id": "subnet-05c1536cc696af6ea",
        "vpc_id": "vpc-028c5f171f9b93e38",
        "az": "us-west-2d",
        "cidr": "10.246.3.0/24",
        "name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-subnet-3",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_ENV": "production",
          "Name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-subnet-3",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_USER": "dmac"
        }
      },
      {
        "id": "subnet-0c89282c76c64465c",
        "vpc_id": "vpc-028c5f171f9b93e38",
        "az": "us-west-2c",
        "cidr": "10.246.2.0/24",
        "name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-subnet-2",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_PROJECT": "general-development",
          "Name": "humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-subnet-2",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_USER": "dmac"
        }
      },
      {
        "id": "subnet-0e13946587ef076ae",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "az": "us-west-2b",
        "cidr": "10.0.16.0/20",
        "name": "lab-us-west-2-subnet-public2-us-west-2b",
        "available_ips": 4091,
        "map_public_ip": false,
        "tags": {
          "Name": "lab-us-west-2-subnet-public2-us-west-2b"
        }
      },
      {
        "id": "subnet-06f02c2f719778af6",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "az": "us-west-1a",
        "cidr": "10.1.64.0/20",
        "name": "hmnd-ml-private-dev-us-west-1-a",
        "available_ips": 4039,
        "map_public_ip": false,
        "tags": {
          "Name": "hmnd-ml-private-dev-us-west-1-a",
          "ManagedBy": "Terraform",
          "fsx.lustre/optimized": "true",
          "karpenter.sh/discovery": "hmnd-ml-dev-us-west-1",
          "Tier": "private",
          "Type": "private",
          "Region": "us-west-1",
          "Environment": "dev",
          "Project": "HMND-ML",
          "Purpose": "ml-compute-fsx",
          "kubernetes.io/role/internal-elb": "1",
          "kubernetes.io/cluster/hmnd-ml-dev-us-west-1": "shared"
        }
      },
      {
        "id": "subnet-028efb33ad3d62f9b",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "az": "us-west-1a",
        "cidr": "10.1.0.0/20",
        "name": "hmnd-ml-public-dev-us-west-1-a",
        "available_ips": 4086,
        "map_public_ip": true,
        "tags": {
          "Region": "us-west-1",
          "Tier": "public",
          "Project": "HMND-ML",
          "kubernetes.io/role/elb": "1",
          "Type": "public",
          "Environment": "dev",
          "Name": "hmnd-ml-public-dev-us-west-1-a",
          "ManagedBy": "Terraform",
          "kubernetes.io/cluster/hmnd-ml-dev-us-west-1": "shared"
        }
      },
      {
        "id": "subnet-06162af46f40935b2",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "az": "us-west-1b",
        "cidr": "10.1.80.0/20",
        "name": "hmnd-ml-private-dev-us-west-1-b",
        "available_ips": 4040,
        "map_public_ip": false,
        "tags": {
          "kubernetes.io/role/internal-elb": "1",
          "Type": "private",
          "fsx.lustre/optimized": "true",
          "karpenter.sh/discovery": "hmnd-ml-dev-us-west-1",
          "Tier": "private",
          "kubernetes.io/cluster/hmnd-ml-dev-us-west-1": "shared",
          "ManagedBy": "Terraform",
          "Name": "hmnd-ml-private-dev-us-west-1-b",
          "Purpose": "ml-compute-fsx",
          "Environment": "dev",
          "Project": "HMND-ML",
          "Region": "us-west-1"
        }
      },
      {
        "id": "subnet-064a031d7154a3668",
        "vpc_id": "vpc-006b54fa0165dba13",
        "az": "us-west-1a",
        "cidr": "172.31.0.0/20",
        "name": "",
        "available_ips": 4091,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-0990b6b00d4d8de4c",
        "vpc_id": "vpc-0843dca91e5e4b27e",
        "az": "us-west-1a",
        "cidr": "10.134.0.0/24",
        "name": "humanoid-lab-uce-us-west-1-SPOT_p5-48xlarge-subnet-0",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_GROUP": "infra",
          "Name": "humanoid-lab-uce-us-west-1-SPOT_p5-48xlarge-subnet-0",
          "HM_COST_TAG_USER": "dmac"
        }
      },
      {
        "id": "subnet-0d511fb1c52512d00",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "az": "us-west-1b",
        "cidr": "10.1.16.0/20",
        "name": "hmnd-ml-public-dev-us-west-1-b",
        "available_ips": 4089,
        "map_public_ip": true,
        "tags": {
          "Type": "public",
          "Region": "us-west-1",
          "Tier": "public",
          "Environment": "dev",
          "Project": "HMND-ML",
          "ManagedBy": "Terraform",
          "kubernetes.io/cluster/hmnd-ml-dev-us-west-1": "shared",
          "Name": "hmnd-ml-public-dev-us-west-1-b",
          "kubernetes.io/role/elb": "1"
        }
      },
      {
        "id": "subnet-0275d0dd04474da3b",
        "vpc_id": "vpc-0843dca91e5e4b27e",
        "az": "us-west-1b",
        "cidr": "10.134.1.0/24",
        "name": "humanoid-lab-uce-us-west-1-SPOT_p5-48xlarge-subnet-1",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_ENV": "production",
          "Name": "humanoid-lab-uce-us-west-1-SPOT_p5-48xlarge-subnet-1",
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_GROUP": "infra"
        }
      },
      {
        "id": "subnet-085fbc93e07eccf19",
        "vpc_id": "vpc-006b54fa0165dba13",
        "az": "us-west-1b",
        "cidr": "172.31.16.0/20",
        "name": "",
        "available_ips": 4091,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-0e58728fa58e7443f",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2b",
        "cidr": "172.31.32.0/28",
        "name": "rds-subnet",
        "available_ips": 0,
        "map_public_ip": false,
        "tags": {
          "Name": "rds-subnet"
        }
      },
      {
        "id": "subnet-017574f1c6d199320",
        "vpc_id": "vpc-0cc93b88905c8eb8d",
        "az": "eu-west-2b",
        "cidr": "10.131.1.0/24",
        "name": "humanoid-lab-uce-eu-west-2-SPOT_p5-48xlarge-subnet-1",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_SERVICE": "prefect",
          "Name": "humanoid-lab-uce-eu-west-2-SPOT_p5-48xlarge-subnet-1",
          "HM_COST_TAG_ENV": "production"
        }
      },
      {
        "id": "subnet-0751336b834bc07ef",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2b",
        "cidr": "172.31.97.0/24",
        "name": "ic-observatory-api-b",
        "available_ips": 249,
        "map_public_ip": true,
        "tags": {
          "Name": "ic-observatory-api-b",
          "HM_COST_TAG_PROJECT": "ic-platform",
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_USER": "general",
          "HM_COST_TAG_SERVICE": "ic-platform-api",
          "ManagedBy": "terraform",
          "HM_COST_TAG_GROUP": "infra",
          "TerraformDomain": "hmnd-network/ic-platform-api"
        }
      },
      {
        "id": "subnet-0c723ca157dc91089",
        "vpc_id": "vpc-08154cc6565a961cb",
        "az": "eu-west-2b",
        "cidr": "10.37.192.0/19",
        "name": "",
        "available_ips": 8186,
        "map_public_ip": false,
        "tags": {}
      },
      {
        "id": "subnet-043aebf49d674359b",
        "vpc_id": "vpc-0c5ed9c2ba56a7808",
        "az": "eu-west-2b",
        "cidr": "10.5.2.0/24",
        "name": "pintel-vpc-public-b",
        "available_ips": 249,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_GROUP": "data",
          "HM_COST_TAG_USER": "general",
          "Type": "public",
          "Name": "pintel-vpc-public-b",
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_PROJECT": "pintel-integration",
          "HM_COST_TAG_SERVICE": "pintel-gateway"
        }
      },
      {
        "id": "subnet-05dd478c41aa47262",
        "vpc_id": "vpc-094933326926cea6e",
        "az": "eu-west-2a",
        "cidr": "10.53.0.0/24",
        "name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksNatSubnet",
        "available_ips": 246,
        "map_public_ip": false,
        "tags": {
          "aws:cloudformation:logical-id": "DBSNatSubnet",
          "aws:cloudformation:stack-id": "arn:aws:cloudformation:eu-west-2:767828728064:stack/AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71/2072bcd0-f805-11ef-bda0-0202abced499",
          "Name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksNatSubnet",
          "aws:cloudformation:stack-name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71",
          "Vendor": "Databricks"
        }
      },
      {
        "id": "subnet-05e3b850ac2203676",
        "vpc_id": "vpc-033eb69021e3deafb",
        "az": "eu-west-2a",
        "cidr": "10.3.0.0/20",
        "name": "hmnd-ml-public-dev-eu-west-2-a",
        "available_ips": 4083,
        "map_public_ip": true,
        "tags": {
          "Project": "HMND-ML",
          "Type": "public",
          "kubernetes.io/role/elb": "1",
          "Region": "eu-west-2",
          "Tier": "public",
          "Name": "hmnd-ml-public-dev-eu-west-2-a",
          "Environment": "dev",
          "ManagedBy": "Terraform",
          "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "shared"
        }
      },
      {
        "id": "subnet-0cb8e82f47c42ccbb",
        "vpc_id": "vpc-08154cc6565a961cb",
        "az": "eu-west-2a",
        "cidr": "10.37.0.0/24",
        "name": "nat-gateway-subnet",
        "available_ips": 250,
        "map_public_ip": false,
        "tags": {
          "Name": "nat-gateway-subnet"
        }
      },
      {
        "id": "subnet-0b8b4508a7a5e8d1b",
        "vpc_id": "vpc-033eb69021e3deafb",
        "az": "eu-west-2c",
        "cidr": "10.3.96.0/20",
        "name": "hmnd-ml-private-dev-eu-west-2-c",
        "available_ips": 3946,
        "map_public_ip": false,
        "tags": {
          "ManagedBy": "Terraform",
          "fsx.lustre/optimized": "true",
          "Region": "eu-west-2",
          "Project": "HMND-ML",
          "Purpose": "ml-compute-fsx",
          "Environment": "dev",
          "Tier": "private",
          "Type": "private",
          "kubernetes.io/role/internal-elb": "1",
          "Name": "hmnd-ml-private-dev-eu-west-2-c",
          "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
          "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "shared"
        }
      },
      {
        "id": "subnet-0068f0b99d020a06b",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2b",
        "cidr": "172.31.65.0/24",
        "name": "hmnd-uce-batch-2b",
        "available_ips": 249,
        "map_public_ip": false,
        "tags": {
          "Name": "hmnd-uce-batch-2b"
        }
      },
      {
        "id": "subnet-08fd3e96ecc9e773c",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "az": "eu-west-2c",
        "cidr": "10.253.32.0/20",
        "name": "vpc-0c402fa39d35e019d-eu-west-2c",
        "available_ips": 4085,
        "map_public_ip": true,
        "tags": {
          "Name": "vpc-0c402fa39d35e019d-eu-west-2c",
          "kubernetes.io/cluster/hmnd-eks-cluster": "shared",
          "kubernetes.io/role/internal-elb": "1",
          "kubernetes.io/role/elb": "1"
        }
      },
      {
        "id": "subnet-01bf215e6a24b08eb",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2a",
        "cidr": "172.31.96.0/24",
        "name": "ic-observatory-api-a",
        "available_ips": 250,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_GROUP": "infra",
          "TerraformDomain": "hmnd-network/ic-platform-api",
          "ManagedBy": "terraform",
          "HM_COST_TAG_SERVICE": "ic-platform-api",
          "HM_COST_TAG_PROJECT": "ic-platform",
          "HM_COST_TAG_USER": "general",
          "Name": "ic-observatory-api-a"
        }
      },
      {
        "id": "subnet-04512e3b6941f8ab2",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2a",
        "cidr": "172.31.98.0/24",
        "name": "ic-observatory-api-alb-a",
        "available_ips": 249,
        "map_public_ip": false,
        "tags": {
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_PROJECT": "ic-platform",
          "HM_COST_TAG_SERVICE": "ic-platform-api",
          "HM_COST_TAG_USER": "general",
          "Name": "ic-observatory-api-alb-a",
          "HM_COST_TAG_GROUP": "infra",
          "ManagedBy": "terraform",
          "TerraformDomain": "hmnd-network/ic-platform-api"
        }
      },
      {
        "id": "subnet-04ac92ef08cc1abee",
        "vpc_id": "vpc-07b89576ed160f978",
        "az": "eu-west-2c",
        "cidr": "10.0.3.0/24",
        "name": "foxglove-poc-vpc-private-eu-west-2c",
        "available_ips": 249,
        "map_public_ip": false,
        "tags": {
          "kubernetes.io/cluster/foxglove-poc-cluster": "shared",
          "kubernetes.io/role/internal-elb": "1",
          "Name": "foxglove-poc-vpc-private-eu-west-2c"
        }
      },
      {
        "id": "subnet-056a270c9cb1ab8be",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "az": "eu-west-2a",
        "cidr": "10.253.0.0/20",
        "name": "vpc-0c402fa39d35e019d-eu-west-2a",
        "available_ips": 4084,
        "map_public_ip": true,
        "tags": {
          "kubernetes.io/cluster/hmnd-eks-cluster": "shared",
          "Name": "vpc-0c402fa39d35e019d-eu-west-2a",
          "kubernetes.io/role/elb": "1",
          "kubernetes.io/role/internal-elb": "1"
        }
      },
      {
        "id": "subnet-0b0c20825e67dab41",
        "vpc_id": "vpc-003033d62c0c872bb",
        "az": "eu-west-2c",
        "cidr": "10.31.3.0/24",
        "name": "hmnd-runner-public-eu-west-2c",
        "available_ips": 249,
        "map_public_ip": true,
        "tags": {
          "Name": "hmnd-runner-public-eu-west-2c"
        }
      },
      {
        "id": "subnet-06c6dd49ea348c9fa",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2a",
        "cidr": "172.31.16.0/20",
        "name": "humanoid-internal-2a",
        "available_ips": 4047,
        "map_public_ip": false,
        "tags": {
          "Name": "humanoid-internal-2a"
        }
      },
      {
        "id": "subnet-00bfbc041b7ac4e95",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2b",
        "cidr": "172.31.48.0/28",
        "name": "github-runner",
        "available_ips": 7,
        "map_public_ip": false,
        "tags": {
          "Name": "github-runner"
        }
      },
      {
        "id": "subnet-0379e30a82da9d80f",
        "vpc_id": "vpc-033eb69021e3deafb",
        "az": "eu-west-2a",
        "cidr": "10.3.64.0/20",
        "name": "hmnd-ml-private-dev-eu-west-2-a",
        "available_ips": 3885,
        "map_public_ip": false,
        "tags": {
          "Tier": "private",
          "ManagedBy": "Terraform",
          "fsx.lustre/optimized": "true",
          "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
          "Environment": "dev",
          "Purpose": "ml-compute-fsx",
          "Project": "HMND-ML",
          "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "shared",
          "kubernetes.io/role/internal-elb": "1",
          "Name": "hmnd-ml-private-dev-eu-west-2-a",
          "Region": "eu-west-2",
          "Type": "private"
        }
      },
      {
        "id": "subnet-0e306421c3f6aa130",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2b",
        "cidr": "172.31.99.0/24",
        "name": "ic-observatory-api-alb-b",
        "available_ips": 249,
        "map_public_ip": false,
        "tags": {
          "HM_COST_TAG_ENV": "prod",
          "HM_COST_TAG_USER": "general",
          "ManagedBy": "terraform",
          "HM_COST_TAG_GROUP": "infra",
          "Name": "ic-observatory-api-alb-b",
          "TerraformDomain": "hmnd-network/ic-platform-api",
          "HM_COST_TAG_SERVICE": "ic-platform-api",
          "HM_COST_TAG_PROJECT": "ic-platform"
        }
      },
      {
        "id": "subnet-038e2908634b885f8",
        "vpc_id": "vpc-07b89576ed160f978",
        "az": "eu-west-2a",
        "cidr": "10.0.1.0/24",
        "name": "foxglove-poc-vpc-private-eu-west-2a",
        "available_ips": 234,
        "map_public_ip": false,
        "tags": {
          "Name": "foxglove-poc-vpc-private-eu-west-2a",
          "kubernetes.io/role/internal-elb": "1",
          "kubernetes.io/cluster/foxglove-poc-cluster": "shared"
        }
      },
      {
        "id": "subnet-06659381428aa7720",
        "vpc_id": "vpc-08154cc6565a961cb",
        "az": "eu-west-2a",
        "cidr": "10.37.224.0/19",
        "name": "",
        "available_ips": 8186,
        "map_public_ip": false,
        "tags": {}
      },
      {
        "id": "subnet-0c5eec9d74d268575",
        "vpc_id": "vpc-003033d62c0c872bb",
        "az": "eu-west-2b",
        "cidr": "10.31.2.0/24",
        "name": "hmnd-runner-public-eu-west-2b",
        "available_ips": 249,
        "map_public_ip": true,
        "tags": {
          "Name": "hmnd-runner-public-eu-west-2b"
        }
      },
      {
        "id": "subnet-0eaa697fcd89b5e1e",
        "vpc_id": "vpc-003033d62c0c872bb",
        "az": "eu-west-2a",
        "cidr": "10.31.1.0/24",
        "name": "hmnd-runner-public-eu-west-2a",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "Name": "hmnd-runner-public-eu-west-2a"
        }
      },
      {
        "id": "subnet-00e754e8d43a7de43",
        "vpc_id": "vpc-033eb69021e3deafb",
        "az": "eu-west-2b",
        "cidr": "10.3.80.0/20",
        "name": "hmnd-ml-private-dev-eu-west-2-b",
        "available_ips": 3470,
        "map_public_ip": false,
        "tags": {
          "Tier": "private",
          "Type": "private",
          "fsx.lustre/optimized": "true",
          "Region": "eu-west-2",
          "Environment": "dev",
          "karpenter.sh/discovery": "hmnd-ml-dev-eu-west-2",
          "Name": "hmnd-ml-private-dev-eu-west-2-b",
          "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "shared",
          "Project": "HMND-ML",
          "Purpose": "ml-compute-fsx",
          "kubernetes.io/role/internal-elb": "1",
          "ManagedBy": "Terraform"
        }
      },
      {
        "id": "subnet-004aaae93f1c2bf12",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2a",
        "cidr": "172.31.0.0/20",
        "name": "humanoid-external-2a",
        "available_ips": 4067,
        "map_public_ip": false,
        "tags": {
          "Name": "humanoid-external-2a"
        }
      },
      {
        "id": "subnet-0eddc3ba335418a31",
        "vpc_id": "vpc-094933326926cea6e",
        "az": "eu-west-2a",
        "cidr": "10.53.160.0/19",
        "name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksClusterSubnet1",
        "available_ips": 8187,
        "map_public_ip": false,
        "tags": {
          "Vendor": "Databricks",
          "Name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksClusterSubnet1",
          "aws:cloudformation:logical-id": "DBSClusterSubnet1",
          "aws:cloudformation:stack-name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71",
          "aws:cloudformation:stack-id": "arn:aws:cloudformation:eu-west-2:767828728064:stack/AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71/2072bcd0-f805-11ef-bda0-0202abced499"
        }
      },
      {
        "id": "subnet-0d1bad752714c7c53",
        "vpc_id": "vpc-033eb69021e3deafb",
        "az": "eu-west-2b",
        "cidr": "10.3.16.0/20",
        "name": "hmnd-ml-public-dev-eu-west-2-b",
        "available_ips": 4086,
        "map_public_ip": true,
        "tags": {
          "Tier": "public",
          "Type": "public",
          "Region": "eu-west-2",
          "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "shared",
          "ManagedBy": "Terraform",
          "Name": "hmnd-ml-public-dev-eu-west-2-b",
          "Project": "HMND-ML",
          "kubernetes.io/role/elb": "1",
          "Environment": "dev"
        }
      },
      {
        "id": "subnet-05a52e047704ecf1c",
        "vpc_id": "vpc-0c402fa39d35e019d",
        "az": "eu-west-2b",
        "cidr": "10.253.16.0/20",
        "name": "vpc-0c402fa39d35e019d-eu-west-2b",
        "available_ips": 4086,
        "map_public_ip": true,
        "tags": {
          "kubernetes.io/role/internal-elb": "1",
          "Name": "vpc-0c402fa39d35e019d-eu-west-2b",
          "kubernetes.io/cluster/hmnd-eks-cluster": "shared",
          "kubernetes.io/role/elb": "1"
        }
      },
      {
        "id": "subnet-07305d9f47cbf9994",
        "vpc_id": "vpc-0c5ed9c2ba56a7808",
        "az": "eu-west-2a",
        "cidr": "10.5.1.0/24",
        "name": "pintel-vpc-public-a",
        "available_ips": 249,
        "map_public_ip": true,
        "tags": {
          "Type": "public",
          "HM_COST_TAG_GROUP": "data",
          "HM_COST_TAG_USER": "general",
          "HM_COST_TAG_ENV": "prod",
          "Name": "pintel-vpc-public-a",
          "HM_COST_TAG_SERVICE": "pintel-gateway",
          "HM_COST_TAG_PROJECT": "pintel-integration"
        }
      },
      {
        "id": "subnet-03d8cb4c54b2ef62a",
        "vpc_id": "vpc-08154cc6565a961cb",
        "az": "eu-west-2c",
        "cidr": "10.37.160.0/19",
        "name": "",
        "available_ips": 8186,
        "map_public_ip": false,
        "tags": {}
      },
      {
        "id": "subnet-0751e069031e96b7c",
        "vpc_id": "vpc-07b89576ed160f978",
        "az": "eu-west-2b",
        "cidr": "10.0.102.0/24",
        "name": "foxglove-poc-vpc-public-eu-west-2b",
        "available_ips": 250,
        "map_public_ip": false,
        "tags": {
          "kubernetes.io/role/elb": "1",
          "Name": "foxglove-poc-vpc-public-eu-west-2b",
          "kubernetes.io/cluster/foxglove-poc-cluster": "shared"
        }
      },
      {
        "id": "subnet-084b8d7b32a6b36a2",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2a",
        "cidr": "172.31.49.0/28",
        "name": "",
        "available_ips": 9,
        "map_public_ip": true,
        "tags": {}
      },
      {
        "id": "subnet-0b73bba9dd22c666a",
        "vpc_id": "vpc-07b89576ed160f978",
        "az": "eu-west-2b",
        "cidr": "10.0.2.0/24",
        "name": "foxglove-poc-vpc-private-eu-west-2b",
        "available_ips": 250,
        "map_public_ip": false,
        "tags": {
          "Name": "foxglove-poc-vpc-private-eu-west-2b",
          "kubernetes.io/role/internal-elb": "1",
          "kubernetes.io/cluster/foxglove-poc-cluster": "shared"
        }
      },
      {
        "id": "subnet-0c4332b64cda245cf",
        "vpc_id": "vpc-07b89576ed160f978",
        "az": "eu-west-2c",
        "cidr": "10.0.103.0/24",
        "name": "foxglove-poc-vpc-public-eu-west-2c",
        "available_ips": 250,
        "map_public_ip": false,
        "tags": {
          "Name": "foxglove-poc-vpc-public-eu-west-2c",
          "kubernetes.io/role/elb": "1",
          "kubernetes.io/cluster/foxglove-poc-cluster": "shared"
        }
      },
      {
        "id": "subnet-001b02f4ac035399e",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2a",
        "cidr": "172.31.64.0/24",
        "name": "hmnd-uce-batch-2a",
        "available_ips": 251,
        "map_public_ip": false,
        "tags": {
          "Name": "hmnd-uce-batch-2a"
        }
      },
      {
        "id": "subnet-028a26ab98353ce33",
        "vpc_id": "vpc-094933326926cea6e",
        "az": "eu-west-2b",
        "cidr": "10.53.192.0/19",
        "name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksClusterSubnet2",
        "available_ips": 8183,
        "map_public_ip": false,
        "tags": {
          "aws:cloudformation:stack-name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71",
          "aws:cloudformation:logical-id": "DBSClusterSubnet2",
          "Vendor": "Databricks",
          "aws:cloudformation:stack-id": "arn:aws:cloudformation:eu-west-2:767828728064:stack/AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71/2072bcd0-f805-11ef-bda0-0202abced499",
          "Name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksClusterSubnet2"
        }
      },
      {
        "id": "subnet-0d4bc346d7c22cff6",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2c",
        "cidr": "172.31.80.0/28",
        "name": "schaeffler-poc-subnet",
        "available_ips": 0,
        "map_public_ip": true,
        "tags": {
          "Name": "schaeffler-poc-subnet"
        }
      },
      {
        "id": "subnet-0f73acfdaf352a436",
        "vpc_id": "vpc-0cc93b88905c8eb8d",
        "az": "eu-west-2a",
        "cidr": "10.131.0.0/24",
        "name": "humanoid-lab-uce-eu-west-2-SPOT_p5-48xlarge-subnet-0",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "HM_COST_TAG_ENV": "production",
          "HM_COST_TAG_SERVICE": "prefect",
          "Name": "humanoid-lab-uce-eu-west-2-SPOT_p5-48xlarge-subnet-0",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_PROJECT": "general-development"
        }
      },
      {
        "id": "subnet-09a6118c2044496de",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2c",
        "cidr": "172.31.32.32/28",
        "name": "rds-subnet-3",
        "available_ips": 1,
        "map_public_ip": false,
        "tags": {
          "Name": "rds-subnet-3"
        }
      },
      {
        "id": "subnet-03ad7c51850183978",
        "vpc_id": "vpc-033eb69021e3deafb",
        "az": "eu-west-2c",
        "cidr": "10.3.32.0/20",
        "name": "hmnd-ml-public-dev-eu-west-2-c",
        "available_ips": 4087,
        "map_public_ip": true,
        "tags": {
          "Region": "eu-west-2",
          "Tier": "public",
          "Type": "public",
          "kubernetes.io/cluster/hmnd-ml-dev-eu-west-2": "shared",
          "Name": "hmnd-ml-public-dev-eu-west-2-c",
          "Project": "HMND-ML",
          "Environment": "dev",
          "kubernetes.io/role/elb": "1",
          "ManagedBy": "Terraform"
        }
      },
      {
        "id": "subnet-0c51c31bf9a006642",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2c",
        "cidr": "172.31.66.0/24",
        "name": "hmnd-uce-batch-2c",
        "available_ips": 251,
        "map_public_ip": false,
        "tags": {
          "Name": "hmnd-uce-batch-2c"
        }
      },
      {
        "id": "subnet-05d3c19af68f4c684",
        "vpc_id": "vpc-064b86b11d9115a70",
        "az": "eu-west-2a",
        "cidr": "172.31.32.16/28",
        "name": "red-subnet-2",
        "available_ips": 11,
        "map_public_ip": false,
        "tags": {
          "Name": "red-subnet-2"
        }
      },
      {
        "id": "subnet-0bfd43f20795ec311",
        "vpc_id": "vpc-07b89576ed160f978",
        "az": "eu-west-2a",
        "cidr": "10.0.101.0/24",
        "name": "foxglove-poc-vpc-public-eu-west-2a",
        "available_ips": 249,
        "map_public_ip": false,
        "tags": {
          "Name": "foxglove-poc-vpc-public-eu-west-2a",
          "kubernetes.io/cluster/foxglove-poc-cluster": "shared",
          "kubernetes.io/role/elb": "1"
        }
      },
      {
        "id": "subnet-04d153ded5e820579",
        "vpc_id": "vpc-0cc93b88905c8eb8d",
        "az": "eu-west-2c",
        "cidr": "10.131.2.0/24",
        "name": "humanoid-lab-uce-eu-west-2-SPOT_p5-48xlarge-subnet-2",
        "available_ips": 251,
        "map_public_ip": true,
        "tags": {
          "Name": "humanoid-lab-uce-eu-west-2-SPOT_p5-48xlarge-subnet-2",
          "HM_COST_TAG_SERVICE": "prefect",
          "HM_COST_TAG_USER": "dmac",
          "HM_COST_TAG_PROJECT": "general-development",
          "HM_COST_TAG_GROUP": "infra",
          "HM_COST_TAG_ENV": "production"
        }
      }
    ],
    "nat_gateways": [
      {
        "id": "nat-014774cfd9d93d97e",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "subnet_id": "subnet-09344ae80abe2f7f8",
        "state": "available",
        "name": "lab-eu-north-1-nat-gw-3",
        "public_ip": "51.21.30.58",
        "private_ip": "10.4.43.21"
      },
      {
        "id": "nat-0acaaa1e843411c74",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "subnet_id": "subnet-0c66af127a310a161",
        "state": "available",
        "name": "lab-eu-north-1-nat-gw-2",
        "public_ip": "13.62.33.145",
        "private_ip": "10.4.16.234"
      },
      {
        "id": "nat-0eae4f52f7abdd9fb",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "subnet_id": "subnet-07f4b58d1fce3588e",
        "state": "available",
        "name": "lab-eu-north-1-nat-gw-1",
        "public_ip": "56.228.38.24",
        "private_ip": "10.4.13.97"
      },
      {
        "id": "nat-0c6485ae67556a875",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "subnet_id": "subnet-0317c297ae1bea2a3",
        "state": "available",
        "name": "lab-us-west-2-nat-public1-us-west-2a",
        "public_ip": "54.186.204.107",
        "private_ip": "10.0.10.110"
      },
      {
        "id": "nat-096cb21ff631a477c",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "subnet_id": "subnet-028efb33ad3d62f9b",
        "state": "available",
        "name": "hmnd-ml-nat-dev-us-west-1-1",
        "public_ip": "13.52.37.30",
        "private_ip": "10.1.3.255"
      },
      {
        "id": "nat-0b89584b1ead7e6dd",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "subnet_id": "subnet-0d511fb1c52512d00",
        "state": "available",
        "name": "hmnd-ml-nat-dev-us-west-1-2",
        "public_ip": "52.52.162.103",
        "private_ip": "10.1.23.163"
      },
      {
        "id": "nat-06d3faaa4f8184e87",
        "vpc_id": "vpc-033eb69021e3deafb",
        "subnet_id": "subnet-0d1bad752714c7c53",
        "state": "available",
        "name": "hmnd-ml-nat-dev-eu-west-2-2",
        "public_ip": "13.134.101.234",
        "private_ip": "10.3.29.91"
      },
      {
        "id": "nat-0146540a2ea5f89ae",
        "vpc_id": "vpc-094933326926cea6e",
        "subnet_id": "subnet-05dd478c41aa47262",
        "state": "available",
        "name": "AWSMarketplaceQuicklaunch-DatabricksDeploymentStack-7545690c-88c8-4272-8b47-9f2e9914fb71-DatabricksNat",
        "public_ip": "18.133.0.121",
        "private_ip": "10.53.0.35"
      },
      {
        "id": "nat-0e395df8f49f6c3ad",
        "vpc_id": "vpc-064b86b11d9115a70",
        "subnet_id": "subnet-004aaae93f1c2bf12",
        "state": "available",
        "name": "nat-gw1",
        "public_ip": "18.133.8.142",
        "private_ip": "172.31.14.66"
      },
      {
        "id": "nat-09421b06835e1e09b",
        "vpc_id": "vpc-033eb69021e3deafb",
        "subnet_id": "subnet-05e3b850ac2203676",
        "state": "available",
        "name": "hmnd-ml-nat-dev-eu-west-2-1",
        "public_ip": "18.170.13.31",
        "private_ip": "10.3.2.28"
      },
      {
        "id": "nat-0653a7dd4b57f9800",
        "vpc_id": "vpc-07b89576ed160f978",
        "subnet_id": "subnet-0bfd43f20795ec311",
        "state": "available",
        "name": "foxglove-poc-vpc-eu-west-2a",
        "public_ip": "35.176.194.217",
        "private_ip": "10.0.101.217"
      },
      {
        "id": "nat-0c90fb0ff14d9321f",
        "vpc_id": "vpc-033eb69021e3deafb",
        "subnet_id": "subnet-03ad7c51850183978",
        "state": "available",
        "name": "hmnd-ml-nat-dev-eu-west-2-3",
        "public_ip": "18.171.38.73",
        "private_ip": "10.3.34.254"
      },
      {
        "id": "nat-07a6d7b9e8c6cf8a5",
        "vpc_id": "vpc-08154cc6565a961cb",
        "subnet_id": "subnet-0cb8e82f47c42ccbb",
        "state": "available",
        "name": "",
        "public_ip": "35.177.177.208",
        "private_ip": "10.37.0.143"
      }
    ],
    "ecs_clusters": [
      {
        "name": "AWSBatch-humanoid-lab-uce-eu-north-1-SPOT_p5-48xlarge-20250627144252093200000005-c671414b-5dd5-397c-9403-dc998b615c2f",
        "status": "ACTIVE",
        "running_tasks": 0,
        "pending_tasks": 0,
        "services_count": 0,
        "services": [],
        "region": "eu-north-1"
      },
      {
        "name": "AWSBatch-humanoid-lab-uce-us-west-2-SPOT_p5-48xlarge-20250613161551026000000001-c9ed977b-784a-3271-b64c-8a8c45df3a1e",
        "status": "ACTIVE",
        "running_tasks": 0,
        "pending_tasks": 0,
        "services_count": 0,
        "services": [],
        "region": "us-west-2"
      },
      {
        "name": "AWSBatch-humanoid-lab-uce-us-west-1-SPOT_p5-48xlarge-20250627145214730000000005-f635dfd8-af47-3901-bcbb-7c63ec9b24cc",
        "status": "ACTIVE",
        "running_tasks": 0,
        "pending_tasks": 0,
        "services_count": 0,
        "services": [],
        "region": "us-west-1"
      }
    ],
    "transit_gateways": [
      {
        "id": "tgw-0d6a83989677686d4",
        "name": "lab-eu-north-1-tgw",
        "state": "available",
        "asn": 64512,
        "attachments": [
          {
            "id": "tgw-attach-062672b3de17af1d9",
            "resource_type": "peering",
            "resource_id": "tgw-03f14d3b25e9f11f1",
            "state": "available"
          },
          {
            "id": "tgw-attach-029a5856c9e4a71f9",
            "resource_type": "vpc",
            "resource_id": "vpc-0f7272f2c99faf857",
            "state": "available"
          }
        ],
        "region": "eu-north-1"
      },
      {
        "id": "tgw-06f3af59e949a571a",
        "name": "lab-usw2-tgw",
        "state": "available",
        "asn": 64512,
        "attachments": [
          {
            "id": "tgw-attach-07c0f27181ef45cd6",
            "resource_type": "peering",
            "resource_id": "tgw-03f14d3b25e9f11f1",
            "state": "available"
          },
          {
            "id": "tgw-attach-041139f7a12648ebd",
            "resource_type": "vpc",
            "resource_id": "vpc-0aab0c7ab152bce5b",
            "state": "available"
          }
        ],
        "region": "us-west-2"
      },
      {
        "id": "tgw-06c6628f172c18f96",
        "name": "lab-usw1-tgw",
        "state": "available",
        "asn": 64512,
        "attachments": [
          {
            "id": "tgw-attach-009da8b4fb287aaaf",
            "resource_type": "peering",
            "resource_id": "tgw-03f14d3b25e9f11f1",
            "state": "available"
          },
          {
            "id": "tgw-attach-013a9c18cded6b1c1",
            "resource_type": "vpc",
            "resource_id": "vpc-018c61725c49d5d9a",
            "state": "available"
          }
        ],
        "region": "us-west-1"
      },
      {
        "id": "tgw-03f14d3b25e9f11f1",
        "name": "lab-euw2-tgw",
        "state": "available",
        "asn": 64512,
        "attachments": [
          {
            "id": "tgw-attach-053c764292df1570f",
            "resource_type": "vpc",
            "resource_id": "vpc-07737cc4573dc8d47",
            "state": "available"
          },
          {
            "id": "tgw-attach-009da8b4fb287aaaf",
            "resource_type": "peering",
            "resource_id": "tgw-06c6628f172c18f96",
            "state": "available"
          },
          {
            "id": "tgw-attach-048abb79dcb639b2a",
            "resource_type": "peering",
            "resource_id": "tgw-0196c97d08ba8a907",
            "state": "available"
          },
          {
            "id": "tgw-attach-062672b3de17af1d9",
            "resource_type": "peering",
            "resource_id": "tgw-0d6a83989677686d4",
            "state": "available"
          },
          {
            "id": "tgw-attach-07c0f27181ef45cd6",
            "resource_type": "peering",
            "resource_id": "tgw-06f3af59e949a571a",
            "state": "available"
          },
          {
            "id": "tgw-attach-097a85b986b5e3e7a",
            "resource_type": "peering",
            "resource_id": "tgw-09d2a7fcda51ff6e6",
            "state": "available"
          },
          {
            "id": "tgw-attach-004ca381f8ee9c538",
            "resource_type": "vpc",
            "resource_id": "vpc-0c5ed9c2ba56a7808",
            "state": "available"
          },
          {
            "id": "tgw-attach-043f2d1297655075b",
            "resource_type": "vpc",
            "resource_id": "vpc-08154cc6565a961cb",
            "state": "available"
          },
          {
            "id": "tgw-attach-086c62fbb60f2e031",
            "resource_type": "vpc",
            "resource_id": "vpc-094933326926cea6e",
            "state": "available"
          },
          {
            "id": "tgw-attach-0a97212abf190199b",
            "resource_type": "vpc",
            "resource_id": "vpc-064b86b11d9115a70",
            "state": "available"
          },
          {
            "id": "tgw-attach-0b22a734b55f466c6",
            "resource_type": "vpc",
            "resource_id": "vpc-0c402fa39d35e019d",
            "state": "available"
          },
          {
            "id": "tgw-attach-0d243b34b8e05be5d",
            "resource_type": "vpc",
            "resource_id": "vpc-033eb69021e3deafb",
            "state": "available"
          },
          {
            "id": "tgw-attach-0187ecd3a1251e38f",
            "resource_type": "vpn",
            "resource_id": "vpn-080f11d3f6d93f6d0",
            "state": "available"
          },
          {
            "id": "tgw-attach-04a8b7fa37209c178",
            "resource_type": "vpn",
            "resource_id": "vpn-0f498db82ad01297a",
            "state": "available"
          },
          {
            "id": "tgw-attach-057bb2d2f87f51405",
            "resource_type": "vpn",
            "resource_id": "vpn-0b560c80f7fbb07b4",
            "state": "available"
          },
          {
            "id": "tgw-attach-08fac8b75fe42ef86",
            "resource_type": "vpn",
            "resource_id": "vpn-097ef35f60bcc20b3",
            "state": "available"
          },
          {
            "id": "tgw-attach-0aebbc1396031336f",
            "resource_type": "vpn",
            "resource_id": "vpn-0c38907df54e45b39",
            "state": "available"
          },
          {
            "id": "tgw-attach-0b43338f2f3be2262",
            "resource_type": "vpn",
            "resource_id": "vpn-06833d537cb4c12d6",
            "state": "available"
          },
          {
            "id": "tgw-attach-0c5c41fe48673a065",
            "resource_type": "vpn",
            "resource_id": "vpn-010916b66c021c4fc",
            "state": "available"
          },
          {
            "id": "tgw-attach-0c65e423453fc0e84",
            "resource_type": "vpn",
            "resource_id": "vpn-09bd242ec6188b5c7",
            "state": "available"
          },
          {
            "id": "tgw-attach-0d164751173dfb3cf",
            "resource_type": "vpn",
            "resource_id": "vpn-039644c712d9923f4",
            "state": "available"
          },
          {
            "id": "tgw-attach-0e96131b9925b2584",
            "resource_type": "vpn",
            "resource_id": "vpn-01f8ffe1863ea0c84",
            "state": "available"
          },
          {
            "id": "tgw-attach-03f5358d8c27f69d3",
            "resource_type": "direct-connect-gateway",
            "resource_id": "7d827b32-5fcc-4eaa-a57c-2e6a3e809607",
            "state": "available"
          }
        ],
        "region": "eu-west-2"
      }
    ],
    "vpc_endpoints": [
      {
        "id": "vpce-04828a36f70ab9764",
        "vpc_id": "vpc-0f7272f2c99faf857",
        "service": "s3",
        "type": "Gateway",
        "state": "available",
        "name": "lab-eu-north-1-s3-endpoint"
      },
      {
        "id": "vpce-00fc8d7ab0990caf0",
        "vpc_id": "vpc-0aab0c7ab152bce5b",
        "service": "s3",
        "type": "Gateway",
        "state": "available",
        "name": "lab-us-west-2-vpce-s3"
      },
      {
        "id": "vpce-0afa66dffc5357b60",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "service": "ec2messages",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ec2messages-dev-us-west-1"
      },
      {
        "id": "vpce-0fc72f1ad6c7060b9",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "service": "ec2",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ec2-dev-us-west-1"
      },
      {
        "id": "vpce-0bdb8a878a1481bea",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "service": "ssm",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ssm-dev-us-west-1"
      },
      {
        "id": "vpce-0164bbc1841d5c11c",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "service": "logs",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-logs-dev-us-west-1"
      },
      {
        "id": "vpce-0afff8277b3ef191c",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "service": "sts",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-sts-dev-us-west-1"
      },
      {
        "id": "vpce-0193d973df1487271",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "service": "api",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ecr-api-dev-us-west-1"
      },
      {
        "id": "vpce-0d87daf10f57416f2",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "service": "ssmmessages",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ssmmessages-dev-us-west-1"
      },
      {
        "id": "vpce-00c2729b8e767c417",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "service": "dkr",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ecr-dkr-dev-us-west-1"
      },
      {
        "id": "vpce-0ad67f9d7889db950",
        "vpc_id": "vpc-018c61725c49d5d9a",
        "service": "s3",
        "type": "Gateway",
        "state": "available",
        "name": "hmnd-ml-vpce-s3-dev-us-west-1"
      },
      {
        "id": "vpce-09ddec37b1778f251",
        "vpc_id": "vpc-08154cc6565a961cb",
        "service": "s3",
        "type": "Gateway",
        "state": "available",
        "name": ""
      },
      {
        "id": "vpce-0ce215e0b9356a2aa",
        "vpc_id": "vpc-094933326926cea6e",
        "service": "s3",
        "type": "Gateway",
        "state": "available",
        "name": ""
      },
      {
        "id": "vpce-045cc6df004c3734b",
        "vpc_id": "vpc-064b86b11d9115a70",
        "service": "secretsmanager",
        "type": "Interface",
        "state": "available",
        "name": "aws-secrets-manager"
      },
      {
        "id": "vpce-0f0e6244429ee7dea",
        "vpc_id": "vpc-064b86b11d9115a70",
        "service": "api",
        "type": "Interface",
        "state": "available",
        "name": "aws-ecr-api-endpoint"
      },
      {
        "id": "vpce-076f20097d9803650",
        "vpc_id": "vpc-064b86b11d9115a70",
        "service": "dkr",
        "type": "Interface",
        "state": "available",
        "name": "aws-ecr-dkr-endpoint"
      },
      {
        "id": "vpce-07806b525c0cde314",
        "vpc_id": "vpc-064b86b11d9115a70",
        "service": "s3",
        "type": "Gateway",
        "state": "available",
        "name": "aws-s3-gateway-endpoint"
      },
      {
        "id": "vpce-0f1b29269d07089fc",
        "vpc_id": "vpc-064b86b11d9115a70",
        "service": "logs",
        "type": "Interface",
        "state": "available",
        "name": "aws-cloudwatch-logs-endpoint"
      },
      {
        "id": "vpce-0801540f232dc27ab",
        "vpc_id": "vpc-033eb69021e3deafb",
        "service": "logs",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-logs-dev-eu-west-2"
      },
      {
        "id": "vpce-017a9499bb5a14a51",
        "vpc_id": "vpc-033eb69021e3deafb",
        "service": "ec2",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ec2-dev-eu-west-2"
      },
      {
        "id": "vpce-01b4d4d047289a07c",
        "vpc_id": "vpc-033eb69021e3deafb",
        "service": "ec2messages",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ec2messages-dev-eu-west-2"
      },
      {
        "id": "vpce-072195d148e263797",
        "vpc_id": "vpc-033eb69021e3deafb",
        "service": "sts",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-sts-dev-eu-west-2"
      },
      {
        "id": "vpce-01c5ed158dc0c5b7e",
        "vpc_id": "vpc-033eb69021e3deafb",
        "service": "ssm",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ssm-dev-eu-west-2"
      },
      {
        "id": "vpce-077d4880af5a19b4c",
        "vpc_id": "vpc-033eb69021e3deafb",
        "service": "dkr",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ecr-dkr-dev-eu-west-2"
      },
      {
        "id": "vpce-0a8776b9ba8531a42",
        "vpc_id": "vpc-033eb69021e3deafb",
        "service": "ssmmessages",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ssmmessages-dev-eu-west-2"
      },
      {
        "id": "vpce-09e91608731315949",
        "vpc_id": "vpc-033eb69021e3deafb",
        "service": "api",
        "type": "Interface",
        "state": "available",
        "name": "hmnd-ml-vpce-ecr-api-dev-eu-west-2"
      },
      {
        "id": "vpce-0df49730ca97cbb6e",
        "vpc_id": "vpc-033eb69021e3deafb",
        "service": "s3",
        "type": "Gateway",
        "state": "available",
        "name": "hmnd-ml-vpce-s3-dev-eu-west-2"
      }
    ],
    "s3": {
      "bucket": "hm-rainbow-mount",
      "totalBucketCount": 186,
      "totalSizeBytes": 588605909213872,
      "totalObjects": 1726494250,
      "buckets": [
        {
          "name": "aws-sam-cli-managed-default-samclisourcebucket-pgfk1mxl62fb",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "cognition-cloud-dev",
          "sizeBytes": 786260208,
          "objectCount": 1380
        },
        {
          "name": "cdk-hnb659fds-assets-767828728064-eu-west-2",
          "sizeBytes": 216213,
          "objectCount": 4
        },
        {
          "name": "databricks-import-export",
          "sizeBytes": 1049747647,
          "objectCount": 16
        },
        {
          "name": "cognition-cloud-prod",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "aws-sam-cli-managed-default-samclisourcebucket-4b333cm4gtpc",
          "sizeBytes": 85742,
          "objectCount": 29
        },
        {
          "name": "beta-morphology-analysis",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "databricks-humanoid-cloud-storage-bucket",
          "sizeBytes": 5303200995649,
          "objectCount": 2592913
        },
        {
          "name": "databricks-s3-ingest-from-hmrecor-lambdazipsbucket-nnio9cqqhaqy",
          "sizeBytes": 1233460,
          "objectCount": 1
        },
        {
          "name": "databricks-s3-ingest-hm-lerobot-d-lambdazipsbucket-daykns38uyce",
          "sizeBytes": 1233460,
          "objectCount": 1
        },
        {
          "name": "dego-registry",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "databricks-workspace-stack-lab-quick-start2-bucket",
          "sizeBytes": 143609315729,
          "objectCount": 23429
        },
        {
          "name": "databricks-workspace-stack-lab-quick-start-bucket",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "do-not-delete-ssm-diagnosis-767828728064-us-east-2-9r38w",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "dev-terraform-statefile-767828728064",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "deployment-test-upload-1",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "databricks-workspace-stack-lab-qu-lambdazipsbucket-pj32mm5ybbrh",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "databricks-workspace-stack-lab-qu-lambdazipsbucket-xuzvg0do013k",
          "sizeBytes": 933747,
          "objectCount": 1
        },
        {
          "name": "diogo-personal-bucket",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "deployment-test-upload-2",
          "sizeBytes": 119388309002,
          "objectCount": 8830
        },
        {
          "name": "hb-linux-x64-dist-jnso2px3lhn90h2mvfp7ca8a",
          "sizeBytes": 226036076,
          "objectCount": 2
        },
        {
          "name": "flowlogs-mdukov",
          "sizeBytes": 853298816195,
          "objectCount": 632757
        },
        {
          "name": "euly-molmo2-vla-libero-hlgauss-gallery",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "foxglove-poc-inbox-bucket",
          "sizeBytes": 1872789975201,
          "objectCount": 4819
        },
        {
          "name": "github-arc-cache",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "foxglove-poc-lake-bucket",
          "sizeBytes": 85765581984334,
          "objectCount": 8175097
        },
        {
          "name": "gitlfsawsstack-bucket83908e77-cnahawbgchvf",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hi-cody-site",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hb-linux-arm64-dist-jnso2px3lhn90h2mvfp7ca8a",
          "sizeBytes": 138824243,
          "objectCount": 2
        },
        {
          "name": "hm-aloha-data",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hm-athena-query-results-767828728064",
          "sizeBytes": 46418,
          "objectCount": 110
        },
        {
          "name": "hm-data-rescue-us",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hm-lerobot-dataset",
          "sizeBytes": 34017474641,
          "objectCount": 4397
        },
        {
          "name": "hm-ops-tfstate",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hm-metastore",
          "sizeBytes": 1580,
          "objectCount": 11
        },
        {
          "name": "hm-mlops-scripts",
          "sizeBytes": 4020280278,
          "objectCount": 565
        },
        {
          "name": "hm-hdf5-episodes",
          "sizeBytes": 257394034209,
          "objectCount": 399
        },
        {
          "name": "hm-mock-output",
          "sizeBytes": 42,
          "objectCount": 1
        },
        {
          "name": "hm-ml-datasets",
          "sizeBytes": 973581000,
          "objectCount": 2443
        },
        {
          "name": "hm-rainbow-mount",
          "sizeBytes": 132199160381107,
          "objectCount": 2823044
        },
        {
          "name": "hm-sagemaker-artifacts",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hm-vla-us",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hm-uce-data",
          "sizeBytes": 102126278,
          "objectCount": 5
        },
        {
          "name": "hm-record-pkg",
          "sizeBytes": 556769126664,
          "objectCount": 3068
        },
        {
          "name": "hm-sync-bags",
          "sizeBytes": 356798677715,
          "objectCount": 1248
        },
        {
          "name": "hm-vla",
          "sizeBytes": 4855981246941,
          "objectCount": 117756
        },
        {
          "name": "hm-uce-data-2",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hm-xdof-src",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-anyscale-backend",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-actuator-id-vancouver",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-auth-test-site",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-cloud-skypilot-jobs2",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-artifacts",
          "sizeBytes": 72772893657,
          "objectCount": 1854
        },
        {
          "name": "hmnd-athena-query-results",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-backup-euw2-pintel-nfs",
          "sizeBytes": 5199112697432,
          "objectCount": 8171254
        },
        {
          "name": "hmnd-chunked-env-report",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-ca-crl",
          "sizeBytes": 112,
          "objectCount": 1
        },
        {
          "name": "hmnd-bottle-rl-criticft-report",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-composed-training-configs",
          "sizeBytes": 26829266578,
          "objectCount": 59
        },
        {
          "name": "hmnd-console-db-dumps",
          "sizeBytes": 1851779146,
          "objectCount": 8
        },
        {
          "name": "hmnd-engineering-allocation-map",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-data-bosch-poc",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-dataset-hub",
          "sizeBytes": 83813464943572,
          "objectCount": 60815434
        },
        {
          "name": "hmnd-ext-platform-logs",
          "sizeBytes": 908456,
          "objectCount": 378
        },
        {
          "name": "hmnd-dataset-report",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-external-data-samples",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-design-assets",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-ext-platform",
          "sizeBytes": 22999683,
          "objectCount": 55
        },
        {
          "name": "hmnd-fluid-data",
          "sizeBytes": 25644455558,
          "objectCount": 292
        },
        {
          "name": "hmnd-dvc-data",
          "sizeBytes": 8315835120,
          "objectCount": 766
        },
        {
          "name": "hmnd-gha-actions-cache",
          "sizeBytes": 410208363216,
          "objectCount": 99
        },
        {
          "name": "hmnd-grafana-loki-logs",
          "sizeBytes": 717678054928,
          "objectCount": 4080049
        },
        {
          "name": "hmnd-hex-prefix-vs-pi05-report",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-ic-platform",
          "sizeBytes": 89925446,
          "objectCount": 443
        },
        {
          "name": "hmnd-inference-artifacts",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-infra-dashboard",
          "sizeBytes": 12293758269,
          "objectCount": 8771
        },
        {
          "name": "hmnd-ic-platform-logs",
          "sizeBytes": 2644477,
          "objectCount": 1623
        },
        {
          "name": "hmnd-internal-apps-logs",
          "sizeBytes": 90606502982,
          "objectCount": 960244
        },
        {
          "name": "hmnd-internal-apps",
          "sizeBytes": 28635316343,
          "objectCount": 50950
        },
        {
          "name": "hmnd-infra-dns",
          "sizeBytes": 6449693,
          "objectCount": 115
        },
        {
          "name": "hmnd-internal-apps-state",
          "sizeBytes": 8720428771,
          "objectCount": 25667
        },
        {
          "name": "hmnd-internal-infra-logs",
          "sizeBytes": 510444798,
          "objectCount": 129631
        },
        {
          "name": "hmnd-ml-shared-bucket",
          "sizeBytes": 1805445833068,
          "objectCount": 92223
        },
        {
          "name": "hmnd-ml-prefect-artifacts",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-ml-fsx-lustre-dev-eu-west-2",
          "sizeBytes": 1102496878281,
          "objectCount": 1620728635
        },
        {
          "name": "hmnd-ml-terraform-state-dev-us-west-1",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-ml-terraform-state-dev-eu-west-2",
          "sizeBytes": 1830381084,
          "objectCount": 2654
        },
        {
          "name": "hmnd-ml-terraform-state-dev-us-east-2",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-ml-terraform-state-prod-eu-west-2",
          "sizeBytes": 1201596,
          "objectCount": 1236
        },
        {
          "name": "hmnd-ml-wandb-dev-eu-west-2-file-storage-wanted-akita",
          "sizeBytes": 1617576523351,
          "objectCount": 8525802
        },
        {
          "name": "hmnd-mlops-scripts-dev-us-east-2",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-partner-staging",
          "sizeBytes": 28731378,
          "objectCount": 115
        },
        {
          "name": "hmnd-playground",
          "sizeBytes": 632972742113,
          "objectCount": 361674
        },
        {
          "name": "hmnd-prefect-logs",
          "sizeBytes": 22189775616,
          "objectCount": 29002
        },
        {
          "name": "hmnd-releases",
          "sizeBytes": 12231389204048,
          "objectCount": 2217
        },
        {
          "name": "hmnd-partner-ingest",
          "sizeBytes": 202039251530813,
          "objectCount": 3951862
        },
        {
          "name": "hmnd-pretraining-report-2026",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-prefect-cache-eu-west-2",
          "sizeBytes": 392211775,
          "objectCount": 16972
        },
        {
          "name": "hmnd-ring-picking-report-olaf",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-ringpicking-jl4nkqzm",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-rl-environment-reports",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-rl-blogpost-video-assets-20260626-olsi",
          "sizeBytes": 320510904,
          "objectCount": 18
        },
        {
          "name": "hmnd-rl-evk68wjr-drift",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-sim-ci-metrics-eu-west-2",
          "sizeBytes": 574976,
          "objectCount": 329
        },
        {
          "name": "hmnd-rl-walkthroughs-cb50",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-sentientx-exchange",
          "sizeBytes": 11012041209832,
          "objectCount": 107852
        },
        {
          "name": "hmnd-rl-sim-report",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-rl-rollouts",
          "sizeBytes": 5126712221490,
          "objectCount": 129408
        },
        {
          "name": "hmnd-skill-rl-make-dc-activity-report",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-sim-validation-eu-west-2",
          "sizeBytes": 1108504189,
          "objectCount": 299
        },
        {
          "name": "hmnd-spike-report-olsi-agibot-spike-high-lr-2f1f8",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-spike-report-olsi-agibot-spike-high-lr",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-spike-report-olsi-agibot-spike-high-lr-26aef",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-spike-report-olsi-agibot-spike-high-lr-ebcb1",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-test-222",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-spike-report-olsi-agibot-spike-v6",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-spike-samples-viewer",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-throughput-test-eu-central-1",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-terraform-state-prod",
          "sizeBytes": 4521658887,
          "objectCount": 3695
        },
        {
          "name": "hmnd-throughput-test-ca-central-1",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-throughput-test-us-west-1",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-throughput-test-us-east-1",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-throughput-test-eu-west-2",
          "sizeBytes": 209715379,
          "objectCount": 4
        },
        {
          "name": "hmnd-throughput-test-us-west-2",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-tmp-metrics-remove-me",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-training-eu-west-2",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-training-us-west-2",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-vla-evals-eu-west-2",
          "sizeBytes": 1469268917,
          "objectCount": 2902
        },
        {
          "name": "hmnd-vlm-proxy-archive",
          "sizeBytes": 3397057,
          "objectCount": 122
        },
        {
          "name": "hmnd-vpc-flow-logs-eu-west-2",
          "sizeBytes": 1058588197548,
          "objectCount": 161482
        },
        {
          "name": "hmnd-wandb",
          "sizeBytes": 37794899032,
          "objectCount": 151
        },
        {
          "name": "hmnd-xdof-shared-files",
          "sizeBytes": 67073473627,
          "objectCount": 6
        },
        {
          "name": "humanoid-dev-pipeline-trigger",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "hmnd-wbc-evaluation-reports",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "humanoid-outliers-shortest-report",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "manipulation-models",
          "sizeBytes": 15155149102870,
          "objectCount": 55030
        },
        {
          "name": "manipulation-datasets",
          "sizeBytes": 1469519438761,
          "objectCount": 1173921
        },
        {
          "name": "lerobot-dataset-test",
          "sizeBytes": 167050642443,
          "objectCount": 21677
        },
        {
          "name": "locomotion-research-results-20250731",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "manipulation-huggingface-cache",
          "sizeBytes": 6983280507173,
          "objectCount": 477696
        },
        {
          "name": "mata-sagemaker",
          "sizeBytes": 140782203,
          "objectCount": 191
        },
        {
          "name": "manipulation-training-mixtures",
          "sizeBytes": 1324760713002,
          "objectCount": 6041
        },
        {
          "name": "manipulation-whatever",
          "sizeBytes": 1124072007083,
          "objectCount": 1243972
        },
        {
          "name": "manipulation-policy-evaluation-videos",
          "sizeBytes": 308437084,
          "objectCount": 93
        },
        {
          "name": "mdukov",
          "sizeBytes": 32147124242,
          "objectCount": 14
        },
        {
          "name": "morphology-results",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "prefect-s3-cache",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "processed-ros-bags",
          "sizeBytes": 132609,
          "objectCount": 128
        },
        {
          "name": "mytest-test-22",
          "sizeBytes": 536870916296,
          "objectCount": 17
        },
        {
          "name": "rae-xdof-grid9-report",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "rby2",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "ros-bags",
          "sizeBytes": 16473059796,
          "objectCount": 22777
        },
        {
          "name": "results-locomotion",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "sagemaker-studio-34syht56qaw",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "sagemaker-eu-west-2-767828728064",
          "sizeBytes": 29114606,
          "objectCount": 172
        },
        {
          "name": "sagemaker-us-east-1-767828728064",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "sagemaker-studio-l4o1fvtelz",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "sagemaker-studio-767828728064-54opw3o1gs3",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "sagemaker-studio-767828728064-76szms9lj97",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "sagemaker-us-east-2-767828728064",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "sfed-source",
          "sizeBytes": 697398937663,
          "objectCount": 41780
        },
        {
          "name": "sfed-target",
          "sizeBytes": 390178389518,
          "objectCount": 20988
        },
        {
          "name": "schaeffler-plan-sweep-master-1c7f",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-1kqwctzm",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-28g6uffc",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-5eumd31e",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-2wnztxjy",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-48c7snnw",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-4ptbm5ge",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-5fhhv56l",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-6elz6m0w",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-8fd4g1d7",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-alwqi95s",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-73k69ru3",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-a7mf2gsl",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-jrsf6vww",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-elmwnpvv",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-ntb-d70e41a2-ezi6y945",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-root-d70e41a2-8nvyuv4y",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-root-d70e41a2-eehozx7e",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "thehumanoid-sagemaker",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "skypilot-filemounts-root-d70e41a2-evyu30qz",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "terraform-state-foxglove-poc",
          "sizeBytes": 187728,
          "objectCount": 1
        },
        {
          "name": "xdof-multicam-frames-gallery",
          "sizeBytes": 0,
          "objectCount": 0
        },
        {
          "name": "whole-body-dataset",
          "sizeBytes": 1203044961368,
          "objectCount": 670740
        },
        {
          "name": "terraform-statefile-767828728064",
          "sizeBytes": 7502450,
          "objectCount": 331
        }
      ],
      "robots": [
        {
          "name": "alpha-1-sim",
          "recordingDirs": 4
        },
        {
          "name": "alpha-2",
          "recordingDirs": 33
        },
        {
          "name": "alpha-3",
          "recordingDirs": 98
        },
        {
          "name": "alpha1",
          "recordingDirs": 86
        },
        {
          "name": "alpha10",
          "recordingDirs": 2697
        },
        {
          "name": "alpha11",
          "recordingDirs": 2550
        },
        {
          "name": "alpha12",
          "recordingDirs": 1361
        },
        {
          "name": "alpha2",
          "recordingDirs": 1972
        },
        {
          "name": "alpha3",
          "recordingDirs": 3154
        },
        {
          "name": "alpha4",
          "recordingDirs": 5331
        },
        {
          "name": "alpha5",
          "recordingDirs": 2864
        },
        {
          "name": "alpha6",
          "recordingDirs": 3787
        },
        {
          "name": "alpha7",
          "recordingDirs": 2298
        },
        {
          "name": "alpha8",
          "recordingDirs": 1444
        },
        {
          "name": "alpha9",
          "recordingDirs": 2784
        },
        {
          "name": "alphabiped01-orin",
          "recordingDirs": 31
        },
        {
          "name": "alphabiped03-orin",
          "recordingDirs": 257
        },
        {
          "name": "dmac-ec2",
          "recordingDirs": 3
        },
        {
          "name": "localhost.localdomain",
          "recordingDirs": 1969
        },
        {
          "name": "models",
          "recordingDirs": 1
        },
        {
          "name": "quest0",
          "recordingDirs": 4
        },
        {
          "name": "quest1",
          "recordingDirs": 266
        },
        {
          "name": "quest10",
          "recordingDirs": 2
        },
        {
          "name": "quest100",
          "recordingDirs": 1
        },
        {
          "name": "quest2",
          "recordingDirs": 84
        },
        {
          "name": "quest3",
          "recordingDirs": 2
        },
        {
          "name": "quest4",
          "recordingDirs": 2
        },
        {
          "name": "quest6",
          "recordingDirs": 19
        },
        {
          "name": "quest6785",
          "recordingDirs": 1
        },
        {
          "name": "quest7",
          "recordingDirs": 20
        },
        {
          "name": "rby1",
          "recordingDirs": 584
        },
        {
          "name": "rby2",
          "recordingDirs": 543
        },
        {
          "name": "rby3",
          "recordingDirs": 126
        },
        {
          "name": "rby4",
          "recordingDirs": 513
        },
        {
          "name": "rby5",
          "recordingDirs": 213
        },
        {
          "name": "rby6",
          "recordingDirs": 189
        },
        {
          "name": "rby7",
          "recordingDirs": 115
        },
        {
          "name": "simtest",
          "recordingDirs": 1
        },
        {
          "name": "test1",
          "recordingDirs": 1
        },
        {
          "name": "test_playable",
          "recordingDirs": 0
        },
        {
          "name": "umi-0001",
          "recordingDirs": 777
        },
        {
          "name": "umi-0002",
          "recordingDirs": 187
        },
        {
          "name": "umi-0003",
          "recordingDirs": 3
        },
        {
          "name": "umi-1",
          "recordingDirs": 1
        }
      ],
      "bosch": {
        "bucket": "hmnd-data-bosch-poc",
        "totalSizeBytes": 0,
        "totalObjects": 0,
        "robots": []
      }
    },
    "collected_at": "2026-07-25T08:01:34.173800+00:00"
  },
  "onepassword": {
    "updated": "2026-07-25T08:25:46Z",
    "credentials": {
      "WA1": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA2": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA3": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA4": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA5": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA6": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA7": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA8": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA9": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA10": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA11": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "WA12": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "AB1": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "AB2": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ],
      "AB3": [
        {
          "title": "Alpha SSID",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=4ghytcpe25pyqfbuqqqss34dpq&h=humanoid.1password.eu",
          "category": "WIRELESS_ROUTER",
          "tags": [],
          "vaultName": "Engineering"
        },
        {
          "title": "Alpha Robots ",
          "deepLink": "onepassword://open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "webLink": "https://start.1password.com/open/i?a=TRMYRMKA7BBLPOLQGG537EOY3A&v=6x4j27m3nnldt2s6fnv5jqrqcm&i=beey5lpckwt53os6dxaeepzlyq&h=humanoid.1password.eu",
          "category": "LOGIN",
          "tags": [],
          "vaultName": "Engineering"
        }
      ]
    }
  },
  "github": {
    "updated": "2026-07-25T08:25:47Z",
    "org": "HumanoidTeam",
    "public_repos": 0,
    "private_repos": 0,
    "total_repos": 0,
    "members": 0,
    "open_prs": 0,
    "open_issues": 0,
    "recent_repos": [],
    "recent_runs": [],
    "pipelines": {},
    "key_repos": []
  },
  "jira": {
    "updated": "2026-07-25T08:25:47.589316",
    "incidents": {
      "WA5": [
        {
          "key": "RIM-991",
          "summary": "WA5 - Fell unattended: battery drained to relayboard cutoff while on charger (plugged, not charging); brakes could not hold leaned bendy-leg. Both grippers broken.",
          "status": "Investigated",
          "status_category": "indeterminate",
          "priority": "Blocker",
          "assignee": "Giulio Cerruti",
          "created": "2026-07-22",
          "labels": [
            "hardware"
          ],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-991"
        },
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-851",
          "summary": "EtherCAT Communication Failure on Right Gripper Affecting WA09 and WA05",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Andrey Basov",
          "created": "2026-06-10",
          "labels": [],
          "subsystem": "End Effectors",
          "url": "https://sklvc.atlassian.net/browse/RIM-851"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA9": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-851",
          "summary": "EtherCAT Communication Failure on Right Gripper Affecting WA09 and WA05",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Andrey Basov",
          "created": "2026-06-10",
          "labels": [],
          "subsystem": "End Effectors",
          "url": "https://sklvc.atlassian.net/browse/RIM-851"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA4": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA1": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA7": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-912",
          "summary": "[alpha7] hardware \u2014 Error in motor on the base. able to fix but not a good look for a demo bot",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "David Ward",
          "created": "2026-07-09",
          "labels": [
            "alpha7",
            "hardware",
            "operator-issue-report"
          ],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-912"
        },
        {
          "key": "RIM-902",
          "summary": "WA7 Base Joint Overvoltage",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "David Ward",
          "created": "2026-07-01",
          "labels": [],
          "subsystem": "Actuators",
          "url": "https://sklvc.atlassian.net/browse/RIM-902"
        },
        {
          "key": "RIM-899",
          "summary": "[alpha7] Stopping base during workflow reset needed",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Owen Ahmet-Hayward",
          "created": "2026-06-30",
          "labels": [
            "alpha7",
            "hardware",
            "operator-issue-report"
          ],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-899"
        },
        {
          "key": "RIM-987",
          "summary": "Replace or repair broken charger for Alpha07 robot",
          "status": "Known Issue",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Samuel Corder",
          "created": "2026-07-22",
          "labels": [
            "deployment"
          ],
          "subsystem": "Charging Station",
          "url": "https://sklvc.atlassian.net/browse/RIM-987"
        },
        {
          "key": "RIM-915",
          "summary": "[alpha7] hardware \u2014 Neck yaw drives hard-over into endstop on workflow start (uncommanded); actuator melted [recurrence of RIM-913]",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Anubhav Dogra",
          "created": "2026-07-10",
          "labels": [
            "alpha7",
            "hardware",
            "neck",
            "operator-issue-report",
            "reverb-workflow",
            "symphony2"
          ],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-915"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA8": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA3": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-856",
          "summary": "AW3: Neck pitch/yaw STO (0xF005) latching \u2014 fault silently ignored, degrading policy performance (RCA needed; suspected PDB / STO inline resistor)",
          "status": "Monitor for Recurrence",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "David Ward",
          "created": "2026-06-11",
          "labels": [],
          "subsystem": "Head & Neck",
          "url": "https://sklvc.atlassian.net/browse/RIM-856"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-841",
          "summary": "Wa3- Vibrations in the torso yaw.",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Anubhav Dogra",
          "created": "2026-06-05",
          "labels": [],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-841"
        },
        {
          "key": "RIM-842",
          "summary": "WA3- Knee and torso pitch went in error causing a Fall. ",
          "status": "Monitor for Recurrence",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Andy Park",
          "created": "2026-06-05",
          "labels": [],
          "subsystem": "Actuators",
          "url": "https://sklvc.atlassian.net/browse/RIM-842"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA2": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA10": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-983",
          "summary": "WA10 - No brake release (suspected blown fuse); can only teleop out of crate, LiDAR range very short",
          "status": "Known Issue",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Owen Ahmet-Hayward",
          "created": "2026-07-17",
          "labels": [],
          "subsystem": "Wheelbase",
          "url": "https://sklvc.atlassian.net/browse/RIM-983"
        },
        {
          "key": "RIM-917",
          "summary": "[alpha10] controls_motion \u2014 Robot executes reset joint configuration too slow with hmnd-bringup-ros.service...",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Anubhav Dogra",
          "created": "2026-07-13",
          "labels": [
            "alpha10",
            "controls_motion",
            "operator-issue-report"
          ],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-917"
        },
        {
          "key": "RIM-913",
          "summary": "[alpha10] hardware \u2014 Reverb Workflow causes neck actuator to hard over into endstop, without commandi...",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Anubhav Dogra",
          "created": "2026-07-09",
          "labels": [
            "alpha10",
            "hardware",
            "operator-issue-report"
          ],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-913"
        },
        {
          "key": "RIM-903",
          "summary": "[alpha10] controls_motion \u2014 STO neck actuators error",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Owen Ahmet-Hayward",
          "created": "2026-07-01",
          "labels": [
            "alpha10",
            "controls_motion",
            "operator-issue-report"
          ],
          "subsystem": "Actuators",
          "url": "https://sklvc.atlassian.net/browse/RIM-903"
        },
        {
          "key": "RIM-884",
          "summary": "[alpha10] data_collection_tooling \u2014 Arms are not reacting on teleop commands from joysticks. At the same time, gripp...",
          "status": "Monitor for Recurrence",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Rodrigo Neves Zenha",
          "created": "2026-06-26",
          "labels": [
            "alpha10",
            "data_collection_tooling",
            "operator-issue-report"
          ],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-884"
        },
        {
          "key": "RIM-918",
          "summary": "[alpha10] other \u2014 Reverb scenario faulted due to localization score.",
          "status": "Investigated",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Federico Proni",
          "created": "2026-07-13",
          "labels": [
            "alpha10",
            "operator-issue-report",
            "other"
          ],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-918"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA6": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-1005",
          "summary": "[WA06] hardware \u2014 head camera crashed",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": null,
          "created": "2026-07-24",
          "labels": [
            "alpha6",
            "hardware",
            "operator-issue-report"
          ],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-1005"
        },
        {
          "key": "RIM-1004",
          "summary": "[WA06] hardware \u2014 Left wrist camera is broken causing policy to fail with insufficient observation",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": null,
          "created": "2026-07-24",
          "labels": [
            "alpha6",
            "hardware",
            "operator-issue-report"
          ],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-1004"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-1001",
          "summary": "[WA06] hardware \u2014 Joints faulting into STO (0xF005) during Symphony2.5 runs, WBC aborts",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "David Ward",
          "created": "2026-07-24",
          "labels": [
            "alphaclaw"
          ],
          "subsystem": "Actuators",
          "url": "https://sklvc.atlassian.net/browse/RIM-1001"
        },
        {
          "key": "RIM-910",
          "summary": "[alpha6] latency \u2014 Something really weird is going on with `vi-output` processes. Camera images are...",
          "status": "Known Issue",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Samuel Perry",
          "created": "2026-07-09",
          "labels": [
            "alpha6",
            "latency",
            "operator-issue-report"
          ],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-910"
        },
        {
          "key": "RIM-871",
          "summary": "HRI failing results in SW stack on Orin failing to launch",
          "status": "Monitor for Recurrence",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Yuriy Strezhik",
          "created": "2026-06-22",
          "labels": [],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-871"
        },
        {
          "key": "RIM-869",
          "summary": "WA6 losing arm in ethercat chain on numerous occasions",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "David Ward",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-869"
        },
        {
          "key": "RIM-706",
          "summary": "Ethernet from torso/RTPC not working - WA6",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "David Ward",
          "created": "2026-04-01",
          "labels": [],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-706"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA11": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-778",
          "summary": "WA11 - Orin spkr (speaker cable) Broken. Needs to be replaced. ",
          "status": "To Do",
          "status_category": "new",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-04-27",
          "labels": [],
          "subsystem": "Power System",
          "url": "https://sklvc.atlassian.net/browse/RIM-778"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-683",
          "summary": "Alpha 11 Leaned and fell when picking a tote.",
          "status": "Investigated",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Andy Park",
          "created": "2026-03-20",
          "labels": [
            "beta_design_consideration"
          ],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-683"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "WA12": [
        {
          "key": "RIM-865",
          "summary": "[Workpack] - Fit elbow cable retaining bracket",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Low",
          "assignee": "Scott Sheridan",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-865"
        },
        {
          "key": "RIM-1003",
          "summary": "[THOR7] infra \u2014 Thor-7 needs repeated reboots; WiFi doesn't auto-reconnect after reboot, killing inference ports 9001/9002",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-07-24",
          "labels": [],
          "subsystem": "Auxiliary",
          "url": "https://sklvc.atlassian.net/browse/RIM-1003"
        },
        {
          "key": "RIM-998",
          "summary": "Repair or replace faulty ethernet port on WA12",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Samuel Corder",
          "created": "2026-07-23",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-998"
        },
        {
          "key": "RIM-67",
          "summary": "Wheeled Alpha arm STO errors due to ESD",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "High",
          "assignee": "Matthew Wong ",
          "created": "2025-10-16",
          "labels": [
            "Deployment",
            "awaiting_status",
            "beta_design_consideration"
          ],
          "subsystem": "Torso Arms",
          "url": "https://sklvc.atlassian.net/browse/RIM-67"
        }
      ],
      "AB3": [
        {
          "key": "RIM-970",
          "summary": "Biped MCAP recorded on AB3 13-07-26 afternoon did not have `/wbc/robot_commands` topic",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Bao Tran",
          "created": "2026-07-17",
          "labels": [],
          "subsystem": "Software",
          "url": "https://sklvc.atlassian.net/browse/RIM-970"
        },
        {
          "key": "RIM-663",
          "summary": "Biped3 left_hip, and right_hip and left_ankle actuators fault",
          "status": "Known Issue",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "David Ward",
          "created": "2026-03-17",
          "labels": [],
          "subsystem": "Actuators",
          "url": "https://sklvc.atlassian.net/browse/RIM-663"
        }
      ],
      "AB4": [
        {
          "key": "RIM-883",
          "summary": "BA4 stumbling during locomotion in demo acceptance testing",
          "status": "Triage",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "David Ward",
          "created": "2026-06-26",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-883"
        },
        {
          "key": "RIM-807",
          "summary": "BA4 biped power failure and sparking in PDB",
          "status": "Blocked",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "David Ward",
          "created": "2026-05-13",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-807"
        }
      ],
      "AB2": [
        {
          "key": "RIM-867",
          "summary": "Investigate and resolve IMU boot failure on biped02",
          "status": "RCA",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Maheswar Madhukumar Sarala",
          "created": "2026-06-19",
          "labels": [],
          "subsystem": null,
          "url": "https://sklvc.atlassian.net/browse/RIM-867"
        },
        {
          "key": "RIM-162",
          "summary": "Foot PCB 24V reg failure",
          "status": "Known Issue",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Owen Ahmet-Hayward",
          "created": "2025-12-02",
          "labels": [
            "form",
            "form-304"
          ],
          "subsystem": "Legs",
          "url": "https://sklvc.atlassian.net/browse/RIM-162"
        }
      ],
      "AB1": [
        {
          "key": "RIM-162",
          "summary": "Foot PCB 24V reg failure",
          "status": "Known Issue",
          "status_category": "indeterminate",
          "priority": "Medium",
          "assignee": "Owen Ahmet-Hayward",
          "created": "2025-12-02",
          "labels": [
            "form",
            "form-304"
          ],
          "subsystem": "Legs",
          "url": "https://sklvc.atlassian.net/browse/RIM-162"
        }
      ]
    },
    "rim_total": 35,
    "reservations": {
      "WA11": [
        {
          "key": "RRA-99",
          "summary": "WA11 Data Collection",
          "type": "allocation",
          "status": "In Progress",
          "activity": "Data collection",
          "assignee": "Arash Momeni",
          "team": "Operations - AI Data Collection",
          "start": "2026-03-16T08:00:00.000+0000",
          "end": "2026-03-27T23:30:00.000+0000",
          "parent_key": null,
          "url": "https://sklvc.atlassian.net/browse/RRA-99"
        }
      ],
      "WA9": [
        {
          "key": "RRA-97",
          "summary": "WA9- Controls team",
          "type": "allocation",
          "status": "In Progress",
          "activity": "Engineering",
          "assignee": "Giulio Cerruti",
          "team": "Engineering - Autonomy - Controls",
          "start": "2026-03-16T08:00:00.000+0000",
          "end": "2026-03-27T23:30:00.000+0000",
          "parent_key": null,
          "url": "https://sklvc.atlassian.net/browse/RRA-97"
        }
      ],
      "WA7": [
        {
          "key": "RRA-96",
          "summary": "WA7 Demo ",
          "type": "allocation",
          "status": "In Progress",
          "activity": "Customer demo",
          "assignee": "Chris Windle",
          "team": "Product - Deployment",
          "start": "2026-03-16T00:00:00.000+0000",
          "end": "2026-04-03T23:30:00.000+0000",
          "parent_key": null,
          "url": "https://sklvc.atlassian.net/browse/RRA-96"
        }
      ],
      "WA4": [
        {
          "key": "RRA-95",
          "summary": "WA4 Data Collection",
          "type": "allocation",
          "status": "In Progress",
          "activity": "Data collection",
          "assignee": "Arash Momeni",
          "team": "Operations - AI Data Collection",
          "start": "2026-03-16T08:00:00.000+0000",
          "end": "2026-03-20T23:30:00.000+0000",
          "parent_key": null,
          "url": "https://sklvc.atlassian.net/browse/RRA-95"
        }
      ],
      "WA3": [
        {
          "key": "RRA-94",
          "summary": "WA3",
          "type": "allocation",
          "status": "In Progress",
          "activity": "PoC demo",
          "assignee": "Chris Windle",
          "team": "Product - Deployment",
          "start": "2026-03-16T08:00:00.000+0000",
          "end": "2026-03-23T09:00:00.000+0000",
          "parent_key": null,
          "url": "https://sklvc.atlassian.net/browse/RRA-94"
        }
      ],
      "WA2": [
        {
          "key": "RRA-93",
          "summary": "WA2",
          "type": "allocation",
          "status": "In Progress",
          "activity": "PoC demo",
          "assignee": "Chris Windle",
          "team": "Product - Deployment",
          "start": "2026-03-17T08:00:00.000+0000",
          "end": "2026-03-24T09:00:00.000+0000",
          "parent_key": null,
          "url": "https://sklvc.atlassian.net/browse/RRA-93"
        }
      ],
      "WA6": [
        {
          "key": "RRA-83",
          "summary": "WA6 GTC",
          "type": "allocation",
          "status": "In Progress",
          "activity": "Off-site (expo/demo)",
          "assignee": "Chris Windle",
          "team": "Product - Deployment",
          "start": "2026-03-03T00:00:00.000+0000",
          "end": "2026-03-31T00:00:00.000+0000",
          "parent_key": null,
          "url": "https://sklvc.atlassian.net/browse/RRA-83"
        }
      ],
      "WA8": [
        {
          "key": "RRA-80",
          "summary": "WA8",
          "type": "allocation",
          "status": "In Progress",
          "activity": "Off-site (expo/demo)",
          "assignee": "Chris Windle",
          "team": "Product - Deployment",
          "start": "2026-03-03T00:00:00.000+0000",
          "end": "2026-03-31T00:00:00.000+0000",
          "parent_key": null,
          "url": "https://sklvc.atlassian.net/browse/RRA-80"
        }
      ],
      "BA3": [
        {
          "key": "RRA-71",
          "summary": "BA3 Engineering",
          "type": "allocation",
          "status": "In Progress",
          "activity": "Engineering",
          "assignee": "Dmitry Rudnitsky",
          "team": null,
          "start": "2026-02-07T01:00:00.000+0000",
          "end": "2026-02-20T23:00:00.000+0000",
          "parent_key": null,
          "url": "https://sklvc.atlassian.net/browse/RRA-71"
        }
      ],
      "WA10": [
        {
          "key": "RRA-64",
          "summary": "WA10",
          "type": "allocation",
          "status": "In Progress",
          "activity": "T&V",
          "assignee": "Sergey Cherdantsev",
          "team": null,
          "start": "2026-02-02T00:00:00.000+0000",
          "end": "2026-03-26T00:00:00.000+0000",
          "parent_key": null,
          "url": "https://sklvc.atlassian.net/browse/RRA-64"
        }
      ]
    },
    "procurement": {
      "key": "HUMPROC-3325",
      "summary": "Luke Richardson - scan computers - Procurement - 022",
      "status": "Invoice paid",
      "status_category": "indeterminate",
      "priority": "Medium",
      "assignee": null,
      "created": "2026-02-03",
      "updated": "2026-06-04",
      "url": "https://sklvc.atlassian.net/browse/HUMPROC-3325"
    },
    "hopsit": {
      "total": 100,
      "by_status": {
        "In Progress": 100
      },
      "by_type": {
        "Task": 37,
        "Epic": 44,
        "Top-level initiative": 15,
        "Sub-task": 4
      },
      "open_tickets": [
        {
          "key": "HOPS-2680",
          "summary": "Provide access to SAP for UAT users",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-07-23",
          "updated": "2026-07-23",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2680"
        },
        {
          "key": "HOPS-2678",
          "summary": "Improvements in the Risk Register for Wheeled Programme ",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Artyom Shibanov",
          "created": "2026-07-03",
          "updated": "2026-07-21",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2678"
        },
        {
          "key": "HOPS-2548",
          "summary": "Cost Engineering Design to cost form support",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Artyom Shibanov",
          "created": "2026-04-15",
          "updated": "2026-07-20",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2548"
        },
        {
          "key": "HOPS-2672",
          "summary": "Training (group of tasks)",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-06-29",
          "updated": "2026-07-13",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2672"
        },
        {
          "key": "HOPS-2671",
          "summary": "Change Management Approach",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-06-29",
          "updated": "2026-07-13",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2671"
        },
        {
          "key": "HOPS-916",
          "summary": "Develop Talent Management capability - current/future phases",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2025-07-09",
          "updated": "2026-07-09",
          "url": "https://sklvc.atlassian.net/browse/HOPS-916"
        },
        {
          "key": "HOPS-2642",
          "summary": "GAP 7 User instructions must be drafted according EN ISO 20607",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-07-06",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2642"
        },
        {
          "key": "HOPS-245",
          "summary": "Develop Risk Assessment and Management capability - current phase",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2025-02-18",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HOPS-245"
        },
        {
          "key": "HOPS-243",
          "summary": "Governance, Risk & Compliance Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Nick Turner",
          "created": "2025-02-18",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HOPS-243"
        },
        {
          "key": "HOPS-942",
          "summary": "Lab Health & Safety - Compliance",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-07-23",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HOPS-942"
        },
        {
          "key": "HOPS-939",
          "summary": "Lab Health & Safety - Training & Competence",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-07-23",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HOPS-939"
        },
        {
          "key": "HOPS-937",
          "summary": "Lab Health & Safety - Policy & Governance",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-07-23",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HOPS-937"
        },
        {
          "key": "HOPS-324",
          "summary": "Lab - Health, Safety and Environment Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-03-01",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HOPS-324"
        },
        {
          "key": "HOPS-938",
          "summary": "Lab Health & Safety - Risk Assessment & Control",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-07-23",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HOPS-938"
        },
        {
          "key": "HOPS-2665",
          "summary": "Organize Inventree tool training for Stock managers & SC team",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "High",
          "assignee": "Mbale Hanyana",
          "created": "2026-05-28",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2665"
        },
        {
          "key": "HOPS-897",
          "summary": "Develop Procurement Management capability - current/actual works",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Neel Ghai",
          "created": "2025-07-07",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-897"
        },
        {
          "key": "HOPS-139",
          "summary": "ERP Implementation - Project Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2025-02-03",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-139"
        },
        {
          "key": "HOPS-2673",
          "summary": "Change Implementation (group of tasks)",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-06-29",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2673"
        },
        {
          "key": "HOPS-2542",
          "summary": "Analyse integration requirements for (SAP + PLM) -> MES",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Matteo Massimi",
          "created": "2026-03-31",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2542"
        },
        {
          "key": "HOPS-2670",
          "summary": "ERP Implementation - Integration",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-06-29",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2670"
        },
        {
          "key": "HOPS-281",
          "summary": "ERP Implementation - Change Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2025-02-18",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-281"
        },
        {
          "key": "HOPS-2529",
          "summary": "Develop a roadmap for trial, selection, and implementation of MES solution",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Matteo Massimi",
          "created": "2026-03-20",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2529"
        },
        {
          "key": "HOPS-317",
          "summary": "MES Implementation",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Matteo Massimi",
          "created": "2025-02-28",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-317"
        },
        {
          "key": "HOPS-2669",
          "summary": "Integrate Atlassian with other tools using Atlassian Teamwork Graph",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Karen Little",
          "created": "2026-06-17",
          "updated": "2026-06-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2669"
        },
        {
          "key": "HOPS-2668",
          "summary": "AI tools integration",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": null,
          "created": "2026-06-17",
          "updated": "2026-06-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2668"
        },
        {
          "key": "HOPS-2617",
          "summary": "HiBob -> Jira Integration for Expenses approval flow",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Artyom Shibanov",
          "created": "2026-05-11",
          "updated": "2026-06-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2617"
        },
        {
          "key": "HOPS-2313",
          "summary": "ERP implementation_Phase 1",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "High",
          "assignee": "Eugene Victorov",
          "created": "2026-01-23",
          "updated": "2026-06-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2313"
        },
        {
          "key": "HOPS-2667",
          "summary": "Cost Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Iulian Negoita",
          "created": "2026-06-17",
          "updated": "2026-06-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2667"
        },
        {
          "key": "HOPS-2648",
          "summary": "GAP 17 Mark shelf life limited components, safety related parts (MTTFD)",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-06-12",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2648"
        },
        {
          "key": "HOPS-2644",
          "summary": "GAP  8 Authorised representative not appointed",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-06-12",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2644"
        },
        {
          "key": "HOPS-2641",
          "summary": "GAP 6 Compliance status is currently not traceable",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-06-12",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2641"
        },
        {
          "key": "HOPS-2640",
          "summary": "GAP 5 The purchasing strategy must incorporate environmental compliance",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-06-12",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2640"
        },
        {
          "key": "HOPS-2650",
          "summary": "GAP 20 Implementing a non-certified WiFi Controller / 5G modem requires additional certification",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Highest",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-06-12",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2650"
        },
        {
          "key": "HOPS-2662",
          "summary": "Define Beta 0 Change categories",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Sub-task",
          "priority": "Medium",
          "assignee": null,
          "created": "2026-05-21",
          "updated": "2026-06-05",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2662"
        },
        {
          "key": "HOPS-2664",
          "summary": "Integrate Bob and Google Calendar",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Sub-task",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-05-28",
          "updated": "2026-06-02",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2664"
        },
        {
          "key": "HOPS-2552",
          "summary": "Services System Requirements Specification (SSRS) ",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "High",
          "assignee": "Eugene Victorov",
          "created": "2026-04-17",
          "updated": "2026-06-02",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2552"
        },
        {
          "key": "HOPS-983",
          "summary": "Get foam inserts for Bott furniture",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-07-23",
          "updated": "2026-05-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-983"
        },
        {
          "key": "HOPS-1235",
          "summary": "Shuffle workbenches in workshop in accordance with Jeffrey's plan - to improve production workflow",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-11-03",
          "updated": "2026-05-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1235"
        },
        {
          "key": "HOPS-1144",
          "summary": "Create change request for Logistic workflow update in Jira",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Sunpreet Malhotra",
          "created": "2025-09-29",
          "updated": "2026-05-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1144"
        },
        {
          "key": "HOPS-1130",
          "summary": "Create shipping guide for UK location",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Sunpreet Malhotra",
          "created": "2025-09-25",
          "updated": "2026-05-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1130"
        },
        {
          "key": "HOPS-960",
          "summary": "Acquire cell battery disposal bin",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-07-23",
          "updated": "2026-05-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-960"
        },
        {
          "key": "HOPS-1002",
          "summary": "Arrange schedule for IOSH Managing Safely course sessions",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-07-23",
          "updated": "2026-05-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1002"
        },
        {
          "key": "HOPS-429",
          "summary": "Analyse Fixed Asset Register from Confluence considering Anastasia comments",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Karen Little",
          "created": "2025-03-22",
          "updated": "2026-05-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-429"
        },
        {
          "key": "HOPS-2212",
          "summary": "Communicate with zone captains to determine organisational responsibilities and delegate responsible, consulted and informed personnel.",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-11-13",
          "updated": "2026-05-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2212"
        },
        {
          "key": "HOPS-2211",
          "summary": "Zone captains assigned (1 per area) with backup.",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Alejandro Pascual",
          "created": "2025-11-13",
          "updated": "2026-05-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2211"
        },
        {
          "key": "HOPS-2661",
          "summary": "TDP Requirements (General HW components)",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Sub-task",
          "priority": "Medium",
          "assignee": null,
          "created": "2026-05-21",
          "updated": "2026-05-28",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2661"
        },
        {
          "key": "HOPS-2654",
          "summary": "Standardised engineering release process & Publish ",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Sub-task",
          "priority": "Highest",
          "assignee": null,
          "created": "2026-05-14",
          "updated": "2026-05-21",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2654"
        },
        {
          "key": "HOPS-2649",
          "summary": "GAP 19 Cyber Resilience measures must be defined and implemented across product but also fleet management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Highest",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-05-14",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2649"
        },
        {
          "key": "HOPS-2638",
          "summary": "GAP 12 Service mode not defined",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Highest",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-05-14",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2638"
        },
        {
          "key": "HOPS-2651",
          "summary": "GAP 21 Data Protection Strategy for operating fields must be defined and deployed",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-05-14",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2651"
        },
        {
          "key": "HOPS-2647",
          "summary": "GAP 16 A trade restriction implementation strategy must be defined",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-05-14",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2647"
        },
        {
          "key": "HOPS-2653",
          "summary": "GAP 23 Documentation to support conformity assessment internally & externally must be drafted",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-05-14",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2653"
        },
        {
          "key": "HOPS-687",
          "summary": "Material Specification MVP",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Mbale Hanyana",
          "created": "2025-05-13",
          "updated": "2026-05-14",
          "url": "https://sklvc.atlassian.net/browse/HOPS-687"
        },
        {
          "key": "HOPS-2634",
          "summary": "GAP 14 Certification partner for proof of concept",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Highest",
          "assignee": "Fabian Huber",
          "created": "2026-05-14",
          "updated": "2026-05-14",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2634"
        },
        {
          "key": "HOPS-2539",
          "summary": "EBOM and TDP Release Process",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Mbale Hanyana",
          "created": "2026-03-27",
          "updated": "2026-05-13",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2539"
        },
        {
          "key": "HOPS-2618",
          "summary": "HiBob -> Jira Assets Sync",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Artyom Shibanov",
          "created": "2026-05-11",
          "updated": "2026-05-11",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2618"
        },
        {
          "key": "HOPS-115",
          "summary": "Draft Engieenering processes map",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Mbale Hanyana",
          "created": "2025-02-03",
          "updated": "2026-04-29",
          "url": "https://sklvc.atlassian.net/browse/HOPS-115"
        },
        {
          "key": "HOPS-2435",
          "summary": "Jira Service Management - Phase 2",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "High",
          "assignee": "Karen Little",
          "created": "2026-02-18",
          "updated": "2026-03-19",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2435"
        },
        {
          "key": "HOPS-2354",
          "summary": "Manufacturing",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Natalia Uttsova",
          "created": "2026-02-02",
          "updated": "2026-03-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2354"
        },
        {
          "key": "HOPS-2351",
          "summary": "Integration & Test",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Natalia Uttsova",
          "created": "2026-02-02",
          "updated": "2026-03-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2351"
        },
        {
          "key": "HOPS-2312",
          "summary": "PLM implementation",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Natalia Uttsova",
          "created": "2026-01-23",
          "updated": "2026-03-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2312"
        },
        {
          "key": "HOPS-2348",
          "summary": "Hardware",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Natalia Uttsova",
          "created": "2026-02-02",
          "updated": "2026-03-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2348"
        },
        {
          "key": "HOPS-2358",
          "summary": "Cost Engineering",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Anastasia Savelyeva",
          "created": "2026-02-02",
          "updated": "2026-03-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2358"
        },
        {
          "key": "HOPS-2419",
          "summary": "Product Management digital transformation",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-02-13",
          "updated": "2026-03-02",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2419"
        },
        {
          "key": "HOPS-2314",
          "summary": "HR Digital Transformation",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "High",
          "assignee": "Eugene Victorov",
          "created": "2026-01-23",
          "updated": "2026-02-23",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2314"
        },
        {
          "key": "HOPS-2364",
          "summary": "Capability Assessments",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Anastasia Savelyeva",
          "created": "2026-02-02",
          "updated": "2026-02-23",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2364"
        },
        {
          "key": "HOPS-1967",
          "summary": "PLT_WB_Phase 4 - Detailed Design",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "High",
          "assignee": null,
          "created": "2025-11-05",
          "updated": "2026-02-17",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1967"
        },
        {
          "key": "HOPS-2422",
          "summary": "Product Deployment digital transformation",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-02-13",
          "updated": "2026-02-13",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2422"
        },
        {
          "key": "HOPS-2421",
          "summary": "Design digital transformation",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-02-13",
          "updated": "2026-02-13",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2421"
        },
        {
          "key": "HOPS-2420",
          "summary": "Product Development digital transformation",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-02-13",
          "updated": "2026-02-13",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2420"
        },
        {
          "key": "HOPS-2318",
          "summary": "Engineering digital transformation",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Natalia Uttsova",
          "created": "2026-01-27",
          "updated": "2026-02-13",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2318"
        },
        {
          "key": "HOPS-2376",
          "summary": "DFX Issue management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Natalia Uttsova",
          "created": "2026-02-03",
          "updated": "2026-02-10",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2376"
        },
        {
          "key": "HOPS-54",
          "summary": "Knowledge Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2025-01-28",
          "updated": "2026-02-09",
          "url": "https://sklvc.atlassian.net/browse/HOPS-54"
        },
        {
          "key": "HOPS-2345",
          "summary": "HR Digitalisation - Other Activities",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-01-30",
          "updated": "2026-02-06",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2345"
        },
        {
          "key": "HOPS-2366",
          "summary": "Wiki Content Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-02-02",
          "updated": "2026-02-06",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2366"
        },
        {
          "key": "HOPS-2346",
          "summary": "Beta Lessons Learned",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Eugene Victorov",
          "created": "2026-01-30",
          "updated": "2026-02-06",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2346"
        },
        {
          "key": "HOPS-1049",
          "summary": "Develop IT Service Management capability - current/future phases",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Karen Little",
          "created": "2025-08-06",
          "updated": "2026-02-06",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1049"
        },
        {
          "key": "HOPS-1145",
          "summary": "Develop IT Portfolio management capability - current/future phases",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Yiannis Levantis",
          "created": "2025-09-29",
          "updated": "2026-02-06",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1145"
        },
        {
          "key": "HOPS-1147",
          "summary": "Develop IT Resilience & Disaster Recovery management capability - current/future phases",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Yiannis Levantis",
          "created": "2025-09-29",
          "updated": "2026-02-06",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1147"
        },
        {
          "key": "HOPS-1087",
          "summary": "Develop IT Security Management capability - current/future phases",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Tarek Mekari",
          "created": "2025-08-27",
          "updated": "2026-02-06",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1087"
        },
        {
          "key": "HOPS-2316",
          "summary": "Back Office Digital Transformation",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Anastasia Savelyeva",
          "created": "2026-01-27",
          "updated": "2026-02-05",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2316"
        },
        {
          "key": "HOPS-2321",
          "summary": "Incident Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Natalia Uttsova",
          "created": "2026-01-27",
          "updated": "2026-02-05",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2321"
        },
        {
          "key": "HOPS-2320",
          "summary": "Robot Allocation development",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Natalia Uttsova",
          "created": "2026-01-27",
          "updated": "2026-02-05",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2320"
        },
        {
          "key": "HOPS-2319",
          "summary": "Business Transformation Development",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "High",
          "assignee": "Anastasia Savelyeva",
          "created": "2026-01-27",
          "updated": "2026-02-03",
          "url": "https://sklvc.atlassian.net/browse/HOPS-2319"
        },
        {
          "key": "HOPS-1048",
          "summary": "Develop Business Architecture Design & Alignment capability - phase 6, 7",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Anastasia Savelyeva",
          "created": "2025-08-06",
          "updated": "2025-12-09",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1048"
        },
        {
          "key": "HOPS-1047",
          "summary": "Develop Logistics Management capability - phase 7",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Anastasia Savelyeva",
          "created": "2025-08-06",
          "updated": "2025-12-09",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1047"
        },
        {
          "key": "HOPS-1046",
          "summary": "Engineering processes overall - phase 7",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Natalia Uttsova",
          "created": "2025-08-06",
          "updated": "2025-12-09",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1046"
        },
        {
          "key": "HOPS-903",
          "summary": "Develop Inventory Management capability - phases 7, 8",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Anastasia Savelyeva",
          "created": "2025-07-07",
          "updated": "2025-12-09",
          "url": "https://sklvc.atlassian.net/browse/HOPS-903"
        },
        {
          "key": "HOPS-292",
          "summary": "Develop Strategy Management capability - phase 3, 4, 5, 6, 7",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Nick Turner",
          "created": "2025-02-19",
          "updated": "2025-12-09",
          "url": "https://sklvc.atlassian.net/browse/HOPS-292"
        },
        {
          "key": "HOPS-152",
          "summary": "Defect management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "High",
          "assignee": "Natalia Uttsova",
          "created": "2025-02-05",
          "updated": "2025-12-09",
          "url": "https://sklvc.atlassian.net/browse/HOPS-152"
        },
        {
          "key": "HOPS-568",
          "summary": "Develop Customer Relationship management capability - phase 3",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Anastasia Savelyeva",
          "created": "2025-03-31",
          "updated": "2025-12-09",
          "url": "https://sklvc.atlassian.net/browse/HOPS-568"
        },
        {
          "key": "HOPS-333",
          "summary": "Requirements Management - phase 2",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Natalia Uttsova",
          "created": "2025-03-01",
          "updated": "2025-12-09",
          "url": "https://sklvc.atlassian.net/browse/HOPS-333"
        },
        {
          "key": "HOPS-325",
          "summary": "Data Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Arash Momeni",
          "created": "2025-03-01",
          "updated": "2025-10-13",
          "url": "https://sklvc.atlassian.net/browse/HOPS-325"
        },
        {
          "key": "HOPS-628",
          "summary": "Data collection best practices documentation",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Task",
          "priority": "Medium",
          "assignee": "Arash Momeni",
          "created": "2025-04-28",
          "updated": "2025-10-13",
          "url": "https://sklvc.atlassian.net/browse/HOPS-628"
        },
        {
          "key": "HOPS-9",
          "summary": "IT Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Yiannis Levantis",
          "created": "2025-01-28",
          "updated": "2025-09-08",
          "url": "https://sklvc.atlassian.net/browse/HOPS-9"
        },
        {
          "key": "HOPS-1",
          "summary": "Enterprise Architecture",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Anastasia Savelyeva",
          "created": "2025-01-28",
          "updated": "2025-06-23",
          "url": "https://sklvc.atlassian.net/browse/HOPS-1"
        },
        {
          "key": "HOPS-240",
          "summary": "Portfolio and Change Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Nick Turner",
          "created": "2025-02-18",
          "updated": "2025-04-30",
          "url": "https://sklvc.atlassian.net/browse/HOPS-240"
        },
        {
          "key": "HOPS-530",
          "summary": "Improve Operational finance capability",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Anastasia Savelyeva",
          "created": "2025-03-30",
          "updated": "2025-03-30",
          "url": "https://sklvc.atlassian.net/browse/HOPS-530"
        },
        {
          "key": "HOPS-246",
          "summary": "Legal Management",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Top-level initiative",
          "priority": "Medium",
          "assignee": "Anastasia Savelyeva",
          "created": "2025-02-18",
          "updated": "2025-03-26",
          "url": "https://sklvc.atlassian.net/browse/HOPS-246"
        },
        {
          "key": "HOPS-410",
          "summary": "Operations Team Planning and Development",
          "status": "In Progress",
          "status_category": "indeterminate",
          "type": "Epic",
          "priority": "Medium",
          "assignee": "Thomas Shepherd",
          "created": "2025-03-17",
          "updated": "2025-03-26",
          "url": "https://sklvc.atlassian.net/browse/HOPS-410"
        }
      ]
    },
    "heco": {
      "releases": [
        {
          "id": "10078",
          "name": "Dual arm Mobile Box/Tote handling with Bipedal Alpha",
          "released": false,
          "release_date": "2026-10-30",
          "description": ""
        },
        {
          "id": "10079",
          "name": "Remote teloperation for Wheeled Alpha",
          "released": false,
          "release_date": "2025-08-15",
          "description": ""
        },
        {
          "id": "10080",
          "name": "Remote teleoperation for preAlpha",
          "released": true,
          "release_date": "2025-03-28",
          "description": ""
        },
        {
          "id": "10081",
          "name": "Stationary Pick & Place with Rainbow",
          "released": true,
          "release_date": "2025-03-04",
          "description": ""
        },
        {
          "id": "10082",
          "name": "Mobile Pick & Place with Rainbow",
          "released": true,
          "release_date": "2025-05-01",
          "description": ""
        },
        {
          "id": "10083",
          "name": "Mobile Pick & Place with Wheeled Alpha",
          "released": false,
          "release_date": "2025-08-29",
          "description": ""
        },
        {
          "id": "10084",
          "name": "Stationary Pick & Place with Hmnd Upper Body",
          "released": false,
          "release_date": "2025-08-15",
          "description": ""
        },
        {
          "id": "10085",
          "name": "Stationary Pick & Place with Bipedal Alpha",
          "released": false,
          "release_date": "2025-10-03",
          "description": ""
        },
        {
          "id": "10086",
          "name": "Dual arm Mobile Box/Tote handling with wheeled Alpha",
          "released": false,
          "release_date": "2025-09-30",
          "description": ""
        },
        {
          "id": "10190",
          "name": "Low Level and Middle Level - Preliminary Design Review",
          "released": true,
          "release_date": "2025-08-14",
          "description": ""
        },
        {
          "id": "10558",
          "name": "Nav Lidar SLAM - W Alpha Platform SW Integration",
          "released": false,
          "release_date": "2025-08-29",
          "description": ""
        },
        {
          "id": "10560",
          "name": "Tesco HRI - W Alpha Platform SW Integration",
          "released": false,
          "release_date": "2025-08-15",
          "description": ""
        },
        {
          "id": "10559",
          "name": "T.op Tote handling - W Alpha Platform SW Integration",
          "released": false,
          "release_date": "2025-08-22",
          "description": ""
        },
        {
          "id": "10561",
          "name": "Bringup Full Body (joint space) - W Alpha Platform SW Integration",
          "released": true,
          "release_date": "2025-08-01",
          "description": ""
        },
        {
          "id": "10562",
          "name": "BringUp two arms - W Alpha Platform SW Integration",
          "released": true,
          "release_date": "2025-06-17",
          "description": ""
        },
        {
          "id": "10563",
          "name": "BringUp Lower Body - W Alpha Platform SW Integration",
          "released": true,
          "release_date": "2025-07-18",
          "description": ""
        },
        {
          "id": "10884",
          "name": "Weekly 2025-11-17",
          "released": false,
          "release_date": "2025-11-17",
          "description": "Weekly monday release cadence. Scope from release planning defined here:\nhttps://miro.com/app/board/uXjVJw7IgFw=/\nFor questions, contact @dmitryR or @doran"
        },
        {
          "id": "11270",
          "name": "2026.02.19",
          "released": true,
          "release_date": "2026-02-19",
          "description": "Targets Bosch POC"
        },
        {
          "id": "11303",
          "name": "2026.03.02",
          "released": true,
          "release_date": "2026-03-02",
          "description": "Targets robo store."
        },
        {
          "id": "11336",
          "name": "2026.03.18",
          "released": true,
          "release_date": "2026-03-18",
          "description": ""
        },
        {
          "id": "11369",
          "name": "2026.04.01",
          "released": true,
          "release_date": "2026-04-01",
          "description": "Targets siemens."
        },
        {
          "id": "11402",
          "name": "2026.04.15",
          "released": true,
          "release_date": "2026-04-15",
          "description": "Targets symphony 2"
        },
        {
          "id": "11435",
          "name": "2026.04.29",
          "released": true,
          "release_date": "2026-04-29",
          "description": ""
        },
        {
          "id": "11468",
          "name": "2026.05.13",
          "released": true,
          "release_date": "2026-05-14",
          "description": ""
        },
        {
          "id": "11501",
          "name": "2026.05.29",
          "released": true,
          "release_date": "2026-05-29",
          "description": ""
        },
        {
          "id": "11534",
          "name": "2026.06.11",
          "released": true,
          "release_date": "2026-06-11",
          "description": ""
        },
        {
          "id": "11600",
          "name": "2026.06.24",
          "released": true,
          "release_date": "2026-06-24",
          "description": ""
        },
        {
          "id": "11633",
          "name": "2026.07.08",
          "released": true,
          "release_date": "2026-07-08",
          "description": ""
        },
        {
          "id": "11666",
          "name": "2026.07.22",
          "released": true,
          "release_date": "2026-07-22",
          "description": ""
        },
        {
          "id": "11734",
          "name": "2026.08.05",
          "released": false,
          "release_date": "2026-08-05",
          "description": ""
        },
        {
          "id": "11800",
          "name": "2026.08.12",
          "released": false,
          "release_date": "2026-08-12",
          "description": ""
        }
      ],
      "active_initiatives": [
        {
          "key": "HECO-4131",
          "summary": "[Q3 Cap Goal] Teleoperation at 600/300 UPH (ring picking / totes)",
          "status": "In Progress",
          "assignee": "Rodrigo Neves Zenha",
          "updated": "2026-07-21",
          "url": "https://sklvc.atlassian.net/browse/HECO-4131"
        },
        {
          "key": "HECO-4128",
          "summary": "[Q3 Cap Goal] Fleet WBC performance-metrics pipeline (pilot readiness)",
          "status": "In Progress",
          "assignee": "Saeid Samadi",
          "updated": "2026-07-21",
          "url": "https://sklvc.atlassian.net/browse/HECO-4128"
        },
        {
          "key": "HECO-4127",
          "summary": "[Q3 Cap Goal] Biped - Perceptive biped loco-manipulation (stairs & obstacles)",
          "status": "In Progress",
          "assignee": "Thomas Corberes",
          "updated": "2026-07-17",
          "url": "https://sklvc.atlassian.net/browse/HECO-4127"
        },
        {
          "key": "HECO-4135",
          "summary": "[Q3 Cap Goal] Biped - Teleoperated full-body RL control",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-07-17",
          "url": "https://sklvc.atlassian.net/browse/HECO-4135"
        },
        {
          "key": "HECO-4134",
          "summary": "[Q2 Cap Goal] Box-handling teleoperation data for VLA training",
          "status": "In Progress",
          "assignee": "Saeid Samadi",
          "updated": "2026-07-07",
          "url": "https://sklvc.atlassian.net/browse/HECO-4134"
        },
        {
          "key": "HECO-2337",
          "summary": "[Cap Backlog] Wheeled",
          "status": "In Progress",
          "assignee": "Andy Park",
          "updated": "2026-07-07",
          "url": "https://sklvc.atlassian.net/browse/HECO-2337"
        },
        {
          "key": "HECO-1613",
          "summary": "[Platform] Biped Alpha",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HECO-1613"
        },
        {
          "key": "HECO-1225",
          "summary": "[Platform] Wheeled Alpha",
          "status": "In Progress",
          "assignee": "Anubhav Dogra",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HECO-1225"
        },
        {
          "key": "HECO-1309",
          "summary": "[Platform Design] Beta Subsys Concept: Sim",
          "status": "In Progress",
          "assignee": "Daksh Dhingra",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HECO-1309"
        },
        {
          "key": "HECO-468",
          "summary": "[Platform] Wheeled Beta - Subsys Concept: Controls",
          "status": "In Progress",
          "assignee": "Anubhav Dogra",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HECO-468"
        },
        {
          "key": "HECO-4133",
          "summary": "[Q2 Cap Goal] Full-body teleoperation live on the fleet",
          "status": "In Progress",
          "assignee": "Rodrigo Neves Zenha",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HECO-4133"
        },
        {
          "key": "HECO-1317",
          "summary": "Beta Subsys Concept: Navigation",
          "status": "In Progress",
          "assignee": "Karim Shaban",
          "updated": "2026-05-05",
          "url": "https://sklvc.atlassian.net/browse/HECO-1317"
        },
        {
          "key": "HECO-3009",
          "summary": "Beta Wheelbase Software/Control",
          "status": "In Progress",
          "assignee": "Muhammad Awais Rafique",
          "updated": "2026-04-20",
          "url": "https://sklvc.atlassian.net/browse/HECO-3009"
        },
        {
          "key": "HECO-2047",
          "summary": "Alpha Controls Development and Testing (Vancouver)",
          "status": "In Progress",
          "assignee": null,
          "updated": "2025-12-05",
          "url": "https://sklvc.atlassian.net/browse/HECO-2047"
        },
        {
          "key": "HECO-1622",
          "summary": "Beta Subsys Concept: Network & Compute SW",
          "status": "In Progress",
          "assignee": "Clifford Pontbriand",
          "updated": "2025-11-05",
          "url": "https://sklvc.atlassian.net/browse/HECO-1622"
        },
        {
          "key": "HECO-3364",
          "summary": "Beta Subsys Design: Network & Compute SW",
          "status": "Backlog",
          "assignee": "Brian Ginebaugh",
          "updated": "2026-07-15",
          "url": "https://sklvc.atlassian.net/browse/HECO-3364"
        },
        {
          "key": "HECO-1605",
          "summary": "[Cap Backlog] Teleoperation",
          "status": "Backlog",
          "assignee": "Rodrigo Neves Zenha",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HECO-1605"
        },
        {
          "key": "HECO-4132",
          "summary": "[Q3 Cap Goal] Single WBC interface for upper-body and base",
          "status": "Backlog",
          "assignee": "Andy Park",
          "updated": "2026-06-25",
          "url": "https://sklvc.atlassian.net/browse/HECO-4132"
        },
        {
          "key": "HECO-4136",
          "summary": "[Cap Backlog] Biped",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-06-25",
          "url": "https://sklvc.atlassian.net/browse/HECO-4136"
        },
        {
          "key": "HECO-3777",
          "summary": "Integrate visual mapping with Reverb-Switchboard workflows",
          "status": "Backlog",
          "assignee": "Matt Klingensmith",
          "updated": "2026-06-03",
          "url": "https://sklvc.atlassian.net/browse/HECO-3777"
        },
        {
          "key": "HECO-3050",
          "summary": "Robostore Followup Tech Debt",
          "status": "Backlog",
          "assignee": "Matt Klingensmith",
          "updated": "2026-05-27",
          "url": "https://sklvc.atlassian.net/browse/HECO-3050"
        },
        {
          "key": "HECO-1326",
          "summary": "Beta Subsys Concept: Cloud Infra / DevOps ",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-04-20",
          "url": "https://sklvc.atlassian.net/browse/HECO-1326"
        },
        {
          "key": "HECO-1325",
          "summary": "Beta Subsys Concept: Safety Subsystem Software",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-04-20",
          "url": "https://sklvc.atlassian.net/browse/HECO-1325"
        },
        {
          "key": "HECO-2714",
          "summary": "WA2 arms lowering whilst holding a tote during navigation",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-02-24",
          "url": "https://sklvc.atlassian.net/browse/HECO-2714"
        },
        {
          "key": "HECO-2611",
          "summary": "Beta Subsys Design: Controls",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-02-12",
          "url": "https://sklvc.atlassian.net/browse/HECO-2611"
        },
        {
          "key": "HECO-1731",
          "summary": "Wheeled - WBC RL (feasibility study)",
          "status": "Backlog",
          "assignee": null,
          "updated": "2025-11-05",
          "url": "https://sklvc.atlassian.net/browse/HECO-1731"
        },
        {
          "key": "HECO-843",
          "summary": "Simulation Development",
          "status": "Backlog",
          "assignee": "Dmitriy Shingarey",
          "updated": "2025-09-30",
          "url": "https://sklvc.atlassian.net/browse/HECO-843"
        },
        {
          "key": "HECO-469",
          "summary": "Tesco PoC - Wheeled Alpha",
          "status": "Backlog",
          "assignee": "Giulio Cerruti",
          "updated": "2025-07-29",
          "url": "https://sklvc.atlassian.net/browse/HECO-469"
        },
        {
          "key": "HECO-844",
          "summary": "Reasoning",
          "status": "Backlog",
          "assignee": null,
          "updated": "2025-07-10",
          "url": "https://sklvc.atlassian.net/browse/HECO-844"
        },
        {
          "key": "HECO-2874",
          "summary": "Applications - ROS tech debt",
          "status": "Selected for Development",
          "assignee": "Cody Griffin",
          "updated": "2026-03-12",
          "url": "https://sklvc.atlassian.net/browse/HECO-2874"
        },
        {
          "key": "HECO-2058",
          "summary": "[Platform Design] Home biped Subsys Concept: Sim",
          "status": "On hold",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-07-09",
          "url": "https://sklvc.atlassian.net/browse/HECO-2058"
        },
        {
          "key": "HECO-1730",
          "summary": "[Cap Backlog] Wheeled - WBC RL feasibility study",
          "status": "On hold",
          "assignee": "Saeid Samadi",
          "updated": "2026-07-09",
          "url": "https://sklvc.atlassian.net/browse/HECO-1730"
        },
        {
          "key": "HECO-2643",
          "summary": "HRI system tech debt, updates and improvements",
          "status": "On hold",
          "assignee": "Yuriy Strezhik",
          "updated": "2026-06-03",
          "url": "https://sklvc.atlassian.net/browse/HECO-2643"
        },
        {
          "key": "HECO-2645",
          "summary": "Incident Management Tools",
          "status": "On hold",
          "assignee": "Matt Klingensmith",
          "updated": "2026-06-01",
          "url": "https://sklvc.atlassian.net/browse/HECO-2645"
        }
      ],
      "active_epics": [
        {
          "key": "HECO-2875",
          "summary": "Convert python ROS clients to faster C++ backed libraries.",
          "status": "In Progress",
          "assignee": "Sam Pfeiffer",
          "updated": "2026-07-23",
          "url": "https://sklvc.atlassian.net/browse/HECO-2875"
        },
        {
          "key": "HECO-2916",
          "summary": "[Symphony 2] Accumulated Tech Debt.",
          "status": "In Progress",
          "assignee": "Matt Klingensmith",
          "updated": "2026-07-23",
          "url": "https://sklvc.atlassian.net/browse/HECO-2916"
        },
        {
          "key": "HECO-3778",
          "summary": "Integrate global relocalization with Reverb",
          "status": "In Progress",
          "assignee": "Bao Tran",
          "updated": "2026-07-23",
          "url": "https://sklvc.atlassian.net/browse/HECO-3778"
        },
        {
          "key": "HECO-3843",
          "summary": "[Symphony 2.5] Fleet Management and Bringup Upgrades",
          "status": "In Progress",
          "assignee": "Matt Klingensmith",
          "updated": "2026-07-23",
          "url": "https://sklvc.atlassian.net/browse/HECO-3843"
        },
        {
          "key": "HECO-3585",
          "summary": "Implement detection and error reporting for gripper failure",
          "status": "In Progress",
          "assignee": "Anubhav Dogra",
          "updated": "2026-07-22",
          "url": "https://sklvc.atlassian.net/browse/HECO-3585"
        },
        {
          "key": "HECO-2936",
          "summary": "Head control via teleop",
          "status": "In Progress",
          "assignee": "Rodrigo Neves Zenha",
          "updated": "2026-07-22",
          "url": "https://sklvc.atlassian.net/browse/HECO-2936"
        },
        {
          "key": "HECO-4191",
          "summary": "[Beta 2] Re-eval roll as last DoF with UMI trj",
          "status": "In Progress",
          "assignee": "Daksh Dhingra",
          "updated": "2026-07-22",
          "url": "https://sklvc.atlassian.net/browse/HECO-4191"
        },
        {
          "key": "HECO-3833",
          "summary": "[SIM] - [Fidelity] - [P0] - Investigate RL \u2194 sim-eval anticorrelation",
          "status": "In Progress",
          "assignee": "Sepehr Ramezani",
          "updated": "2026-07-21",
          "url": "https://sklvc.atlassian.net/browse/HECO-3833"
        },
        {
          "key": "HECO-4447",
          "summary": "[Symphony 2.5] Physical workflow development and deployment.",
          "status": "In Progress",
          "assignee": "Matt Klingensmith",
          "updated": "2026-07-21",
          "url": "https://sklvc.atlassian.net/browse/HECO-4447"
        },
        {
          "key": "HECO-4184",
          "summary": "Suction capability testing and validation (Box handling)",
          "status": "In Progress",
          "assignee": "Saeid Samadi",
          "updated": "2026-07-20",
          "url": "https://sklvc.atlassian.net/browse/HECO-4184"
        },
        {
          "key": "HECO-4198",
          "summary": "Evaluation of mushroom for lidded totes placement",
          "status": "In Progress",
          "assignee": "Saeid Samadi",
          "updated": "2026-07-20",
          "url": "https://sklvc.atlassian.net/browse/HECO-4198"
        },
        {
          "key": "HECO-3323",
          "summary": "The Alphaclaw Fleet",
          "status": "In Progress",
          "assignee": "Atindra Nair",
          "updated": "2026-07-20",
          "url": "https://sklvc.atlassian.net/browse/HECO-3323"
        },
        {
          "key": "HECO-1316",
          "summary": "[Tool] Power modelling for Beta",
          "status": "In Progress",
          "assignee": "Gregory Michaud",
          "updated": "2026-07-17",
          "url": "https://sklvc.atlassian.net/browse/HECO-1316"
        },
        {
          "key": "HECO-4336",
          "summary": "Synapse Common Class Specification and Userspace Implementation",
          "status": "In Progress",
          "assignee": "Brian Ginebaugh",
          "updated": "2026-07-15",
          "url": "https://sklvc.atlassian.net/browse/HECO-4336"
        },
        {
          "key": "HECO-2424",
          "summary": "F/T estimation from joint torques at EE bringup",
          "status": "In Progress",
          "assignee": "Gregory Michaud",
          "updated": "2026-07-15",
          "url": "https://sklvc.atlassian.net/browse/HECO-2424"
        },
        {
          "key": "HECO-4325",
          "summary": "Switchboard 2.0 Migration Tasks",
          "status": "In Progress",
          "assignee": "Cody Griffin",
          "updated": "2026-07-14",
          "url": "https://sklvc.atlassian.net/browse/HECO-4325"
        },
        {
          "key": "HECO-4190",
          "summary": "[Beta 2] Sensitivity analysis to inform arm design",
          "status": "In Progress",
          "assignee": "Daksh Dhingra",
          "updated": "2026-07-13",
          "url": "https://sklvc.atlassian.net/browse/HECO-4190"
        },
        {
          "key": "HECO-3408",
          "summary": "CI Build Telemetry and Dashboards",
          "status": "In Progress",
          "assignee": "Ricardo Delfin",
          "updated": "2026-07-13",
          "url": "https://sklvc.atlassian.net/browse/HECO-3408"
        },
        {
          "key": "HECO-3832",
          "summary": "[SIM] - [PoC] - [P1] - Tidy & clean environment + robot with xhands",
          "status": "In Progress",
          "assignee": "Luke Bierbaum",
          "updated": "2026-07-09",
          "url": "https://sklvc.atlassian.net/browse/HECO-3832"
        },
        {
          "key": "HECO-4232",
          "summary": "Super charged System2 - Intern Project",
          "status": "In Progress",
          "assignee": "muhammad.siddiqui",
          "updated": "2026-07-08",
          "url": "https://sklvc.atlassian.net/browse/HECO-4232"
        },
        {
          "key": "HECO-4212",
          "summary": "Vision-guided Human Intervention from Sockpuppet",
          "status": "In Progress",
          "assignee": "Fanqi Xu",
          "updated": "2026-07-08",
          "url": "https://sklvc.atlassian.net/browse/HECO-4212"
        },
        {
          "key": "HECO-4243",
          "summary": "Fault Service Improvements",
          "status": "In Progress",
          "assignee": "Bao Tran",
          "updated": "2026-07-08",
          "url": "https://sklvc.atlassian.net/browse/HECO-4243"
        },
        {
          "key": "HECO-1495",
          "summary": "[Safety] Safety + Controls: define interfaces definitions and expected behaviors",
          "status": "In Progress",
          "assignee": "Andy Park",
          "updated": "2026-07-07",
          "url": "https://sklvc.atlassian.net/browse/HECO-1495"
        },
        {
          "key": "HECO-2635",
          "summary": "[Tech Debt] Reverb tech debt.",
          "status": "In Progress",
          "assignee": "Cody Griffin",
          "updated": "2026-07-07",
          "url": "https://sklvc.atlassian.net/browse/HECO-2635"
        },
        {
          "key": "HECO-4069",
          "summary": "10-minute testing",
          "status": "In Progress",
          "assignee": "Tobias Jacob",
          "updated": "2026-07-07",
          "url": "https://sklvc.atlassian.net/browse/HECO-4069"
        },
        {
          "key": "HECO-4072",
          "summary": "Symphony 2.5 digital twin",
          "status": "In Progress",
          "assignee": "Tobias Jacob",
          "updated": "2026-07-07",
          "url": "https://sklvc.atlassian.net/browse/HECO-4072"
        },
        {
          "key": "HECO-1268",
          "summary": "Integration Testing in Simulation",
          "status": "In Progress",
          "assignee": "Yuriy Strezhik",
          "updated": "2026-07-07",
          "url": "https://sklvc.atlassian.net/browse/HECO-1268"
        },
        {
          "key": "HECO-3817",
          "summary": "[Applications] Symphony 2 Policy/VLA Improvements",
          "status": "In Progress",
          "assignee": "Matt Klingensmith",
          "updated": "2026-07-07",
          "url": "https://sklvc.atlassian.net/browse/HECO-3817"
        },
        {
          "key": "HECO-2059",
          "summary": "Walking with passive toe",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-07-06",
          "url": "https://sklvc.atlassian.net/browse/HECO-2059"
        },
        {
          "key": "HECO-3720",
          "summary": "Standardize Biped bringup procedure and improve WBC state machine",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-07-03",
          "url": "https://sklvc.atlassian.net/browse/HECO-3720"
        },
        {
          "key": "HECO-3632",
          "summary": "Convert hmnd_robot/core as Pure CMake",
          "status": "In Progress",
          "assignee": "Ricardo Delfin",
          "updated": "2026-07-01",
          "url": "https://sklvc.atlassian.net/browse/HECO-3632"
        },
        {
          "key": "HECO-4056",
          "summary": "Untether biped actions items",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-07-01",
          "url": "https://sklvc.atlassian.net/browse/HECO-4056"
        },
        {
          "key": "HECO-2180",
          "summary": "WBC Classic vs RL analysis",
          "status": "In Progress",
          "assignee": "Saeid Samadi",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HECO-2180"
        },
        {
          "key": "HECO-3834",
          "summary": "[SIM] - [Perf] - [P1] - RL code refactoring / unify shared code across tasks",
          "status": "In Progress",
          "assignee": "Sepehr Ramezani",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HECO-3834"
        },
        {
          "key": "HECO-1055",
          "summary": "State estimation - Biped",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-06-29",
          "url": "https://sklvc.atlassian.net/browse/HECO-1055"
        },
        {
          "key": "HECO-3270",
          "summary": "Wheeled Alpha WBC comparison analysis: Placo vs EmbodIK",
          "status": "In Progress",
          "assignee": "Andy Park",
          "updated": "2026-06-25",
          "url": "https://sklvc.atlassian.net/browse/HECO-3270"
        },
        {
          "key": "HECO-2728",
          "summary": "New WBC solver development",
          "status": "In Progress",
          "assignee": "Andy Park",
          "updated": "2026-06-25",
          "url": "https://sklvc.atlassian.net/browse/HECO-2728"
        },
        {
          "key": "HECO-2396",
          "summary": "Motion control architecture for Home biped",
          "status": "In Progress",
          "assignee": "Giulio Cerruti",
          "updated": "2026-06-25",
          "url": "https://sklvc.atlassian.net/browse/HECO-2396"
        },
        {
          "key": "HECO-1763",
          "summary": "Newton for RL",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-06-25",
          "url": "https://sklvc.atlassian.net/browse/HECO-1763"
        },
        {
          "key": "HECO-2429",
          "summary": "Human like walking (twist as input)",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-06-25",
          "url": "https://sklvc.atlassian.net/browse/HECO-2429"
        },
        {
          "key": "HECO-2790",
          "summary": "Motion generator + Motion tracker (proprio)",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-06-25",
          "url": "https://sklvc.atlassian.net/browse/HECO-2790"
        },
        {
          "key": "HECO-1611",
          "summary": "[Eng PoC] Root tracking",
          "status": "In Progress",
          "assignee": "Rodrigo Neves Zenha",
          "updated": "2026-06-25",
          "url": "https://sklvc.atlassian.net/browse/HECO-1611"
        },
        {
          "key": "HECO-1931",
          "summary": "Log and track errors to show reliability metrics for unthetering biped",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2026-06-25",
          "url": "https://sklvc.atlassian.net/browse/HECO-1931"
        },
        {
          "key": "HECO-4120",
          "summary": "[SIM] - [ISAACSIM] - Update to Isaacsim 6.0",
          "status": "In Progress",
          "assignee": "Luke Bierbaum",
          "updated": "2026-06-24",
          "url": "https://sklvc.atlassian.net/browse/HECO-4120"
        },
        {
          "key": "HECO-3051",
          "summary": "[SIM] - [Fidelity] - [P0] - Sim2real discrepancy catalogue & fixes",
          "status": "In Progress",
          "assignee": "Sepehr Ramezani",
          "updated": "2026-06-24",
          "url": "https://sklvc.atlassian.net/browse/HECO-3051"
        },
        {
          "key": "HECO-3897",
          "summary": "Standardized Cloud communication ",
          "status": "In Progress",
          "assignee": "Joe Nunez",
          "updated": "2026-06-24",
          "url": "https://sklvc.atlassian.net/browse/HECO-3897"
        },
        {
          "key": "HECO-3935",
          "summary": "Backbone OTA \u2014 Platform, Infrastructure & Observability",
          "status": "In Progress",
          "assignee": null,
          "updated": "2026-06-24",
          "url": "https://sklvc.atlassian.net/browse/HECO-3935"
        },
        {
          "key": "HECO-3640",
          "summary": "OTA \u2014 Enable end-to-end cloud-to-device OTA for developers and operators to have one-click release targeting to devices",
          "status": "In Progress",
          "assignee": "Blake Lieber",
          "updated": "2026-06-24",
          "url": "https://sklvc.atlassian.net/browse/HECO-3640"
        },
        {
          "key": "HECO-3934",
          "summary": "Backbone Console \u2014 UI Bug Fixes",
          "status": "In Progress",
          "assignee": null,
          "updated": "2026-06-24",
          "url": "https://sklvc.atlassian.net/browse/HECO-3934"
        },
        {
          "key": "HECO-2719",
          "summary": "Investigate Coupled Joint Reflected Inertia",
          "status": "In Progress",
          "assignee": "Thomas Corberes",
          "updated": "2026-06-23",
          "url": "https://sklvc.atlassian.net/browse/HECO-2719"
        },
        {
          "key": "HECO-4001",
          "summary": "[Symphony 2.5] Workflow authoring improvements.",
          "status": "In Progress",
          "assignee": "Matt Klingensmith",
          "updated": "2026-06-17",
          "url": "https://sklvc.atlassian.net/browse/HECO-4001"
        },
        {
          "key": "HECO-3840",
          "summary": "[Reverb] Improve deployment experience.",
          "status": "In Progress",
          "assignee": "Matt Klingensmith",
          "updated": "2026-06-05",
          "url": "https://sklvc.atlassian.net/browse/HECO-3840"
        },
        {
          "key": "HECO-3635",
          "summary": "Enable Bazel Remote Cache",
          "status": "In Progress",
          "assignee": "Ricardo Delfin",
          "updated": "2026-06-02",
          "url": "https://sklvc.atlassian.net/browse/HECO-3635"
        },
        {
          "key": "HECO-3668",
          "summary": "Support end-to-end physical testing of Reverb",
          "status": "In Progress",
          "assignee": "Yuriy Strezhik",
          "updated": "2026-06-02",
          "url": "https://sklvc.atlassian.net/browse/HECO-3668"
        },
        {
          "key": "HECO-3637",
          "summary": "TOIL: Build and CI Reliability Issues",
          "status": "In Progress",
          "assignee": "Cody Griffin",
          "updated": "2026-06-01",
          "url": "https://sklvc.atlassian.net/browse/HECO-3637"
        },
        {
          "key": "HECO-3496",
          "summary": "VLA Training Pipeline and Teleoperation for Egocentric Data",
          "status": "In Progress",
          "assignee": "Bao Tran",
          "updated": "2026-05-11",
          "url": "https://sklvc.atlassian.net/browse/HECO-3496"
        },
        {
          "key": "HECO-3484",
          "summary": "[Health Reporting] Module Health & Fault Service Improvements",
          "status": "In Progress",
          "assignee": "Bao Tran",
          "updated": "2026-05-08",
          "url": "https://sklvc.atlassian.net/browse/HECO-3484"
        },
        {
          "key": "HECO-3274",
          "summary": "Improve WBC RL training speed",
          "status": "In Progress",
          "assignee": "Daksh Dhingra",
          "updated": "2026-05-06",
          "url": "https://sklvc.atlassian.net/browse/HECO-3274"
        },
        {
          "key": "HECO-3223",
          "summary": "WBC RL - tote handling for beta design",
          "status": "In Progress",
          "assignee": "Daksh Dhingra",
          "updated": "2026-04-22",
          "url": "https://sklvc.atlassian.net/browse/HECO-3223"
        },
        {
          "key": "HECO-3265",
          "summary": "[SIM] - [MODEL] - Beta Wheelbase URDF Bringup",
          "status": "In Progress",
          "assignee": "Luke Bierbaum",
          "updated": "2026-04-21",
          "url": "https://sklvc.atlassian.net/browse/HECO-3265"
        },
        {
          "key": "HECO-1640",
          "summary": "A/B Immutable OS Images",
          "status": "In Progress",
          "assignee": "Brian Ginebaugh",
          "updated": "2026-04-20",
          "url": "https://sklvc.atlassian.net/browse/HECO-1640"
        },
        {
          "key": "HECO-3210",
          "summary": "mjviser-based WBC evaluation framework",
          "status": "In Progress",
          "assignee": "Andy Park",
          "updated": "2026-04-16",
          "url": "https://sklvc.atlassian.net/browse/HECO-3210"
        },
        {
          "key": "HECO-3116",
          "summary": "[Health Reporting] Fault service and module health fixes",
          "status": "In Progress",
          "assignee": "Anubhav Dogra",
          "updated": "2026-04-14",
          "url": "https://sklvc.atlassian.net/browse/HECO-3116"
        },
        {
          "key": "HECO-3012",
          "summary": "[Wheeled base] Document features available in Alpha Wheeled base",
          "status": "In Progress",
          "assignee": "Muhammad Awais Rafique",
          "updated": "2026-03-27",
          "url": "https://sklvc.atlassian.net/browse/HECO-3012"
        },
        {
          "key": "HECO-3011",
          "summary": "[Wheeled base] Understand and document Alpha Wheeledbase Software setup",
          "status": "In Progress",
          "assignee": "Muhammad Awais Rafique",
          "updated": "2026-03-27",
          "url": "https://sklvc.atlassian.net/browse/HECO-3011"
        },
        {
          "key": "HECO-3010",
          "summary": "[Wheeled base] Understand and document Alpha Wheelbase Hardware",
          "status": "In Progress",
          "assignee": "Muhammad Awais Rafique",
          "updated": "2026-03-27",
          "url": "https://sklvc.atlassian.net/browse/HECO-3010"
        },
        {
          "key": "HECO-2179",
          "summary": "WBC RL - our first policy",
          "status": "In Progress",
          "assignee": "Saeid Samadi",
          "updated": "2026-03-11",
          "url": "https://sklvc.atlassian.net/browse/HECO-2179"
        },
        {
          "key": "HECO-2852",
          "summary": "UMI Fixes, bugs, and reliability backlog",
          "status": "In Progress",
          "assignee": "Ricardo Delfin",
          "updated": "2026-03-10",
          "url": "https://sklvc.atlassian.net/browse/HECO-2852"
        },
        {
          "key": "HECO-2001",
          "summary": "Flexion testing of RL policy on wheeled Alpha",
          "status": "In Progress",
          "assignee": "Saeid Samadi",
          "updated": "2026-02-16",
          "url": "https://sklvc.atlassian.net/browse/HECO-2001"
        },
        {
          "key": "HECO-2009",
          "summary": "Add support for UMI Gripper data collection on device",
          "status": "In Progress",
          "assignee": "Ricardo Delfin",
          "updated": "2026-02-06",
          "url": "https://sklvc.atlassian.net/browse/HECO-2009"
        },
        {
          "key": "HECO-2148",
          "summary": "Controller Improvements",
          "status": "In Progress",
          "assignee": null,
          "updated": "2026-01-05",
          "url": "https://sklvc.atlassian.net/browse/HECO-2148"
        },
        {
          "key": "HECO-1419",
          "summary": "Robot Observability ",
          "status": "In Progress",
          "assignee": "Cody Griffin",
          "updated": "2025-12-22",
          "url": "https://sklvc.atlassian.net/browse/HECO-1419"
        },
        {
          "key": "HECO-1910",
          "summary": "Platform Software: Toil work",
          "status": "In Progress",
          "assignee": "Ricardo Delfin",
          "updated": "2025-11-20",
          "url": "https://sklvc.atlassian.net/browse/HECO-1910"
        },
        {
          "key": "HECO-1029",
          "summary": "[SIM] - Organisational",
          "status": "In Progress",
          "assignee": "Dmitriy Shingarey",
          "updated": "2025-11-13",
          "url": "https://sklvc.atlassian.net/browse/HECO-1029"
        },
        {
          "key": "HECO-1719",
          "summary": "Deployment pipeline improvent",
          "status": "In Progress",
          "assignee": "Gourav Wadhwa",
          "updated": "2025-11-07",
          "url": "https://sklvc.atlassian.net/browse/HECO-1719"
        },
        {
          "key": "HECO-1357",
          "summary": "Core Control Plane",
          "status": "In Progress",
          "assignee": "Cody Griffin",
          "updated": "2025-10-27",
          "url": "https://sklvc.atlassian.net/browse/HECO-1357"
        },
        {
          "key": "HECO-905",
          "summary": "[Schaeffler PoC] :: in-house demo issue diagnostics",
          "status": "In Progress",
          "assignee": "Leo Lesin",
          "updated": "2025-07-16",
          "url": "https://sklvc.atlassian.net/browse/HECO-905"
        },
        {
          "key": "HECO-4163",
          "summary": "[PAM handle] Beta repositioning for PAM handle",
          "status": "Backlog",
          "assignee": "Anubhav Dogra",
          "updated": "2026-07-24",
          "url": "https://sklvc.atlassian.net/browse/HECO-4163"
        },
        {
          "key": "HECO-3149",
          "summary": "Exteroceptive WBC - obstacle avoidance",
          "status": "Backlog",
          "assignee": "Andy Park",
          "updated": "2026-07-23",
          "url": "https://sklvc.atlassian.net/browse/HECO-3149"
        },
        {
          "key": "HECO-3556",
          "summary": "Implement 3D task space control for tote primitive",
          "status": "Backlog",
          "assignee": "Andy Park",
          "updated": "2026-07-23",
          "url": "https://sklvc.atlassian.net/browse/HECO-3556"
        },
        {
          "key": "HECO-4496",
          "summary": "Avoid accessing configurations where brake can't hold the robot",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-07-23",
          "url": "https://sklvc.atlassian.net/browse/HECO-4496"
        },
        {
          "key": "HECO-4478",
          "summary": "Avoid accessing configurations where brake can't hold the robot",
          "status": "Backlog",
          "assignee": "Andy Park",
          "updated": "2026-07-22",
          "url": "https://sklvc.atlassian.net/browse/HECO-4478"
        },
        {
          "key": "HECO-4348",
          "summary": "Synapse Wire Format and Transport Correctness",
          "status": "Backlog",
          "assignee": "Aleksei Chernikhovskii",
          "updated": "2026-07-22",
          "url": "https://sklvc.atlassian.net/browse/HECO-4348"
        },
        {
          "key": "HECO-4441",
          "summary": "Synapse RPC vs Streaming language semantics",
          "status": "Backlog",
          "assignee": "Aleksei Chernikhovskii",
          "updated": "2026-07-21",
          "url": "https://sklvc.atlassian.net/browse/HECO-4441"
        },
        {
          "key": "HECO-4225",
          "summary": "Boundend end-effector twist wrt base_link (base twist included)",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-07-16",
          "url": "https://sklvc.atlassian.net/browse/HECO-4225"
        },
        {
          "key": "HECO-4349",
          "summary": "Add first-class bounded arrays to the schema toolchain",
          "status": "Backlog",
          "assignee": "Aleksei Chernikhovskii",
          "updated": "2026-07-16",
          "url": "https://sklvc.atlassian.net/browse/HECO-4349"
        },
        {
          "key": "HECO-4351",
          "summary": "Specify firmware update and align the Rust/TFTP workflow",
          "status": "Backlog",
          "assignee": "Aleksei Chernikhovskii",
          "updated": "2026-07-16",
          "url": "https://sklvc.atlassian.net/browse/HECO-4351"
        },
        {
          "key": "HECO-4411",
          "summary": "Button on wheeled base for robot repositioning",
          "status": "Backlog",
          "assignee": "Anubhav Dogra",
          "updated": "2026-07-16",
          "url": "https://sklvc.atlassian.net/browse/HECO-4411"
        },
        {
          "key": "HECO-3443",
          "summary": "[PAM handle] Strain Gauge to Base Twist",
          "status": "Backlog",
          "assignee": "Anubhav Dogra",
          "updated": "2026-07-16",
          "url": "https://sklvc.atlassian.net/browse/HECO-3443"
        },
        {
          "key": "HECO-4203",
          "summary": "Use PD control at ENCOS level - perf improvements?",
          "status": "Backlog",
          "assignee": "Thomas Corberes",
          "updated": "2026-07-15",
          "url": "https://sklvc.atlassian.net/browse/HECO-4203"
        },
        {
          "key": "HECO-4219",
          "summary": "Reliable Joint Torque Feedback",
          "status": "Backlog",
          "assignee": "Gregory Michaud",
          "updated": "2026-07-15",
          "url": "https://sklvc.atlassian.net/browse/HECO-4219"
        },
        {
          "key": "HECO-4353",
          "summary": "Synapse Standard and Non-Common Classes",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-07-15",
          "url": "https://sklvc.atlassian.net/browse/HECO-4353"
        },
        {
          "key": "HECO-4352",
          "summary": "Synapse Protocol Evolution, Security, and Documentation",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-07-15",
          "url": "https://sklvc.atlassian.net/browse/HECO-4352"
        },
        {
          "key": "HECO-4350",
          "summary": "Add a cross-implementation protocol conformance suite",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-07-15",
          "url": "https://sklvc.atlassian.net/browse/HECO-4350"
        },
        {
          "key": "HECO-2163",
          "summary": "Control stack refactoring",
          "status": "Backlog",
          "assignee": "Anubhav Dogra",
          "updated": "2026-07-15",
          "url": "https://sklvc.atlassian.net/browse/HECO-2163"
        },
        {
          "key": "HECO-4346",
          "summary": "Dynamixel temperature sensors early warning",
          "status": "Backlog",
          "assignee": "Anubhav Dogra",
          "updated": "2026-07-15",
          "url": "https://sklvc.atlassian.net/browse/HECO-4346"
        },
        {
          "key": "HECO-4171",
          "summary": "Differential mechanism - work in actuator space",
          "status": "Backlog",
          "assignee": "Thomas Corberes",
          "updated": "2026-07-14",
          "url": "https://sklvc.atlassian.net/browse/HECO-4171"
        },
        {
          "key": "HECO-4057",
          "summary": "Non-linear kt torque2current for ENCOS",
          "status": "Backlog",
          "assignee": "Thomas Corberes",
          "updated": "2026-07-14",
          "url": "https://sklvc.atlassian.net/browse/HECO-4057"
        },
        {
          "key": "HECO-4293",
          "summary": "Factory Software \u2014 Production Hardening & Scale",
          "status": "Backlog",
          "assignee": null,
          "updated": "2026-07-10",
          "url": "https://sklvc.atlassian.net/browse/HECO-4293"
        },
        {
          "key": "HECO-3643",
          "summary": "Factory Software \u2014 MVP",
          "status": "Backlog",
          "assignee": "Blake Lieber",
          "updated": "2026-07-10",
          "url": "https://sklvc.atlassian.net/browse/HECO-3643"
        }
      ],
      "total_issues": 134,
      "next_release": {
        "id": "11734",
        "name": "2026.08.05",
        "released": false,
        "release_date": "2026-08-05",
        "description": ""
      }
    }
  },
  "cloudflare": {
    "updated": "2026-07-25T08:25:45.256585",
    "account": {
      "id": "1b5eab8e2dbe19dd0d46495e90f31c6d",
      "name": "Itmanager@thehumanoid.ai's Account",
      "type": "standard"
    },
    "r2": {
      "buckets": [
        {
          "name": "ego4d-v2-packed",
          "creationDate": "2026-03-26T11:45:04.823Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 7880620725867,
          "metadataSize": 4958,
          "objectCount": 155,
          "uploadCount": 0
        },
        {
          "name": "hm-rainbow-mount",
          "creationDate": "2026-02-09T12:17:31.562Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 31656600648631,
          "metadataSize": 13919711,
          "objectCount": 174686,
          "uploadCount": 953
        },
        {
          "name": "hmnd-backup",
          "creationDate": "2026-03-07T11:48:30.895Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 29326621650709,
          "metadataSize": 337495461,
          "objectCount": 4159339,
          "uploadCount": 0
        },
        {
          "name": "hmnd-bosch-exchange",
          "creationDate": "2026-06-03T10:48:38.528Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 0,
          "metadataSize": 0,
          "objectCount": 0,
          "uploadCount": 0
        },
        {
          "name": "hmnd-checkpoints",
          "creationDate": "2026-03-28T09:09:16.183Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 9743067441958,
          "metadataSize": 132346,
          "objectCount": 6392,
          "uploadCount": 1
        },
        {
          "name": "hmnd-composed-training-configs",
          "creationDate": "2026-06-24T15:05:27.808Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 241473799019,
          "metadataSize": 1878,
          "objectCount": 76,
          "uploadCount": 0
        },
        {
          "name": "hmnd-dataset-hub",
          "creationDate": "2026-02-11T13:26:18.581Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 83785157180603,
          "metadataSize": 2646741694,
          "objectCount": 60815476,
          "uploadCount": 168
        },
        {
          "name": "hmnd-microsoft-exchange",
          "creationDate": "2026-04-10T23:15:23.696Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 81804027803,
          "metadataSize": 28710,
          "objectCount": 2049,
          "uploadCount": 0
        },
        {
          "name": "hmnd-miraxis-exchange",
          "creationDate": "2026-07-08T14:34:58.762Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 2758794420,
          "metadataSize": 163,
          "objectCount": 16,
          "uploadCount": 0
        },
        {
          "name": "hmnd-ml-fsx-lustre-dev-eu-west-2",
          "creationDate": "2026-03-09T17:58:28.735Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 29974925644,
          "metadataSize": 173,
          "objectCount": 4,
          "uploadCount": 1
        },
        {
          "name": "hmnd-nvidia-exchange",
          "creationDate": "2026-04-07T14:54:29.499Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 81553764328,
          "metadataSize": 28654,
          "objectCount": 2047,
          "uploadCount": 0
        },
        {
          "name": "hmnd-partner-ingest",
          "creationDate": "2026-04-15T13:27:04.290Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 102384616290707,
          "metadataSize": 101500566,
          "objectCount": 2537102,
          "uploadCount": 0
        },
        {
          "name": "hmnd-sentientx-exchange",
          "creationDate": "2026-04-10T13:07:44.438Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 11451506448453,
          "metadataSize": 4070865,
          "objectCount": 111482,
          "uploadCount": 865
        },
        {
          "name": "manipulation-models",
          "creationDate": "2026-04-29T13:24:24.888Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 45332807449182,
          "metadataSize": 2627086,
          "objectCount": 60042,
          "uploadCount": 2
        },
        {
          "name": "sfed-source",
          "creationDate": "2026-05-26T15:47:56.274Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 130018246656,
          "metadataSize": 645659,
          "objectCount": 16938,
          "uploadCount": 0
        },
        {
          "name": "sfed-target",
          "creationDate": "2026-05-22T17:50:36.404Z",
          "location": "",
          "storageClass": "",
          "payloadSize": 655057289344,
          "metadataSize": 390532,
          "objectCount": 33493,
          "uploadCount": 0
        }
      ],
      "bucketCount": 16,
      "totalPayloadSize": 322783638683324,
      "totalObjectCount": 67919297,
      "totalMetadataSize": 3107588456
    },
    "zones": [
      {
        "id": "01d08fa65a3988c8492bd67edfd824e1",
        "name": "hmnd-connect.com",
        "status": "active",
        "type": "full",
        "paused": false,
        "nameServers": [
          "alan.ns.cloudflare.com",
          "holly.ns.cloudflare.com"
        ],
        "plan": "Free Website",
        "records": [],
        "recordCount": 0
      }
    ],
    "tunnels": [],
    "workers": [],
    "pages": [],
    "d1_databases": [],
    "kv_namespaces": []
  },
  "vancouver_probe": {
    "source": "vancouver-office",
    "updated": "2026-03-22T17:34:01Z",
    "target": "sklrobotics.cloud.teamcenter.com",
    "dns": {
      "answer_ip": "3.120.49.142",
      "query_ms": 7
    },
    "ping": {
      "avg_ms": 0,
      "min_ms": 0,
      "max_ms": 0,
      "loss_pct": 100,
      "icmp_blocked": true
    },
    "endpoints": [
      {
        "endpoint": "/tc",
        "dns_ms": 11.6,
        "tcp_ms": 1171.2,
        "tls_ms": 598.3,
        "server_ms": 452.7,
        "ttfb_ms": 2233.8,
        "total_ms": 2234.0,
        "http_code": 404,
        "bytes": 759,
        "remote_ip": "3.120.49.142"
      },
      {
        "endpoint": "/awc",
        "dns_ms": 9.7,
        "tcp_ms": 147.0,
        "tls_ms": 154.8,
        "server_ms": 329.6,
        "ttfb_ms": 641.1,
        "total_ms": 641.4,
        "http_code": 200,
        "bytes": 711,
        "remote_ip": "3.120.49.142"
      },
      {
        "endpoint": "/awc/loginservice/sa",
        "dns_ms": 9.8,
        "tcp_ms": 147.2,
        "tls_ms": 763.1,
        "server_ms": 310.7,
        "ttfb_ms": 1230.8,
        "total_ms": 1231.0,
        "http_code": 404,
        "bytes": 155,
        "remote_ip": "63.181.124.135"
      }
    ],
    "lan": {
      "gateway": "172.30.128.1",
      "gateway_avg_ms": 0.529,
      "gateway_jitter_ms": 0.35,
      "gateway_loss_pct": 0,
      "dns_resolve_ms": 19,
      "local_baseline_ms": 30.4,
      "net_type": "ethernet"
    },
    "burst": {
      "requests": 10,
      "connection_reuse": true,
      "first_ttfb_ms": 783.1,
      "avg_ttfb_ms": 373.4,
      "min_ttfb_ms": 302.4,
      "max_ttfb_ms": 783.1,
      "reuse_ttfb_ms": 369.3
    },
    "mtr": [
      {
        "hop": 1,
        "host": "172.30.128.1",
        "asn": "AS???",
        "rdns": "",
        "avg_ms": 0.8,
        "best_ms": 0.5,
        "worst_ms": 1.1,
        "loss_pct": 0.0
      },
      {
        "hop": 2,
        "host": "10.167.56.1",
        "asn": "AS???",
        "rdns": "",
        "avg_ms": 3.2,
        "best_ms": 2.7,
        "worst_ms": 3.7,
        "loss_pct": 0.0
      },
      {
        "hop": 3,
        "host": "97.111.11.225",
        "asn": "AS812",
        "rdns": "",
        "avg_ms": 4.3,
        "best_ms": 3.2,
        "worst_ms": 5.5,
        "loss_pct": 0.0
      },
      {
        "hop": 4,
        "host": "209.148.225.93",
        "asn": "AS812",
        "rdns": "",
        "avg_ms": 10.6,
        "best_ms": 4.1,
        "worst_ms": 35.4,
        "loss_pct": 0.0
      },
      {
        "hop": 5,
        "host": "???",
        "asn": "AS???",
        "rdns": "",
        "avg_ms": 0.0,
        "best_ms": 0.0,
        "worst_ms": 0.0,
        "loss_pct": 100.0
      },
      {
        "hop": 6,
        "host": "66.163.76.66",
        "asn": "AS6327",
        "rdns": "rc1wt-be90-1.wa.shawcable.net",
        "avg_ms": 29.6,
        "best_ms": 7.4,
        "worst_ms": 207.0,
        "loss_pct": 0.0
      },
      {
        "hop": 7,
        "host": "213.248.67.224",
        "asn": "AS1299",
        "rdns": "sea-b1-link.ip.twelve99.net",
        "avg_ms": 7.6,
        "best_ms": 7.1,
        "worst_ms": 8.2,
        "loss_pct": 0.0
      },
      {
        "hop": 8,
        "host": "62.115.132.154",
        "asn": "AS1299",
        "rdns": "chi-bb2-link.ip.twelve99.net",
        "avg_ms": 48.3,
        "best_ms": 47.5,
        "worst_ms": 49.2,
        "loss_pct": 0.0
      },
      {
        "hop": 9,
        "host": "62.115.132.134",
        "asn": "AS1299",
        "rdns": "ewr-bb2-link.ip.twelve99.net",
        "avg_ms": 64.6,
        "best_ms": 63.8,
        "worst_ms": 65.9,
        "loss_pct": 0.0
      },
      {
        "hop": 10,
        "host": "62.115.139.247",
        "asn": "AS1299",
        "rdns": "ldn-bb2-link.ip.twelve99.net",
        "avg_ms": 131.5,
        "best_ms": 130.7,
        "worst_ms": 132.0,
        "loss_pct": 0.0
      },
      {
        "hop": 11,
        "host": "62.115.112.63",
        "asn": "AS1299",
        "rdns": "slou-b2-link.ip.twelve99.net",
        "avg_ms": 134.0,
        "best_ms": 131.2,
        "worst_ms": 143.6,
        "loss_pct": 0.0
      },
      {
        "hop": 12,
        "host": "???",
        "asn": "AS???",
        "rdns": "",
        "avg_ms": 0.0,
        "best_ms": 0.0,
        "worst_ms": 0.0,
        "loss_pct": 100.0
      }
    ],
    "trends": {
      "tc_ttfb": [
        620.0,
        705.5,
        712.4,
        627.3,
        632.4,
        703.9,
        1283.5,
        632.2,
        631.3,
        1388.6,
        711.7,
        631.3,
        825.4,
        1229.0,
        1403.1,
        820.1,
        1189.6,
        829.3,
        633.7,
        665.7,
        632.5,
        648.1,
        626.2,
        875.6,
        1209.9,
        1246.2,
        1435.1,
        634.2,
        1409.4,
        651.7,
        1243.5,
        782.9,
        633.5,
        705.1,
        1434.3,
        812.3,
        828.4,
        1344.9,
        1209.8,
        804.3,
        627.0,
        808.0,
        1206.0,
        816.0,
        997.1,
        822.1,
        634.6,
        634.6,
        780.9,
        631.0,
        638.3,
        623.1,
        1087.0,
        965.6,
        638.7,
        1402.7,
        785.9,
        622.0,
        629.2,
        827.4,
        707.4,
        627.2,
        631.3,
        630.1,
        1383.0,
        634.5,
        618.9,
        618.8,
        628.3,
        628.0,
        631.7,
        630.6,
        703.9,
        781.1,
        632.7,
        971.1,
        638.0,
        630.3,
        631.4,
        820.3,
        633.9,
        625.4,
        623.9,
        808.9,
        631.3,
        632.7,
        812.0,
        1643.4,
        1394.3,
        711.9,
        810.8,
        630.4,
        636.0,
        638.9,
        821.4,
        1249.9,
        963.2,
        816.8,
        1398.6,
        818.2,
        699.9,
        619.7,
        819.5,
        634.7,
        777.1,
        829.7,
        639.7,
        831.3,
        963.5,
        629.9,
        633.0,
        629.2,
        630.8,
        818.3,
        629.5,
        631.9,
        1819.1,
        629.5,
        778.0,
        633.2,
        812.0,
        616.6,
        635.1,
        696.8,
        966.3,
        784.2,
        619.9,
        824.7,
        703.8,
        1242.6,
        634.2,
        631.5,
        620.0,
        1187.4,
        823.1,
        627.2,
        958.2,
        974.0,
        815.3,
        639.5,
        638.0,
        622.3,
        1419.6,
        820.3,
        628.8,
        1559.7,
        621.3,
        701.3,
        630.0,
        629.5,
        624.8,
        627.7,
        632.7,
        630.5,
        1273.5,
        736.6,
        1401.9,
        630.8,
        635.2,
        1933.5,
        930.7,
        631.6,
        635.4,
        630.4,
        626.9,
        637.8,
        619.3,
        702.3,
        626.1,
        706.9,
        816.0,
        953.4,
        634.4,
        629.2,
        817.0,
        631.6,
        633.5,
        779.6,
        629.4,
        641.0,
        641.9,
        638.2,
        628.3,
        1246.3,
        624.7,
        627.1,
        617.1,
        635.7,
        627.1,
        1235.1,
        632.4,
        805.4,
        811.2,
        1586.3,
        922.0,
        964.8,
        618.7,
        2458.5,
        623.0,
        1376.8,
        623.0,
        815.4,
        1191.8,
        1242.2,
        638.0,
        996.9,
        625.5,
        808.0,
        631.5,
        915.9,
        678.5,
        1783.4,
        911.6,
        632.1,
        641.4,
        714.8,
        808.5,
        626.0,
        620.7,
        657.5,
        774.6,
        627.1,
        1248.3,
        1855.3,
        628.6,
        642.3,
        621.7,
        710.8,
        1374.3,
        624.0,
        632.2,
        617.3,
        634.2,
        629.2,
        783.6,
        619.4,
        702.8,
        635.6,
        1638.7,
        820.0,
        619.3,
        701.2,
        630.8,
        1270.9,
        1203.1,
        632.9,
        808.0,
        818.4,
        709.0,
        628.5,
        631.8,
        1939.3,
        921.6,
        777.0,
        624.4,
        630.5,
        622.5,
        819.4,
        619.2,
        633.8,
        916.3,
        618.4,
        630.7,
        1674.7,
        894.2,
        652.9,
        621.3,
        1646.3,
        811.5,
        870.3,
        633.2,
        2354.3,
        827.9,
        626.4,
        706.9,
        632.2,
        624.0,
        633.0,
        811.0,
        779.6,
        1946.8,
        620.4,
        967.7,
        1258.1,
        1523.2,
        628.9,
        636.4,
        811.4,
        1219.9,
        625.7,
        629.3,
        625.8,
        829.8,
        808.4,
        790.6,
        822.4,
        694.9,
        635.4,
        632.5,
        634.4,
        633.1,
        620.3,
        637.2,
        629.3,
        624.4,
        1388.4,
        628.3,
        821.2,
        823.3,
        634.1,
        620.4,
        1926.0,
        635.2,
        2303.5,
        626.5,
        1764.0,
        917.5,
        626.0,
        621.2,
        911.9,
        625.7,
        639.3,
        1016.2,
        1260.7,
        624.1,
        634.8,
        1377.7,
        625.3,
        796.4,
        715.7,
        639.6,
        632.1,
        630.4,
        623.9,
        698.8,
        630.0,
        614.2,
        706.8,
        821.0,
        628.6,
        628.9,
        814.9,
        631.5,
        628.8,
        625.6,
        699.2,
        1371.4,
        631.5,
        809.2,
        1267.4,
        629.6,
        1396.4,
        709.4,
        819.2,
        630.6,
        964.1,
        810.8,
        626.2,
        634.5,
        957.5,
        1651.1,
        635.1,
        722.5,
        655.3,
        815.8,
        962.4,
        765.4,
        623.3,
        1399.1,
        632.5,
        868.9,
        628.1,
        818.5,
        1205.8,
        2142.8,
        817.9,
        620.8,
        779.1,
        802.7,
        641.2,
        630.4,
        720.4,
        628.3,
        631.1,
        629.7,
        641.5,
        631.2,
        1432.7,
        628.0,
        926.1,
        714.3,
        628.8,
        696.8,
        635.7,
        632.1,
        820.3,
        632.2,
        1956.0,
        1410.9,
        830.7,
        637.7,
        705.4,
        816.7,
        636.9,
        642.3,
        917.5,
        809.6,
        951.8,
        1938.6,
        1223.4,
        627.7,
        809.0,
        636.8,
        829.5,
        647.3,
        709.6,
        619.4,
        659.2,
        626.6,
        930.6,
        637.0,
        1458.1,
        639.6,
        822.4,
        980.4,
        823.6,
        817.7,
        634.6,
        817.1,
        627.3,
        1243.4,
        805.8,
        851.2,
        970.1,
        635.4,
        623.6,
        806.4,
        925.7,
        1829.7,
        628.4,
        633.0,
        619.4,
        627.0,
        1207.4,
        633.5,
        644.6,
        627.4,
        627.0,
        624.1,
        966.0,
        827.6,
        1200.7,
        783.0,
        617.4,
        631.4,
        629.6,
        773.6,
        636.9,
        632.9,
        638.1,
        635.5,
        707.8,
        919.6,
        828.2,
        805.3,
        1409.6,
        627.4,
        628.8,
        626.0,
        824.0,
        1253.3,
        634.3,
        1082.5,
        629.1,
        820.0,
        631.5,
        622.6,
        620.7,
        876.9,
        624.5,
        639.2,
        820.8,
        970.4,
        1577.2,
        629.4,
        630.6,
        624.9,
        1421.0,
        1202.4,
        822.4,
        824.9,
        622.1,
        695.3,
        1560.0,
        631.0,
        633.6,
        1641.2,
        632.3,
        1241.3,
        630.6,
        1001.0,
        1397.2,
        637.2,
        628.6,
        2305.3,
        1386.8,
        771.6,
        975.9,
        633.1,
        630.7,
        704.0,
        779.0,
        776.2,
        654.1,
        649.9,
        1273.5,
        835.4,
        651.1,
        850.7,
        1279.5,
        823.1,
        652.9,
        1269.3,
        649.5,
        916.3,
        822.8,
        2138.6,
        2070.5,
        705.2,
        990.8,
        1620.3,
        843.8,
        654.6,
        845.1,
        842.9,
        839.0,
        831.9,
        706.6,
        625.4,
        706.7,
        1246.0,
        633.6,
        717.2,
        645.9,
        662.9,
        1258.1,
        641.0,
        844.1,
        842.3,
        651.9,
        864.2,
        641.0,
        643.7,
        627.0,
        1939.9,
        632.5,
        640.9,
        830.7,
        646.1,
        659.3,
        641.4,
        1441.3,
        2165.5,
        1254.4,
        997.1,
        1297.3,
        636.2,
        649.3,
        656.1,
        643.9,
        1303.5,
        635.2,
        647.1,
        837.5,
        1036.9,
        654.6,
        618.9,
        774.9,
        1192.1,
        629.2,
        627.1,
        914.2,
        874.6,
        650.8,
        623.5,
        798.3,
        1565.3,
        636.0,
        1462.0,
        1402.8,
        661.8,
        1243.6,
        698.7,
        637.9,
        633.4,
        637.4,
        835.9,
        627.1,
        636.5,
        617.6,
        633.5,
        623.4,
        1554.7,
        630.5,
        625.2,
        780.8,
        631.2,
        636.2,
        713.1,
        814.9,
        1218.6,
        816.4,
        1400.8,
        632.4,
        641.0,
        629.0,
        1360.9,
        817.1,
        778.1,
        635.9,
        622.4,
        1192.1,
        627.3,
        806.5,
        632.1,
        836.3,
        622.8,
        775.4,
        818.5,
        1385.4,
        622.2,
        697.1,
        821.6,
        637.1,
        2117.5,
        780.5,
        630.6,
        640.3,
        629.2,
        815.9,
        813.2,
        810.6,
        619.4,
        816.2,
        1447.4,
        1207.9,
        618.5,
        627.8,
        634.8,
        820.5,
        819.0,
        621.9,
        636.8,
        634.3,
        628.8,
        623.8,
        625.5,
        628.7,
        624.5,
        619.0,
        697.5,
        628.2,
        632.7,
        1226.7,
        815.8,
        708.9,
        623.6,
        625.2,
        633.0,
        1159.1,
        801.4,
        622.9,
        2321.3,
        696.2,
        774.9,
        630.5,
        916.7,
        2526.6,
        954.9,
        2062.3,
        724.1,
        813.8,
        809.0,
        923.7,
        775.5,
        635.0,
        1238.3,
        1222.9,
        620.6,
        635.7,
        625.9,
        629.8,
        812.5,
        770.1,
        673.1,
        693.8,
        632.8,
        700.3,
        617.5,
        1408.2,
        622.1,
        807.8,
        1247.5,
        624.4,
        617.2,
        634.3,
        628.3,
        819.0,
        625.2,
        622.0,
        619.0,
        1233.4,
        1408.9,
        635.4,
        625.9,
        769.0,
        620.1,
        629.9,
        634.0,
        2233.8
      ],
      "tc_tcp": [
        147.4,
        168.1,
        167.6,
        146.2,
        147.9,
        166.6,
        148.9,
        148.2,
        147.4,
        148.1,
        167.7,
        148.0,
        147.9,
        149.1,
        147.8,
        147.9,
        147.6,
        148.1,
        148.0,
        147.5,
        148.0,
        148.5,
        146.5,
        167.3,
        147.1,
        148.2,
        147.0,
        148.1,
        147.0,
        148.2,
        147.0,
        149.0,
        147.3,
        167.1,
        147.2,
        147.9,
        148.8,
        147.0,
        148.3,
        146.2,
        148.1,
        146.8,
        147.2,
        146.5,
        146.8,
        148.7,
        148.5,
        147.2,
        147.7,
        146.6,
        148.8,
        150.5,
        168.2,
        146.8,
        148.7,
        147.2,
        148.1,
        147.6,
        148.6,
        146.4,
        192.2,
        148.8,
        146.7,
        147.9,
        147.5,
        147.5,
        147.1,
        147.0,
        147.8,
        146.8,
        147.5,
        148.0,
        167.4,
        148.6,
        147.3,
        149.3,
        147.5,
        148.2,
        148.8,
        147.8,
        147.5,
        148.4,
        146.2,
        147.0,
        147.3,
        148.7,
        147.6,
        147.0,
        147.8,
        166.7,
        147.8,
        148.1,
        148.2,
        148.7,
        147.7,
        147.6,
        147.7,
        147.0,
        147.7,
        147.6,
        165.9,
        147.9,
        147.6,
        148.1,
        147.4,
        147.7,
        164.3,
        148.8,
        147.9,
        147.3,
        148.0,
        147.0,
        148.3,
        147.3,
        147.7,
        147.5,
        167.6,
        146.8,
        148.7,
        146.6,
        147.9,
        148.0,
        147.0,
        167.3,
        147.6,
        148.6,
        147.6,
        148.4,
        167.4,
        148.3,
        148.5,
        147.8,
        149.6,
        146.9,
        148.5,
        147.3,
        147.4,
        147.5,
        147.8,
        147.7,
        147.6,
        148.4,
        167.2,
        148.7,
        148.3,
        168.0,
        148.0,
        166.9,
        148.0,
        148.3,
        147.3,
        147.7,
        148.9,
        147.0,
        147.7,
        167.5,
        167.2,
        147.4,
        147.5,
        1150.7,
        167.7,
        147.9,
        148.4,
        148.0,
        148.1,
        148.8,
        147.8,
        167.8,
        147.8,
        166.7,
        146.7,
        147.9,
        148.6,
        147.2,
        148.1,
        148.0,
        147.6,
        147.7,
        147.3,
        148.9,
        147.6,
        148.0,
        147.0,
        148.5,
        146.9,
        147.5,
        147.4,
        147.0,
        147.6,
        147.8,
        147.7,
        147.1,
        148.1,
        166.4,
        167.0,
        148.0,
        148.6,
        148.7,
        148.3,
        147.5,
        148.5,
        147.1,
        148.0,
        147.8,
        147.2,
        148.1,
        147.3,
        147.6,
        147.5,
        166.7,
        148.0,
        1159.1,
        167.1,
        148.1,
        148.4,
        167.1,
        147.4,
        146.9,
        148.5,
        147.3,
        148.0,
        148.4,
        148.8,
        1172.6,
        147.9,
        147.9,
        148.3,
        166.6,
        148.4,
        148.1,
        146.9,
        147.0,
        147.6,
        147.6,
        148.3,
        147.3,
        167.0,
        148.8,
        147.8,
        148.6,
        146.9,
        166.4,
        148.5,
        149.1,
        147.8,
        147.2,
        147.2,
        147.1,
        166.9,
        147.1,
        147.8,
        1166.4,
        166.7,
        147.9,
        147.2,
        148.1,
        148.5,
        148.9,
        147.7,
        148.8,
        167.9,
        147.5,
        147.3,
        147.6,
        148.1,
        147.0,
        147.1,
        1168.7,
        147.4,
        147.2,
        148.9,
        148.9,
        148.5,
        146.8,
        167.0,
        147.2,
        148.3,
        147.9,
        147.0,
        146.9,
        1167.8,
        147.4,
        147.2,
        147.2,
        147.2,
        148.0,
        147.6,
        147.4,
        148.0,
        146.9,
        146.6,
        147.9,
        147.6,
        148.3,
        148.5,
        147.5,
        166.6,
        148.1,
        147.3,
        148.1,
        149.0,
        147.3,
        147.5,
        147.5,
        148.2,
        149.6,
        148.2,
        147.6,
        148.3,
        148.6,
        146.9,
        1157.7,
        148.9,
        147.4,
        147.2,
        166.6,
        166.5,
        148.6,
        146.7,
        166.4,
        147.6,
        151.1,
        150.5,
        148.7,
        146.8,
        148.2,
        150.1,
        146.7,
        149.1,
        166.7,
        147.6,
        149.7,
        148.5,
        147.6,
        166.1,
        148.3,
        146.8,
        166.9,
        146.6,
        146.2,
        146.8,
        146.9,
        146.8,
        147.3,
        147.8,
        147.4,
        147.9,
        147.3,
        147.5,
        146.5,
        148.5,
        147.6,
        167.6,
        148.2,
        147.3,
        148.2,
        148.1,
        148.0,
        148.4,
        147.3,
        1170.2,
        147.6,
        167.7,
        148.0,
        147.4,
        146.8,
        147.8,
        147.0,
        146.5,
        148.5,
        166.6,
        147.4,
        147.1,
        147.8,
        1176.2,
        147.7,
        148.5,
        147.7,
        146.9,
        149.3,
        147.9,
        180.7,
        148.3,
        148.0,
        147.1,
        149.5,
        148.3,
        147.9,
        146.9,
        168.4,
        168.3,
        147.7,
        167.1,
        147.2,
        147.8,
        148.4,
        149.0,
        1179.3,
        148.2,
        147.3,
        147.8,
        165.9,
        148.2,
        147.8,
        147.5,
        166.9,
        147.8,
        147.4,
        1149.0,
        147.7,
        147.6,
        148.1,
        146.9,
        147.0,
        148.6,
        147.2,
        147.5,
        147.5,
        148.0,
        167.9,
        148.3,
        147.1,
        148.1,
        148.0,
        147.5,
        147.9,
        147.5,
        147.4,
        148.4,
        148.0,
        147.5,
        147.8,
        148.1,
        148.2,
        149.6,
        147.4,
        146.6,
        167.9,
        148.2,
        147.7,
        147.8,
        147.2,
        146.8,
        147.3,
        147.8,
        148.1,
        148.2,
        147.3,
        147.7,
        146.8,
        148.6,
        147.1,
        149.1,
        147.3,
        147.2,
        149.2,
        147.4,
        147.8,
        147.5,
        147.8,
        147.9,
        166.4,
        167.4,
        149.1,
        147.9,
        146.7,
        148.3,
        147.7,
        146.8,
        148.6,
        147.4,
        148.3,
        166.2,
        147.8,
        147.9,
        148.1,
        148.7,
        147.7,
        167.1,
        147.4,
        147.3,
        147.0,
        147.8,
        147.8,
        147.3,
        147.1,
        147.8,
        148.4,
        147.6,
        148.9,
        147.8,
        147.3,
        166.6,
        148.0,
        147.6,
        148.1,
        147.5,
        146.8,
        147.3,
        147.1,
        147.1,
        146.3,
        148.5,
        146.9,
        146.9,
        147.8,
        148.1,
        146.6,
        147.3,
        147.7,
        166.5,
        147.5,
        147.4,
        153.0,
        152.7,
        152.3,
        152.2,
        151.6,
        152.0,
        152.6,
        148.5,
        152.6,
        147.6,
        151.9,
        166.6,
        147.4,
        1150.7,
        1159.6,
        233.5,
        152.6,
        148.0,
        152.9,
        153.9,
        151.8,
        152.1,
        152.9,
        151.8,
        166.4,
        148.1,
        166.5,
        147.3,
        148.1,
        166.5,
        152.4,
        153.3,
        152.3,
        152.1,
        152.1,
        151.8,
        154.0,
        153.4,
        152.4,
        151.3,
        147.5,
        1164.6,
        147.8,
        152.2,
        151.6,
        152.2,
        151.7,
        152.7,
        152.8,
        1157.7,
        153.5,
        152.4,
        151.8,
        151.7,
        151.9,
        153.4,
        153.1,
        152.8,
        152.1,
        152.6,
        152.7,
        151.7,
        152.2,
        147.7,
        146.5,
        147.9,
        147.0,
        147.7,
        167.0,
        148.0,
        153.2,
        148.7,
        152.9,
        147.9,
        151.4,
        151.7,
        152.3,
        153.1,
        153.3,
        166.7,
        148.7,
        147.2,
        146.9,
        148.9,
        146.6,
        149.1,
        148.1,
        147.4,
        147.1,
        147.1,
        147.4,
        147.5,
        147.8,
        147.3,
        148.5,
        168.7,
        147.9,
        147.6,
        147.9,
        147.4,
        147.6,
        147.4,
        147.9,
        148.1,
        148.1,
        147.9,
        148.3,
        148.5,
        147.2,
        147.7,
        145.9,
        147.7,
        148.9,
        147.9,
        147.0,
        147.9,
        148.3,
        149.4,
        167.4,
        147.0,
        147.7,
        1154.1,
        147.8,
        147.7,
        147.5,
        146.7,
        148.0,
        147.6,
        147.7,
        146.9,
        148.8,
        146.4,
        148.3,
        147.0,
        147.3,
        146.9,
        147.7,
        147.8,
        147.7,
        148.5,
        147.2,
        147.8,
        147.1,
        148.6,
        147.7,
        147.4,
        147.4,
        167.3,
        148.9,
        147.4,
        147.8,
        147.3,
        167.2,
        150.4,
        149.0,
        147.6,
        147.8,
        147.3,
        147.1,
        147.6,
        167.1,
        147.2,
        147.1,
        166.8,
        1157.9,
        166.9,
        166.5,
        166.5,
        147.4,
        148.0,
        166.1,
        147.8,
        148.8,
        148.3,
        147.7,
        147.8,
        148.5,
        147.8,
        147.8,
        146.9,
        148.1,
        148.6,
        166.7,
        149.3,
        167.6,
        147.5,
        147.1,
        147.3,
        147.4,
        147.0,
        148.2,
        148.3,
        147.4,
        148.0,
        148.0,
        147.5,
        147.7,
        146.8,
        147.2,
        147.8,
        147.5,
        147.7,
        147.8,
        147.8,
        147.1,
        148.5,
        1171.2
      ],
      "tc_tls": [
        154.7,
        175.2,
        174.0,
        151.4,
        155.0,
        173.9,
        155.2,
        154.8,
        152.6,
        346.7,
        174.6,
        154.3,
        156.9,
        157.2,
        780.8,
        153.4,
        154.8,
        154.8,
        155.9,
        152.0,
        154.9,
        155.4,
        153.0,
        340.9,
        153.8,
        766.1,
        341.8,
        154.5,
        341.2,
        155.7,
        758.4,
        302.3,
        154.6,
        175.3,
        818.9,
        155.4,
        345.9,
        302.6,
        154.6,
        152.7,
        155.3,
        343.7,
        155.4,
        152.9,
        346.7,
        341.8,
        155.3,
        154.7,
        303.9,
        156.2,
        157.0,
        152.6,
        551.5,
        489.3,
        154.8,
        752.8,
        302.7,
        154.0,
        156.2,
        342.6,
        154.9,
        155.3,
        152.1,
        156.0,
        347.7,
        152.1,
        154.9,
        151.1,
        154.0,
        154.0,
        153.2,
        155.5,
        174.6,
        305.3,
        153.1,
        496.3,
        155.3,
        154.1,
        154.1,
        155.9,
        156.3,
        153.4,
        151.8,
        343.3,
        152.7,
        154.7,
        342.9,
        946.8,
        770.0,
        173.8,
        155.5,
        152.8,
        155.9,
        153.4,
        342.5,
        770.6,
        301.3,
        343.1,
        778.0,
        153.8,
        170.9,
        154.0,
        344.8,
        154.6,
        301.6,
        154.0,
        155.5,
        345.3,
        489.3,
        154.8,
        155.0,
        154.1,
        153.1,
        342.4,
        152.7,
        153.6,
        1081.5,
        153.8,
        302.9,
        154.0,
        154.8,
        154.6,
        155.3,
        176.2,
        495.1,
        303.2,
        154.1,
        342.7,
        173.1,
        765.5,
        155.8,
        154.3,
        152.9,
        152.8,
        156.7,
        151.8,
        305.4,
        301.5,
        151.6,
        154.2,
        155.5,
        153.5,
        171.6,
        346.2,
        158.0,
        866.8,
        153.8,
        173.6,
        156.4,
        156.3,
        152.2,
        155.0,
        153.8,
        156.6,
        156.3,
        173.2,
        876.3,
        154.4,
        154.8,
        451.1,
        175.9,
        154.9,
        155.4,
        155.1,
        154.3,
        157.3,
        154.7,
        172.7,
        154.5,
        172.8,
        340.1,
        302.0,
        156.0,
        154.8,
        155.1,
        155.0,
        154.1,
        303.0,
        154.6,
        154.7,
        155.5,
        155.2,
        152.2,
        771.3,
        154.3,
        154.2,
        153.9,
        154.8,
        154.5,
        757.3,
        155.5,
        342.5,
        154.7,
        895.0,
        385.5,
        301.8,
        154.9,
        494.3,
        156.7,
        154.0,
        152.6,
        341.4,
        498.7,
        154.0,
        155.8,
        490.4,
        155.4,
        154.9,
        155.8,
        389.8,
        154.9,
        302.2,
        388.6,
        154.6,
        159.1,
        175.7,
        151.8,
        153.1,
        154.4,
        154.0,
        302.8,
        156.2,
        153.2,
        342.7,
        156.3,
        154.7,
        155.2,
        174.3,
        304.7,
        153.8,
        155.3,
        152.9,
        154.5,
        154.5,
        301.8,
        154.5,
        176.3,
        156.3,
        948.8,
        343.1,
        153.5,
        172.5,
        155.3,
        155.3,
        154.3,
        155.2,
        341.7,
        154.6,
        173.2,
        154.7,
        154.1,
        448.3,
        387.1,
        301.7,
        155.2,
        155.4,
        155.8,
        344.0,
        156.0,
        155.6,
        174.6,
        153.1,
        155.0,
        154.6,
        347.1,
        153.3,
        153.1,
        155.9,
        154.2,
        153.6,
        154.9,
        1872.9,
        155.8,
        153.0,
        174.6,
        153.0,
        154.6,
        153.6,
        154.7,
        299.6,
        449.1,
        154.6,
        489.5,
        155.0,
        487.8,
        153.2,
        153.4,
        339.5,
        155.4,
        153.9,
        154.7,
        153.3,
        154.5,
        154.7,
        304.2,
        345.1,
        172.4,
        154.1,
        155.4,
        156.8,
        154.5,
        152.4,
        153.8,
        155.6,
        152.2,
        771.2,
        154.6,
        345.8,
        349.4,
        155.3,
        154.3,
        447.8,
        156.5,
        1689.6,
        152.7,
        1073.1,
        384.4,
        154.7,
        150.8,
        173.4,
        152.0,
        155.3,
        351.8,
        154.8,
        154.4,
        154.0,
        302.0,
        151.8,
        303.8,
        173.8,
        158.5,
        156.3,
        152.0,
        152.7,
        170.4,
        156.8,
        151.6,
        175.9,
        152.6,
        152.5,
        152.8,
        345.8,
        154.0,
        153.5,
        152.3,
        155.3,
        756.3,
        156.1,
        152.9,
        154.0,
        155.1,
        155.4,
        173.5,
        155.0,
        153.5,
        489.2,
        343.3,
        152.8,
        158.3,
        490.3,
        152.0,
        153.3,
        173.3,
        155.5,
        340.9,
        491.9,
        303.4,
        154.3,
        345.6,
        155.2,
        342.4,
        153.1,
        345.3,
        155.7,
        451.9,
        152.8,
        154.6,
        302.0,
        153.6,
        156.8,
        155.0,
        154.3,
        154.8,
        154.9,
        153.4,
        156.4,
        155.1,
        770.6,
        154.2,
        389.8,
        175.0,
        151.7,
        174.9,
        156.0,
        153.7,
        344.5,
        155.8,
        447.0,
        303.6,
        343.9,
        154.3,
        171.7,
        152.3,
        153.9,
        156.2,
        390.1,
        344.2,
        300.0,
        447.9,
        751.2,
        156.2,
        154.0,
        152.9,
        343.2,
        155.5,
        231.5,
        154.8,
        155.4,
        154.6,
        389.6,
        156.2,
        848.0,
        154.5,
        344.0,
        304.0,
        345.4,
        342.9,
        154.0,
        345.9,
        155.0,
        757.6,
        155.0,
        155.0,
        342.9,
        152.7,
        152.6,
        342.4,
        174.1,
        775.5,
        152.3,
        153.8,
        153.8,
        153.9,
        153.3,
        157.0,
        156.0,
        152.5,
        152.9,
        155.5,
        492.0,
        346.5,
        154.1,
        303.9,
        151.2,
        155.2,
        156.0,
        303.3,
        154.5,
        153.7,
        155.1,
        154.7,
        174.2,
        175.8,
        345.8,
        155.2,
        797.5,
        156.2,
        153.6,
        154.6,
        343.2,
        781.1,
        154.8,
        552.2,
        153.2,
        345.7,
        155.0,
        153.6,
        153.4,
        342.1,
        152.1,
        153.7,
        344.5,
        492.6,
        960.0,
        153.9,
        152.5,
        156.6,
        801.9,
        151.8,
        348.6,
        153.5,
        152.9,
        174.3,
        951.4,
        154.9,
        154.2,
        157.1,
        154.3,
        154.3,
        153.7,
        339.9,
        782.6,
        153.0,
        152.5,
        343.3,
        155.1,
        299.8,
        489.1,
        154.4,
        155.0,
        175.7,
        299.5,
        302.8,
        159.6,
        156.9,
        778.2,
        354.1,
        157.9,
        159.9,
        784.6,
        154.6,
        158.9,
        156.0,
        160.0,
        383.9,
        345.4,
        452.1,
        448.0,
        151.7,
        312.1,
        812.9,
        158.8,
        161.3,
        352.5,
        355.0,
        352.1,
        158.2,
        172.8,
        155.8,
        172.1,
        764.6,
        153.3,
        171.9,
        159.0,
        158.8,
        158.1,
        159.7,
        157.6,
        352.6,
        159.1,
        356.9,
        156.2,
        157.8,
        153.1,
        450.0,
        153.8,
        161.4,
        156.4,
        161.3,
        159.8,
        160.1,
        813.9,
        463.2,
        159.9,
        507.9,
        156.2,
        158.4,
        158.5,
        161.6,
        160.1,
        159.4,
        156.6,
        156.8,
        159.9,
        354.9,
        159.7,
        154.2,
        151.6,
        153.9,
        154.0,
        152.8,
        385.8,
        154.7,
        157.8,
        154.9,
        311.8,
        956.0,
        159.8,
        830.2,
        311.1,
        160.5,
        159.0,
        174.7,
        153.8,
        152.0,
        154.5,
        342.0,
        151.5,
        154.9,
        153.3,
        155.6,
        154.5,
        754.9,
        153.4,
        155.3,
        299.9,
        154.2,
        153.8,
        173.8,
        153.0,
        156.5,
        346.7,
        301.8,
        155.7,
        154.1,
        155.1,
        304.6,
        341.0,
        302.3,
        155.5,
        154.6,
        154.6,
        154.9,
        153.0,
        154.7,
        156.0,
        154.2,
        299.9,
        346.6,
        774.0,
        154.1,
        172.1,
        345.5,
        155.3,
        493.5,
        301.6,
        154.8,
        153.8,
        154.1,
        155.7,
        342.5,
        341.7,
        152.5,
        340.7,
        154.2,
        154.9,
        153.7,
        153.6,
        154.0,
        154.8,
        344.2,
        153.8,
        154.8,
        153.6,
        155.5,
        153.5,
        155.3,
        152.3,
        154.1,
        153.0,
        174.7,
        156.2,
        153.0,
        750.3,
        343.8,
        173.1,
        151.7,
        155.9,
        152.0,
        490.6,
        153.9,
        152.3,
        1703.9,
        173.6,
        304.6,
        153.4,
        382.2,
        594.6,
        175.4,
        1214.5,
        173.9,
        154.6,
        343.8,
        387.3,
        303.5,
        159.7,
        767.1,
        748.1,
        155.5,
        156.4,
        155.2,
        153.4,
        343.7,
        303.0,
        156.4,
        173.0,
        157.1,
        173.5,
        152.9,
        799.4,
        156.0,
        155.6,
        154.6,
        153.9,
        152.3,
        152.4,
        153.6,
        154.1,
        153.5,
        155.6,
        152.4,
        757.2,
        793.6,
        151.8,
        154.8,
        302.4,
        155.0,
        155.5,
        155.4,
        598.3
      ],
      "tc_server": [
        306.0,
        350.0,
        359.6,
        316.3,
        317.4,
        353.1,
        952.6,
        317.2,
        320.1,
        882.9,
        356.9,
        317.8,
        509.6,
        911.7,
        458.6,
        504.8,
        876.1,
        507.6,
        317.5,
        328.0,
        316.7,
        305.9,
        315.1,
        356.0,
        896.4,
        320.2,
        929.6,
        317.6,
        903.9,
        320.8,
        320.3,
        312.5,
        321.0,
        352.3,
        455.8,
        498.9,
        310.2,
        882.5,
        894.8,
        495.1,
        312.7,
        306.3,
        892.3,
        506.4,
        491.8,
        321.0,
        311.7,
        320.5,
        318.4,
        315.4,
        320.8,
        308.9,
        344.7,
        319.9,
        323.1,
        492.3,
        306.9,
        309.5,
        313.5,
        315.0,
        350.3,
        312.1,
        320.7,
        315.4,
        874.9,
        317.1,
        304.2,
        309.2,
        315.5,
        315.8,
        320.8,
        313.1,
        351.3,
        316.1,
        316.1,
        311.1,
        315.7,
        316.8,
        317.3,
        496.9,
        319.4,
        309.6,
        313.7,
        307.5,
        320.2,
        319.3,
        306.2,
        538.2,
        457.8,
        354.3,
        495.9,
        316.4,
        320.0,
        314.3,
        318.5,
        318.9,
        499.5,
        314.0,
        456.2,
        505.3,
        352.5,
        307.4,
        316.5,
        320.5,
        315.4,
        496.9,
        305.8,
        311.7,
        316.2,
        317.1,
        318.9,
        315.9,
        319.1,
        317.0,
        318.4,
        317.8,
        557.1,
        312.2,
        316.3,
        317.1,
        491.9,
        303.2,
        319.4,
        344.0,
        312.7,
        322.5,
        305.6,
        323.0,
        351.9,
        318.7,
        318.9,
        308.1,
        306.3,
        873.9,
        506.8,
        317.1,
        495.0,
        503.9,
        505.0,
        317.3,
        315.7,
        308.4,
        1069.4,
        313.8,
        309.9,
        513.0,
        308.0,
        349.5,
        314.9,
        314.5,
        314.0,
        313.7,
        318.7,
        314.3,
        952.8,
        356.7,
        347.5,
        318.2,
        321.9,
        320.2,
        571.9,
        316.4,
        319.0,
        315.6,
        313.6,
        318.2,
        305.4,
        350.3,
        313.2,
        352.1,
        316.2,
        491.0,
        318.5,
        312.7,
        498.2,
        315.1,
        305.6,
        315.9,
        315.9,
        317.1,
        317.8,
        316.9,
        317.5,
        315.5,
        308.4,
        311.1,
        304.8,
        318.0,
        313.6,
        308.6,
        316.3,
        304.1,
        497.8,
        513.1,
        354.7,
        504.1,
        304.2,
        1805.1,
        306.9,
        1063.7,
        311.7,
        309.5,
        528.6,
        924.4,
        319.8,
        332.0,
        309.0,
        493.8,
        316.7,
        348.9,
        319.2,
        306.9,
        343.8,
        317.8,
        319.9,
        359.7,
        499.2,
        314.0,
        307.7,
        318.2,
        312.8,
        312.1,
        924.5,
        323.5,
        312.5,
        318.8,
        306.9,
        359.4,
        910.5,
        311.9,
        319.1,
        305.1,
        322.5,
        315.3,
        317.3,
        307.3,
        347.7,
        318.9,
        531.2,
        316.3,
        308.8,
        346.7,
        313.2,
        953.0,
        880.1,
        319.4,
        308.4,
        504.9,
        357.2,
        309.1,
        318.6,
        310.1,
        356.0,
        316.8,
        311.3,
        314.1,
        308.4,
        316.1,
        304.8,
        308.2,
        560.0,
        306.6,
        316.0,
        1354.9,
        381.5,
        341.5,
        308.9,
        310.8,
        495.3,
        559.5,
        315.6,
        309.7,
        512.7,
        316.7,
        355.3,
        321.2,
        309.1,
        320.3,
        498.0,
        319.4,
        319.9,
        306.7,
        319.5,
        943.2,
        878.8,
        314.9,
        311.2,
        314.0,
        905.0,
        314.8,
        315.7,
        305.4,
        507.0,
        493.6,
        322.2,
        317.0,
        345.4,
        315.5,
        319.3,
        319.0,
        319.9,
        307.8,
        318.8,
        316.6,
        314.2,
        456.3,
        315.5,
        318.1,
        313.8,
        319.5,
        308.5,
        306.4,
        319.2,
        455.6,
        311.1,
        510.5,
        344.9,
        309.8,
        309.2,
        558.7,
        314.1,
        305.9,
        503.8,
        937.8,
        309.5,
        322.0,
        900.8,
        311.4,
        319.8,
        359.6,
        321.0,
        312.0,
        315.0,
        313.0,
        351.0,
        314.8,
        305.7,
        352.1,
        504.9,
        319.6,
        315.0,
        307.2,
        320.5,
        316.3,
        314.5,
        317.8,
        449.8,
        317.4,
        498.1,
        955.7,
        312.2,
        1081.8,
        356.7,
        502.7,
        317.5,
        316.6,
        307.3,
        313.6,
        317.5,
        307.5,
        318.2,
        307.0,
        361.0,
        314.5,
        309.9,
        314.4,
        304.5,
        311.9,
        897.3,
        318.1,
        346.1,
        317.7,
        305.5,
        890.1,
        504.3,
        506.9,
        307.1,
        317.3,
        492.2,
        318.9,
        317.3,
        328.0,
        314.3,
        316.3,
        315.4,
        324.3,
        315.4,
        500.6,
        316.7,
        357.4,
        359.5,
        317.7,
        343.7,
        319.4,
        319.2,
        309.3,
        317.7,
        318.0,
        947.8,
        316.7,
        325.3,
        357.0,
        504.7,
        317.5,
        321.4,
        349.8,
        306.0,
        494.4,
        317.7,
        312.6,
        312.3,
        494.1,
        313.1,
        317.8,
        316.9,
        318.7,
        305.8,
        342.6,
        314.4,
        357.9,
        320.0,
        452.2,
        321.5,
        315.6,
        507.2,
        317.6,
        306.7,
        321.6,
        313.0,
        314.7,
        316.8,
        491.0,
        509.1,
        466.3,
        321.0,
        313.1,
        306.7,
        571.9,
        894.3,
        317.4,
        318.8,
        307.8,
        314.7,
        889.5,
        316.9,
        326.6,
        315.3,
        316.0,
        310.0,
        304.7,
        320.4,
        887.7,
        319.6,
        308.4,
        317.3,
        309.7,
        306.7,
        317.2,
        320.1,
        322.0,
        321.2,
        343.8,
        565.2,
        321.6,
        489.8,
        452.9,
        308.8,
        314.1,
        314.9,
        317.4,
        308.9,
        317.8,
        352.4,
        316.6,
        315.4,
        317.8,
        309.0,
        306.7,
        356.6,
        313.6,
        314.0,
        318.2,
        318.7,
        458.1,
        317.3,
        318.9,
        309.6,
        456.2,
        890.7,
        315.0,
        509.7,
        311.8,
        344.6,
        449.6,
        317.3,
        314.0,
        1321.4,
        317.8,
        928.7,
        313.2,
        504.2,
        456.3,
        324.7,
        316.5,
        1803.7,
        1072.4,
        311.5,
        318.6,
        322.1,
        316.5,
        351.6,
        317.8,
        315.1,
        328.8,
        328.2,
        328.5,
        316.2,
        328.1,
        529.1,
        328.6,
        508.9,
        329.7,
        954.7,
        327.6,
        354.4,
        319.1,
        517.6,
        452.5,
        308.0,
        513.6,
        644.1,
        521.8,
        329.1,
        329.0,
        323.2,
        322.9,
        508.6,
        346.5,
        309.4,
        356.6,
        322.6,
        304.7,
        358.1,
        321.6,
        335.0,
        924.4,
        317.8,
        521.6,
        326.7,
        325.0,
        329.4,
        316.2,
        322.0,
        313.8,
        314.2,
        317.8,
        316.5,
        509.4,
        315.4,
        328.4,
        318.0,
        462.1,
        513.2,
        930.3,
        325.8,
        976.4,
        315.3,
        327.2,
        330.2,
        320.4,
        978.4,
        316.0,
        326.4,
        511.3,
        519.6,
        327.9,
        305.4,
        466.0,
        879.7,
        317.4,
        310.9,
        350.4,
        507.1,
        328.0,
        307.0,
        322.1,
        449.7,
        314.0,
        465.2,
        925.9,
        321.8,
        920.0,
        345.9,
        321.8,
        322.5,
        321.4,
        303.5,
        318.1,
        316.2,
        304.9,
        319.0,
        309.0,
        641.5,
        312.9,
        310.2,
        322.3,
        316.8,
        316.5,
        359.2,
        503.5,
        903.0,
        307.1,
        940.4,
        318.1,
        318.6,
        314.2,
        880.2,
        316.0,
        315.7,
        320.8,
        308.7,
        879.4,
        313.8,
        496.9,
        317.6,
        520.0,
        307.6,
        317.9,
        313.0,
        448.8,
        306.8,
        347.2,
        316.7,
        316.7,
        457.6,
        319.2,
        307.1,
        322.6,
        315.1,
        493.5,
        308.2,
        307.8,
        308.8,
        315.0,
        1136.6,
        894.2,
        305.9,
        314.9,
        307.9,
        504.6,
        314.2,
        309.0,
        322.5,
        313.4,
        313.2,
        311.3,
        309.4,
        317.5,
        312.0,
        306.9,
        344.3,
        313.8,
        320.2,
        319.3,
        306.3,
        356.6,
        305.2,
        309.2,
        316.7,
        505.2,
        489.3,
        308.6,
        455.3,
        344.4,
        310.6,
        308.0,
        356.0,
        762.5,
        603.0,
        663.6,
        345.5,
        498.0,
        306.7,
        354.1,
        312.2,
        309.0,
        307.5,
        316.3,
        306.3,
        319.5,
        311.1,
        314.9,
        311.2,
        307.9,
        357.1,
        343.9,
        309.0,
        346.2,
        306.9,
        448.3,
        307.1,
        494.2,
        934.5,
        311.9,
        305.4,
        320.3,
        307.5,
        505.8,
        306.1,
        306.9,
        308.4,
        317.1,
        454.5,
        316.4,
        309.8,
        306.8,
        306.2,
        313.9,
        318.8,
        452.7
      ],
      "awc_ttfb": [
        638.7,
        1167.3,
        931.6,
        717.9,
        837.2,
        830.8,
        826.4,
        644.5,
        1598.8,
        819.3,
        974.6,
        2277.6,
        644.2,
        640.0,
        639.9,
        790.4,
        820.0,
        947.7,
        641.4,
        811.8,
        648.8,
        631.6,
        834.4,
        1234.9,
        651.2,
        955.4,
        628.6,
        642.3,
        643.5,
        1151.3,
        647.7,
        624.9,
        824.3,
        833.7,
        834.4,
        2896.1,
        706.0,
        717.2,
        635.2,
        628.5,
        635.5,
        627.9,
        1273.2,
        643.8,
        642.6,
        928.7,
        633.2,
        782.9,
        644.8,
        643.5,
        639.3,
        622.4,
        636.0,
        835.2,
        1395.6,
        1428.0,
        705.5,
        1262.6,
        931.8,
        1859.4,
        1571.3,
        628.3,
        641.3,
        636.9,
        635.3,
        1599.4,
        627.5,
        784.4,
        828.5,
        625.8,
        640.1,
        632.6,
        715.7,
        643.2,
        638.3,
        2516.8,
        851.4,
        636.6,
        737.8,
        638.5,
        678.0,
        968.5,
        633.0,
        832.6,
        636.9,
        641.0,
        1874.2,
        642.3,
        635.9,
        819.6,
        645.5,
        632.0,
        822.4,
        818.6,
        837.6,
        638.1,
        824.9,
        836.2,
        797.7,
        786.0,
        784.9,
        1016.1,
        631.7,
        1506.2,
        881.7,
        791.5,
        654.2,
        635.3,
        639.3,
        831.9,
        782.1,
        826.2,
        638.5,
        641.9,
        635.5,
        635.0,
        676.6,
        892.5,
        1250.9,
        636.6,
        827.7,
        627.7,
        636.0,
        643.2,
        651.6,
        961.4,
        1938.9,
        643.2,
        835.7,
        638.4,
        826.7,
        827.8,
        639.3,
        696.4,
        664.0,
        635.2,
        817.1,
        642.9,
        814.3,
        637.8,
        2131.7,
        2260.9,
        636.3,
        883.3,
        810.6,
        646.8,
        818.5,
        718.6,
        644.6,
        1237.6,
        718.8,
        627.9,
        837.1,
        874.2,
        638.1,
        629.9,
        962.6,
        636.1,
        632.6,
        687.6,
        824.6,
        2792.3,
        646.8,
        628.1,
        829.8,
        660.6,
        629.1,
        623.4,
        633.7,
        630.6,
        721.7,
        630.0,
        1062.7,
        1825.7,
        641.8,
        641.2,
        629.5,
        775.3,
        979.5,
        632.2,
        740.0,
        817.9,
        889.4,
        1267.2,
        637.6,
        642.7,
        629.6,
        826.3,
        1270.4,
        638.3,
        784.5,
        635.8,
        637.6,
        2310.3,
        626.9,
        824.1,
        623.7,
        711.1,
        973.6,
        815.7,
        637.1,
        629.7,
        830.9,
        782.4,
        815.5,
        825.3,
        623.1,
        824.2,
        833.7,
        648.9,
        641.1,
        660.4,
        830.4,
        887.0,
        1320.2,
        644.8,
        626.6,
        646.8,
        710.6,
        782.6,
        642.9,
        910.5,
        726.4,
        835.1,
        646.5,
        641.4,
        818.7,
        663.6,
        980.0,
        973.7,
        657.3,
        821.3,
        739.6,
        636.3,
        639.2,
        820.7,
        823.0,
        661.0,
        644.4,
        848.3,
        825.8,
        642.0,
        641.5,
        1008.3,
        1309.0,
        640.5,
        630.5,
        1057.4,
        931.8,
        1442.5,
        640.8,
        626.7,
        830.2,
        642.9,
        1011.2,
        698.3,
        777.8,
        646.4,
        1123.7,
        642.0,
        635.0,
        628.8,
        645.2,
        791.3,
        2285.4,
        841.8,
        818.3,
        645.2,
        633.2,
        641.0,
        645.7,
        1461.1,
        697.0,
        637.7,
        787.3,
        642.9,
        627.2,
        632.4,
        643.3,
        715.6,
        655.9,
        632.6,
        782.7,
        638.1,
        1168.6,
        639.5,
        644.5,
        638.9,
        638.8,
        812.6,
        639.9,
        1445.7,
        649.5,
        630.9,
        639.2,
        640.7,
        817.8,
        931.1,
        829.7,
        828.2,
        647.0,
        625.8,
        2547.6,
        1584.1,
        942.7,
        644.5,
        640.8,
        639.2,
        646.7,
        646.8,
        632.7,
        822.8,
        822.5,
        676.9,
        823.2,
        634.8,
        975.5,
        642.0,
        967.8,
        819.6,
        791.9,
        998.6,
        1677.0,
        1415.2,
        824.3,
        829.1,
        630.6,
        638.4,
        641.3,
        829.4,
        639.0,
        639.2,
        824.4,
        715.2,
        628.2,
        826.4,
        628.6,
        637.5,
        719.1,
        630.9,
        924.1,
        626.2,
        1453.2,
        1842.6,
        964.8,
        638.9,
        786.7,
        787.1,
        680.7,
        1410.8,
        2130.1,
        630.2,
        641.6,
        641.6,
        835.0,
        640.7,
        876.1,
        632.8,
        643.3,
        931.6,
        836.7,
        637.8,
        640.3,
        640.0,
        830.1,
        641.7,
        625.9,
        1262.7,
        721.0,
        791.4,
        641.3,
        627.9,
        936.9,
        1581.5,
        642.2,
        780.9,
        1609.5,
        831.4,
        638.7,
        648.5,
        829.6,
        1175.5,
        718.0,
        799.1,
        639.6,
        830.3,
        779.5,
        641.9,
        633.4,
        635.4,
        784.8,
        869.1,
        631.5,
        635.5,
        652.3,
        662.4,
        628.1,
        643.3,
        640.7,
        1024.4,
        643.2,
        641.9,
        981.3,
        645.3,
        991.0,
        634.5,
        880.8,
        698.6,
        639.2,
        950.1,
        1707.5,
        713.3,
        995.5,
        836.1,
        640.1,
        646.4,
        628.4,
        642.7,
        716.8,
        988.7,
        636.8,
        636.8,
        639.8,
        637.1,
        1620.6,
        831.5,
        646.6,
        654.0,
        795.6,
        635.4,
        1508.5,
        625.2,
        644.3,
        865.0,
        1945.1,
        1915.6,
        821.6,
        722.5,
        643.8,
        620.8,
        773.3,
        628.3,
        850.7,
        642.5,
        813.2,
        2336.5,
        822.3,
        842.6,
        813.9,
        712.3,
        648.8,
        630.5,
        643.0,
        835.2,
        832.5,
        631.3,
        627.9,
        1470.1,
        750.7,
        818.1,
        641.0,
        1227.7,
        632.5,
        1482.6,
        976.0,
        642.9,
        642.8,
        976.3,
        1428.9,
        642.5,
        823.3,
        1223.7,
        825.4,
        830.7,
        625.7,
        832.4,
        822.9,
        790.4,
        639.1,
        775.0,
        1168.2,
        815.4,
        641.6,
        831.8,
        1397.5,
        643.4,
        1619.3,
        702.0,
        828.9,
        834.1,
        983.9,
        2064.6,
        824.9,
        895.1,
        648.1,
        639.7,
        657.3,
        639.4,
        653.5,
        636.1,
        1620.8,
        622.4,
        647.1,
        816.6,
        640.2,
        843.9,
        791.3,
        982.1,
        632.9,
        821.4,
        825.1,
        775.6,
        894.5,
        664.8,
        655.2,
        851.1,
        649.2,
        657.6,
        1053.2,
        659.1,
        632.5,
        1610.1,
        632.1,
        645.5,
        1003.9,
        654.9,
        664.7,
        641.1,
        662.9,
        662.0,
        873.0,
        839.9,
        788.3,
        640.2,
        809.5,
        1028.5,
        709.1,
        640.8,
        922.0,
        823.1,
        674.0,
        632.9,
        659.2,
        664.4,
        847.6,
        1050.1,
        652.2,
        851.2,
        1647.2,
        848.6,
        725.5,
        850.6,
        655.4,
        831.1,
        661.4,
        877.5,
        662.0,
        1498.0,
        937.9,
        855.8,
        659.0,
        646.8,
        666.9,
        667.0,
        901.8,
        731.7,
        646.2,
        953.7,
        657.0,
        676.5,
        717.5,
        654.1,
        663.7,
        815.4,
        831.7,
        664.9,
        629.5,
        1703.9,
        664.2,
        1003.7,
        640.0,
        789.3,
        629.2,
        895.5,
        680.2,
        656.3,
        710.0,
        661.1,
        853.9,
        854.8,
        652.6,
        845.6,
        641.5,
        637.1,
        1614.6,
        833.7,
        1116.8,
        822.0,
        864.0,
        776.2,
        815.8,
        626.9,
        635.4,
        787.9,
        1277.7,
        634.4,
        813.5,
        826.5,
        826.6,
        639.9,
        831.3,
        813.6,
        654.9,
        632.0,
        638.6,
        833.0,
        897.2,
        639.7,
        641.1,
        716.5,
        3788.4,
        793.0,
        1583.3,
        1132.0,
        636.4,
        779.8,
        1969.0,
        648.2,
        642.5,
        777.7,
        1143.6,
        630.6,
        1168.2,
        836.5,
        722.0,
        642.0,
        631.1,
        715.1,
        829.1,
        1210.6,
        1411.5,
        825.6,
        640.4,
        641.0,
        1422.9,
        639.1,
        633.8,
        635.6,
        1013.9,
        1605.8,
        636.7,
        623.7,
        1026.2,
        638.8,
        640.4,
        831.6,
        821.4,
        1251.9,
        823.7,
        640.5,
        816.8,
        629.5,
        1493.3,
        691.4,
        637.6,
        640.6,
        769.5,
        1142.9,
        629.4,
        891.5,
        823.6,
        631.2,
        821.2,
        1235.9,
        1396.6,
        627.7,
        846.6,
        630.9,
        1167.1,
        628.8,
        825.1,
        1403.8,
        632.5,
        777.8,
        683.9,
        634.2,
        1142.1,
        735.2,
        625.5,
        839.7,
        812.4,
        632.7,
        667.7,
        908.2,
        818.2,
        636.8,
        631.2,
        663.6,
        831.1,
        662.4,
        661.7,
        625.5,
        722.7,
        632.3,
        714.7,
        636.5,
        631.0,
        636.7,
        647.7,
        708.9,
        1247.4,
        631.7,
        835.4,
        775.8,
        922.0,
        817.0,
        820.3,
        639.4,
        716.6,
        641.1
      ],
      "gw_latency": [
        0.674,
        0.64,
        0.632,
        0.551,
        0.721,
        0.674,
        0.614,
        0.72,
        0.548,
        0.624,
        0.702,
        0.655,
        0.698,
        0.553,
        0.617,
        0.693,
        0.658,
        0.631,
        0.605,
        0.67,
        0.575,
        0.682,
        0.633,
        0.604,
        0.707,
        0.854,
        0.69,
        0.654,
        0.651,
        0.648,
        0.698,
        0.631,
        0.729,
        0.569,
        0.598,
        0.672,
        0.597,
        0.621,
        0.591,
        0.601,
        0.724,
        0.605,
        0.623,
        0.662,
        0.723,
        0.68,
        0.681,
        0.706,
        0.645,
        0.7,
        0.629,
        0.56,
        0.553,
        0.665,
        0.656,
        0.558,
        0.783,
        0.773,
        0.69,
        0.791,
        0.571,
        0.724,
        0.687,
        0.525,
        0.889,
        0.662,
        0.667,
        0.647,
        0.621,
        0.662,
        0.805,
        0.617,
        0.588,
        0.58,
        0.673,
        0.739,
        0.68,
        0.61,
        0.556,
        0.557,
        0.639,
        0.687,
        0.323,
        0.596,
        0.605,
        0.724,
        0.643,
        0.732,
        0.665,
        0.593,
        0.886,
        0.504,
        0.701,
        0.636,
        0.67,
        0.723,
        0.626,
        0.673,
        0.699,
        0.692,
        0.663,
        0.608,
        0.679,
        0.539,
        0.564,
        0.583,
        0.678,
        0.627,
        0.628,
        0.725,
        0.798,
        0.624,
        0.554,
        0.706,
        0.601,
        0.572,
        0.603,
        0.52,
        0.587,
        0.64,
        0.551,
        0.712,
        0.822,
        0.628,
        0.59,
        0.586,
        0.86,
        0.57,
        0.676,
        0.727,
        0.608,
        0.595,
        0.67,
        0.634,
        0.678,
        0.812,
        0.578,
        0.703,
        0.743,
        0.546,
        0.774,
        0.772,
        0.613,
        0.707,
        0.843,
        0.463,
        0.669,
        0.579,
        0.642,
        0.614,
        0.627,
        0.577,
        0.719,
        0.774,
        0.716,
        0.641,
        0.648,
        0.657,
        0.577,
        0.613,
        0.721,
        0.646,
        0.526,
        0.533,
        0.698,
        0.558,
        0.608,
        0.736,
        0.727,
        0.631,
        0.671,
        0.755,
        0.64,
        0.656,
        0.663,
        0.593,
        0.606,
        0.588,
        0.628,
        0.542,
        0.662,
        0.606,
        0.719,
        0.634,
        0.582,
        0.64,
        0.61,
        0.644,
        0.661,
        0.632,
        0.644,
        0.706,
        0.742,
        0.769,
        0.635,
        0.571,
        0.599,
        0.658,
        0.56,
        0.706,
        0.569,
        0.723,
        0.644,
        0.626,
        0.61,
        0.503,
        0.604,
        0.645,
        0.766,
        0.603,
        0.698,
        0.572,
        0.781,
        0.636,
        0.633,
        0.602,
        0.593,
        0.548,
        0.748,
        0.598,
        0.804,
        0.718,
        0.61,
        0.733,
        0.595,
        0.609,
        0.641,
        0.622,
        0.617,
        0.648,
        0.623,
        0.616,
        0.836,
        0.626,
        0.64,
        0.662,
        0.671,
        0.789,
        0.733,
        0.655,
        0.745,
        0.698,
        0.655,
        0.586,
        0.615,
        0.578,
        0.572,
        0.72,
        0.581,
        0.616,
        0.643,
        0.663,
        0.769,
        0.59,
        0.635,
        0.688,
        0.622,
        0.489,
        0.638,
        0.591,
        0.626,
        0.59,
        0.619,
        0.614,
        0.58,
        0.663,
        0.524,
        0.666,
        0.715,
        0.68,
        0.552,
        0.59,
        0.57,
        0.75,
        0.599,
        0.568,
        0.625,
        0.576,
        0.661,
        0.768,
        0.714,
        57.326,
        0.611,
        0.572,
        0.581,
        0.667,
        0.569,
        0.78,
        0.68,
        0.631,
        0.659,
        0.707,
        0.577,
        0.673,
        0.595,
        0.641,
        0.712,
        0.671,
        0.658,
        0.619,
        0.726,
        0.591,
        0.591,
        0.737,
        0.845,
        0.639,
        0.609,
        0.499,
        0.704,
        0.607,
        0.573,
        0.635,
        0.641,
        0.509,
        0.512,
        0.341,
        0.621,
        0.535,
        0.577,
        0.566,
        0.587,
        0.585,
        0.605,
        0.471,
        0.528,
        0.39,
        0.91,
        0.497,
        0.7,
        0.584,
        0.567,
        0.544,
        0.723,
        0.269,
        0.291,
        0.616,
        0.497,
        0.552,
        0.601,
        0.774,
        0.643,
        0.539,
        0.611,
        0.612,
        0.667,
        0.538,
        0.694,
        0.682,
        0.662,
        0.616,
        0.634,
        0.665,
        0.656,
        0.681,
        0.674,
        0.554,
        0.59,
        0.59,
        0.614,
        0.563,
        0.597,
        0.671,
        0.562,
        0.545,
        0.298,
        0.611,
        0.659,
        0.604,
        0.698,
        0.755,
        0.601,
        0.601,
        0.631,
        0.638,
        0.526,
        0.578,
        0.718,
        0.634,
        0.709,
        0.703,
        0.734,
        0.695,
        0.78,
        0.694,
        0.629,
        0.637,
        0.629,
        0.562,
        0.527,
        0.692,
        0.802,
        0.6,
        0.609,
        0.606,
        0.593,
        0.507,
        0.725,
        0.739,
        0.664,
        0.536,
        0.79,
        0.628,
        0.628,
        0.581,
        0.63,
        0.509,
        0.656,
        0.728,
        0.504,
        0.656,
        0.608,
        0.667,
        0.571,
        0.682,
        0.617,
        0.662,
        0.557,
        0.497,
        0.567,
        0.653,
        0.618,
        0.441,
        0.562,
        0.689,
        0.618,
        0.632,
        0.473,
        0.65,
        0.614,
        0.524,
        0.613,
        0.542,
        0.615,
        0.671,
        0.565,
        0.745,
        0.635,
        0.668,
        0.58,
        0.709,
        0.504,
        0.566,
        0.586,
        0.709,
        0.54,
        0.665,
        0.516,
        0.627,
        0.547,
        0.664,
        0.803,
        0.575,
        0.672,
        0.516,
        0.59,
        0.668,
        0.573,
        0.561,
        0.608,
        0.555,
        0.687,
        0.616,
        0.581,
        0.639,
        0.678,
        0.698,
        0.558,
        0.61,
        0.743,
        0.634,
        0.512,
        0.636,
        0.601,
        0.693,
        0.614,
        0.543,
        0.603,
        0.686,
        0.627,
        0.631,
        0.613,
        0.623,
        0.582,
        0.48,
        0.745,
        0.65,
        0.569,
        0.571,
        0.756,
        0.7,
        0.616,
        0.757,
        0.542,
        0.719,
        0.764,
        0.644,
        0.58,
        0.691,
        0.631,
        0.583,
        0.61,
        0.666,
        0.756,
        0.486,
        0.587,
        0.601,
        0.484,
        0.674,
        0.654,
        0.552,
        0.595,
        0.645,
        0.677,
        0.677,
        0.648,
        0.706,
        0.689,
        0.573,
        0.725,
        0.445,
        0.569,
        0.516,
        0.675,
        0.562,
        0.51,
        0.65,
        0.701,
        0.588,
        0.622,
        0.696,
        0.529,
        0.531,
        0.633,
        0.627,
        0.596,
        0.668,
        0.785,
        0.607,
        0.412,
        0.577,
        0.636,
        0.557,
        0.759,
        0.643,
        0.636,
        0.237,
        0.55,
        0.692,
        0.581,
        0.591,
        0.561,
        0.598,
        0.683,
        0.656,
        0.601,
        0.691,
        0.658,
        0.616,
        0.568,
        0.493,
        0.632,
        0.556,
        0.775,
        0.601,
        0.621,
        0.48,
        0.552,
        0.556,
        0.741,
        0.694,
        0.527,
        0.692,
        0.63,
        0.624,
        0.536,
        0.707,
        0.644,
        0.695,
        0.539,
        0.664,
        0.55,
        0.706,
        0.65,
        0.497,
        0.642,
        0.532,
        0.734,
        0.615,
        0.603,
        0.593,
        0.441,
        0.722,
        0.679,
        0.613,
        0.703,
        0.686,
        0.564,
        0.598,
        0.552,
        0.629,
        0.595,
        0.612,
        0.586,
        0.569,
        0.708,
        0.531,
        0.567,
        0.637,
        0.507,
        0.601,
        0.609,
        0.592,
        0.539,
        0.578,
        0.601,
        0.619,
        0.623,
        0.794,
        0.707,
        0.638,
        0.566,
        0.728,
        0.442,
        0.721,
        0.575,
        0.53,
        0.592,
        0.651,
        0.663,
        0.64,
        0.684,
        0.715,
        0.614,
        0.602,
        0.692,
        0.663,
        0.594,
        0.712,
        0.657,
        0.693,
        0.576,
        0.607,
        0.547,
        0.642,
        0.54,
        0.653,
        0.609,
        0.649,
        0.555,
        0.59,
        0.643,
        0.565,
        0.657,
        0.452,
        0.473,
        0.544,
        0.648,
        0.754,
        0.606,
        0.643,
        0.623,
        0.584,
        0.613,
        0.783,
        0.587,
        0.562,
        0.29,
        0.658,
        0.574,
        0.498,
        0.603,
        0.646,
        0.713,
        0.586,
        0.513,
        0.69,
        0.391,
        0.646,
        0.488,
        0.623,
        0.707,
        0.656,
        0.621,
        0.717,
        0.572,
        0.581,
        0.674,
        0.627,
        0.589,
        0.55,
        0.75,
        0.593,
        0.611,
        0.735,
        0.565,
        0.492,
        0.705,
        0.511,
        0.562,
        0.714,
        0.589,
        0.623,
        0.613,
        0.666,
        0.619,
        0.59,
        0.631,
        0.723,
        0.54,
        0.711,
        0.63,
        0.549,
        0.571,
        0.542,
        0.63,
        0.602,
        0.678,
        0.563,
        0.694,
        0.529
      ],
      "dns_resolve": [
        16,
        39,
        15,
        15,
        15,
        19,
        24,
        20,
        20,
        15,
        55,
        15,
        19,
        48,
        52,
        24,
        19,
        55,
        23,
        95,
        23,
        64,
        20,
        19,
        19,
        47,
        79,
        23,
        36,
        20,
        35,
        19,
        35,
        15,
        23,
        20,
        40,
        19,
        19,
        31,
        23,
        51,
        36,
        28,
        19,
        15,
        43,
        39,
        19,
        40,
        24,
        37,
        47,
        19,
        15,
        19,
        40,
        20,
        37,
        27,
        7,
        15,
        15,
        23,
        39,
        43,
        35,
        19,
        71,
        71,
        31,
        19,
        19,
        43,
        23,
        39,
        36,
        19,
        15,
        39,
        15,
        15,
        47,
        43,
        19,
        19,
        19,
        23,
        67,
        50,
        19,
        43,
        15,
        19,
        27,
        35,
        19,
        31,
        90,
        15,
        19,
        31,
        23,
        23,
        19,
        23,
        106,
        271,
        19,
        23,
        39,
        15,
        27,
        15,
        15,
        46,
        12,
        51,
        39,
        23,
        50,
        23,
        35,
        23,
        31,
        19,
        23,
        43,
        27,
        19,
        19,
        55,
        15,
        19,
        19,
        19,
        19,
        19,
        23,
        59,
        46,
        15,
        24,
        15,
        48,
        35,
        20,
        36,
        23,
        19,
        15,
        43,
        23,
        16,
        16,
        43,
        19,
        27,
        19,
        47,
        40,
        23,
        39,
        27,
        20,
        32,
        19,
        27,
        15,
        19,
        15,
        24,
        20,
        23,
        43,
        19,
        43,
        51,
        16,
        24,
        63,
        23,
        19,
        63,
        15,
        24,
        36,
        82,
        19,
        19,
        19,
        23,
        16,
        20,
        45,
        19,
        15,
        19,
        19,
        55,
        32,
        57,
        19,
        51,
        15,
        43,
        19,
        16,
        20,
        19,
        55,
        47,
        19,
        28,
        76,
        20,
        19,
        43,
        19,
        39,
        44,
        256,
        63,
        39,
        39,
        47,
        23,
        19,
        71,
        19,
        43,
        27,
        19,
        23,
        83,
        19,
        39,
        19,
        19,
        34,
        43,
        15,
        19,
        47,
        43,
        31,
        39,
        23,
        19,
        43,
        23,
        19,
        19,
        27,
        19,
        19,
        42,
        35,
        32,
        19,
        15,
        38,
        31,
        39,
        275,
        19,
        23,
        27,
        19,
        19,
        19,
        78,
        15,
        27,
        23,
        19,
        39,
        47,
        19,
        23,
        27,
        39,
        19,
        19,
        23,
        15,
        15,
        20,
        15,
        23,
        19,
        19,
        55,
        27,
        66,
        15,
        15,
        46,
        19,
        15,
        15,
        23,
        43,
        19,
        23,
        23,
        15,
        15,
        15,
        19,
        15,
        11,
        38,
        19,
        19,
        43,
        58,
        43,
        19,
        23,
        31,
        19,
        19,
        23,
        23,
        15,
        15,
        15,
        43,
        43,
        19,
        31,
        23,
        43,
        42,
        15,
        19,
        19,
        35,
        15,
        15,
        19,
        23,
        15,
        15,
        19,
        43,
        19,
        19,
        19,
        15,
        39,
        15,
        19,
        19,
        19,
        19,
        23,
        27,
        42,
        20,
        70,
        23,
        62,
        19,
        19,
        19,
        15,
        15,
        23,
        15,
        23,
        47,
        23,
        19,
        35,
        23,
        35,
        47,
        19,
        19,
        50,
        15,
        19,
        15,
        62,
        23,
        35,
        39,
        20,
        15,
        19,
        19,
        35,
        19,
        43,
        43,
        23,
        23,
        23,
        15,
        23,
        31,
        43,
        43,
        23,
        47,
        15,
        47,
        23,
        35,
        19,
        23,
        15,
        19,
        15,
        19,
        50,
        27,
        35,
        23,
        19,
        23,
        19,
        19,
        23,
        15,
        51,
        15,
        19,
        19,
        15,
        59,
        15,
        23,
        19,
        15,
        15,
        15,
        15,
        15,
        47,
        23,
        54,
        66,
        19,
        15,
        31,
        15,
        19,
        19,
        15,
        15,
        15,
        27,
        35,
        19,
        15,
        31,
        15,
        47,
        31,
        19,
        58,
        15,
        69,
        16,
        15,
        16,
        19,
        15,
        19,
        31,
        23,
        23,
        15,
        35,
        59,
        43,
        15,
        23,
        19,
        15,
        15,
        23,
        15,
        32,
        15,
        19,
        15,
        15,
        34,
        15,
        15,
        15,
        15,
        35,
        19,
        27,
        39,
        19,
        19,
        23,
        15,
        23,
        19,
        15,
        35,
        15,
        19,
        15,
        39,
        39,
        27,
        15,
        15,
        15,
        15,
        19,
        23,
        15,
        23,
        43,
        27,
        15,
        23,
        43,
        19,
        31,
        35,
        66,
        7,
        19,
        23,
        19,
        15,
        19,
        38,
        19,
        19,
        15,
        11,
        15,
        15,
        31,
        39,
        19,
        23,
        23,
        19,
        15,
        43,
        234,
        39,
        15,
        31,
        19,
        23,
        47,
        70,
        31,
        38,
        66,
        15,
        74,
        58,
        15,
        15,
        19,
        39,
        51,
        16,
        15,
        35,
        19,
        15,
        48,
        19,
        39,
        47,
        19,
        15,
        104,
        43,
        43,
        23,
        15,
        19,
        19,
        19,
        55,
        27,
        15,
        23,
        15,
        20,
        43,
        23,
        58,
        15,
        34,
        19,
        19,
        19,
        15,
        19,
        23,
        15,
        19,
        15,
        35,
        19,
        19,
        47,
        19,
        15,
        47,
        14,
        15,
        23,
        19,
        27,
        19,
        15,
        31,
        19,
        19,
        23,
        23,
        23,
        19,
        23,
        19,
        39,
        19,
        15,
        19,
        39,
        19,
        39,
        50,
        15,
        15,
        43,
        42,
        70,
        19,
        23,
        27,
        19,
        43,
        39,
        19,
        19,
        15,
        15,
        15,
        23,
        27,
        42,
        54,
        15,
        15,
        19,
        50,
        19,
        19,
        3,
        43,
        43,
        15,
        19,
        19,
        27,
        19,
        62,
        15,
        46,
        59,
        43,
        30,
        15,
        19,
        15,
        20,
        39,
        23,
        19,
        27,
        27,
        19,
        15,
        46,
        23,
        43,
        31,
        50,
        27,
        19,
        19,
        23,
        23,
        27,
        27,
        19,
        23,
        64,
        43,
        46,
        19,
        38,
        23,
        20,
        27,
        23,
        19,
        19,
        27,
        31,
        19
      ],
      "timestamps": [
        "05:35",
        "05:36",
        "05:37",
        "05:38",
        "05:39",
        "05:40",
        "05:41",
        "05:42",
        "05:43",
        "05:44",
        "05:45",
        "05:46",
        "05:47",
        "05:48",
        "05:49",
        "05:50",
        "05:51",
        "05:52",
        "05:53",
        "05:54",
        "05:55",
        "05:56",
        "05:57",
        "05:58",
        "05:59",
        "06:00",
        "06:01",
        "06:02",
        "06:03",
        "06:04",
        "06:05",
        "06:06",
        "06:07",
        "06:08",
        "06:09",
        "06:10",
        "06:11",
        "06:12",
        "06:13",
        "06:14",
        "06:15",
        "06:16",
        "06:17",
        "06:18",
        "06:19",
        "06:20",
        "06:21",
        "06:22",
        "06:23",
        "06:24",
        "06:25",
        "06:26",
        "06:27",
        "06:28",
        "06:29",
        "06:30",
        "06:31",
        "06:32",
        "06:33",
        "06:34",
        "06:35",
        "06:36",
        "06:37",
        "06:38",
        "06:39",
        "06:40",
        "06:41",
        "06:42",
        "06:43",
        "06:44",
        "06:45",
        "06:46",
        "06:47",
        "06:48",
        "06:49",
        "06:50",
        "06:51",
        "06:52",
        "06:53",
        "06:54",
        "06:55",
        "06:56",
        "06:57",
        "06:58",
        "06:59",
        "07:00",
        "07:01",
        "07:02",
        "07:03",
        "07:04",
        "07:05",
        "07:06",
        "07:07",
        "07:08",
        "07:09",
        "07:10",
        "07:11",
        "07:12",
        "07:13",
        "07:14",
        "07:15",
        "07:16",
        "07:17",
        "07:18",
        "07:19",
        "07:20",
        "07:21",
        "07:22",
        "07:23",
        "07:24",
        "07:25",
        "07:26",
        "07:27",
        "07:28",
        "07:29",
        "07:30",
        "07:31",
        "07:32",
        "07:33",
        "07:34",
        "07:35",
        "07:36",
        "07:37",
        "07:38",
        "07:39",
        "07:40",
        "07:41",
        "07:42",
        "07:43",
        "07:44",
        "07:45",
        "07:46",
        "07:47",
        "07:48",
        "07:49",
        "07:50",
        "07:51",
        "07:52",
        "07:53",
        "07:54",
        "07:55",
        "07:56",
        "07:57",
        "07:58",
        "07:59",
        "08:00",
        "08:01",
        "08:02",
        "08:03",
        "08:04",
        "08:05",
        "08:06",
        "08:07",
        "08:08",
        "08:09",
        "08:10",
        "08:11",
        "08:12",
        "08:13",
        "08:14",
        "08:15",
        "08:16",
        "08:17",
        "08:18",
        "08:19",
        "08:20",
        "08:21",
        "08:22",
        "08:23",
        "08:24",
        "08:25",
        "08:26",
        "08:27",
        "08:28",
        "08:29",
        "08:30",
        "08:31",
        "08:32",
        "08:33",
        "08:34",
        "08:35",
        "08:36",
        "08:37",
        "08:38",
        "08:39",
        "08:40",
        "08:41",
        "08:42",
        "08:43",
        "08:44",
        "08:45",
        "08:46",
        "08:47",
        "08:48",
        "08:49",
        "08:50",
        "08:51",
        "08:52",
        "08:53",
        "08:54",
        "08:55",
        "08:56",
        "08:57",
        "08:58",
        "08:59",
        "09:00",
        "09:01",
        "09:02",
        "09:03",
        "09:04",
        "09:05",
        "09:06",
        "09:07",
        "09:08",
        "09:09",
        "09:10",
        "09:11",
        "09:12",
        "09:13",
        "09:14",
        "09:15",
        "09:16",
        "09:17",
        "09:18",
        "09:19",
        "09:20",
        "09:21",
        "09:22",
        "09:23",
        "09:24",
        "09:25",
        "09:26",
        "09:27",
        "09:28",
        "09:29",
        "09:30",
        "09:31",
        "09:32",
        "09:33",
        "09:34",
        "09:35",
        "09:36",
        "09:37",
        "09:38",
        "09:39",
        "09:40",
        "09:41",
        "09:42",
        "09:43",
        "09:44",
        "09:45",
        "09:46",
        "09:47",
        "09:48",
        "09:49",
        "09:50",
        "09:51",
        "09:52",
        "09:53",
        "09:54",
        "09:55",
        "09:56",
        "09:57",
        "09:58",
        "09:59",
        "10:00",
        "10:01",
        "10:02",
        "10:03",
        "10:04",
        "10:05",
        "10:06",
        "10:07",
        "10:08",
        "10:09",
        "10:10",
        "10:11",
        "10:12",
        "10:13",
        "10:14",
        "10:15",
        "10:16",
        "10:17",
        "10:18",
        "10:19",
        "10:20",
        "10:21",
        "10:22",
        "10:23",
        "10:24",
        "10:25",
        "10:26",
        "10:27",
        "10:28",
        "10:29",
        "10:30",
        "10:31",
        "10:32",
        "10:33",
        "10:34",
        "10:35",
        "10:36",
        "10:37",
        "10:38",
        "10:39",
        "10:40",
        "10:41",
        "10:42",
        "10:43",
        "10:44",
        "10:45",
        "10:46",
        "10:47",
        "10:48",
        "10:49",
        "10:50",
        "10:51",
        "10:52",
        "10:53",
        "10:54",
        "10:55",
        "10:56",
        "10:57",
        "10:58",
        "10:59",
        "11:00",
        "11:01",
        "11:02",
        "11:03",
        "11:04",
        "11:05",
        "11:06",
        "11:07",
        "11:08",
        "11:09",
        "11:10",
        "11:11",
        "11:12",
        "11:13",
        "11:14",
        "11:15",
        "11:16",
        "11:17",
        "11:18",
        "11:19",
        "11:20",
        "11:21",
        "11:22",
        "11:23",
        "11:24",
        "11:25",
        "11:26",
        "11:27",
        "11:28",
        "11:29",
        "11:30",
        "11:31",
        "11:32",
        "11:33",
        "11:34",
        "11:35",
        "11:36",
        "11:37",
        "11:38",
        "11:39",
        "11:40",
        "11:41",
        "11:42",
        "11:43",
        "11:44",
        "11:45",
        "11:46",
        "11:47",
        "11:48",
        "11:49",
        "11:50",
        "11:51",
        "11:52",
        "11:53",
        "11:54",
        "11:55",
        "11:56",
        "11:57",
        "11:58",
        "11:59",
        "12:00",
        "12:01",
        "12:02",
        "12:03",
        "12:04",
        "12:05",
        "12:06",
        "12:07",
        "12:08",
        "12:09",
        "12:10",
        "12:11",
        "12:12",
        "12:13",
        "12:14",
        "12:15",
        "12:16",
        "12:17",
        "12:18",
        "12:19",
        "12:20",
        "12:21",
        "12:22",
        "12:23",
        "12:24",
        "12:25",
        "12:26",
        "12:27",
        "12:28",
        "12:29",
        "12:30",
        "12:31",
        "12:32",
        "12:33",
        "12:34",
        "12:35",
        "12:36",
        "12:37",
        "12:38",
        "12:39",
        "12:40",
        "12:41",
        "12:42",
        "12:43",
        "12:44",
        "12:45",
        "12:46",
        "12:47",
        "12:48",
        "12:49",
        "12:50",
        "12:51",
        "12:52",
        "12:53",
        "12:54",
        "12:55",
        "12:56",
        "12:57",
        "12:58",
        "12:59",
        "13:00",
        "13:01",
        "13:02",
        "13:03",
        "13:04",
        "13:05",
        "13:06",
        "13:07",
        "13:08",
        "13:09",
        "13:10",
        "13:11",
        "13:12",
        "13:13",
        "13:14",
        "13:15",
        "13:16",
        "13:17",
        "13:18",
        "13:19",
        "13:20",
        "13:21",
        "13:22",
        "13:23",
        "13:24",
        "13:25",
        "13:26",
        "13:27",
        "13:28",
        "13:29",
        "13:30",
        "13:31",
        "13:32",
        "13:33",
        "13:34",
        "13:35",
        "13:36",
        "13:37",
        "13:38",
        "13:39",
        "13:40",
        "13:41",
        "13:42",
        "13:43",
        "13:44",
        "13:45",
        "13:46",
        "13:47",
        "13:48",
        "13:49",
        "13:50",
        "13:51",
        "13:52",
        "13:53",
        "13:54",
        "13:55",
        "13:56",
        "13:57",
        "13:58",
        "13:59",
        "14:00",
        "14:01",
        "14:02",
        "14:03",
        "14:04",
        "14:05",
        "14:06",
        "14:07",
        "14:08",
        "14:09",
        "14:10",
        "14:11",
        "14:12",
        "14:13",
        "14:14",
        "14:15",
        "14:16",
        "14:17",
        "14:18",
        "14:19",
        "14:20",
        "14:21",
        "14:22",
        "14:23",
        "14:24",
        "14:25",
        "14:26",
        "14:27",
        "14:28",
        "14:29",
        "14:30",
        "14:31",
        "14:32",
        "14:33",
        "14:34",
        "14:35",
        "14:36",
        "14:37",
        "14:38",
        "14:39",
        "14:40",
        "14:41",
        "14:42",
        "14:43",
        "14:44",
        "14:45",
        "14:46",
        "14:47",
        "14:48",
        "14:49",
        "14:50",
        "14:51",
        "14:52",
        "14:53",
        "14:54",
        "14:55",
        "14:56",
        "14:57",
        "14:58",
        "14:59",
        "15:00",
        "15:01",
        "15:02",
        "15:03",
        "15:04",
        "15:05",
        "15:06",
        "15:07",
        "15:08",
        "15:09",
        "15:10",
        "15:11",
        "15:12",
        "15:13",
        "15:14",
        "15:15",
        "15:16",
        "15:17",
        "15:18",
        "15:19",
        "15:20",
        "15:21",
        "15:22",
        "15:23",
        "15:24",
        "15:25",
        "15:26",
        "15:27",
        "15:28",
        "15:29",
        "15:30",
        "15:31",
        "15:32",
        "15:33",
        "15:34",
        "15:35",
        "15:36",
        "15:37",
        "15:38",
        "15:39",
        "15:40",
        "15:41",
        "15:42",
        "15:43",
        "15:44",
        "15:45",
        "15:46",
        "15:47",
        "15:48",
        "15:49",
        "15:50",
        "15:51",
        "15:52",
        "15:53",
        "15:54",
        "15:55",
        "15:56",
        "15:57",
        "15:58",
        "15:59",
        "16:00",
        "16:01",
        "16:02",
        "16:03",
        "16:04",
        "16:05",
        "16:06",
        "16:07",
        "16:08",
        "16:09",
        "16:10",
        "16:11",
        "16:12",
        "16:13",
        "16:14",
        "16:15",
        "16:16",
        "16:17",
        "16:18",
        "16:19",
        "16:20",
        "16:21",
        "16:22",
        "16:23",
        "16:24",
        "16:25",
        "16:26",
        "16:27",
        "16:28",
        "16:29",
        "16:30",
        "16:31",
        "16:32",
        "16:33",
        "16:34",
        "16:35",
        "16:36",
        "16:37",
        "16:38",
        "16:39",
        "16:40",
        "16:41",
        "16:42",
        "16:43",
        "16:44",
        "16:45",
        "16:46",
        "16:47",
        "16:48",
        "16:49",
        "16:50",
        "16:51",
        "16:52",
        "16:53",
        "16:54",
        "16:55",
        "16:56",
        "16:57",
        "16:58",
        "16:59",
        "17:00",
        "17:01",
        "17:02",
        "17:03",
        "17:04",
        "17:05",
        "17:06",
        "17:07",
        "17:08",
        "17:09",
        "17:10",
        "17:11",
        "17:12",
        "17:13",
        "17:14",
        "17:15",
        "17:16",
        "17:17",
        "17:18",
        "17:19",
        "17:20",
        "17:21",
        "17:22",
        "17:23",
        "17:24",
        "17:25",
        "17:26",
        "17:27",
        "17:28",
        "17:29",
        "17:30",
        "17:31",
        "17:32",
        "17:33",
        "17:34"
      ]
    },
    "stale": true,
    "age_minutes": 179452
  },
  "tailscale": {
    "updated": "2026-07-25T08:25:48.340948",
    "tailnet": "-",
    "devices": [
      {
        "id": "7265935324976177",
        "name": "antoines-macbook-air.tail6f660f.ts.net",
        "hostname": "Antoine\u2019s MacBook Air",
        "addresses": [
          "100.118.39.110",
          "fd7a:115c:a1e0::aa01:2773"
        ],
        "ipv4": "100.118.39.110",
        "ipv6": "fd7a:115c:a1e0::aa01:2773",
        "os": "macOS",
        "lastSeen": "2026-07-17T14:45:03Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.96.2-td916d8651-gd905b0868",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-11-29T09:56:04Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "2036998147758905",
        "name": "aws-gateway-2a.tail6f660f.ts.net",
        "hostname": "gateway-2a",
        "addresses": [
          "100.100.172.31",
          "fd7a:115c:a1e0::8c01:8a3b"
        ],
        "ipv4": "100.100.172.31",
        "ipv6": "fd7a:115c:a1e0::8c01:8a3b",
        "os": "linux",
        "lastSeen": "2026-07-25T08:25:45Z",
        "authorized": true,
        "tags": [
          "tag:aws"
        ],
        "clientVersion": "1.98.3-ta16e0f20c-ge0c644472",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-01-19T15:45:06Z",
        "online": true,
        "advertisedRoutes": [
          "10.3.0.0/16",
          "10.253.0.0/16",
          "172.31.0.0/16"
        ],
        "enabledRoutes": [
          "10.3.0.0/16",
          "10.253.0.0/16",
          "172.31.0.0/16"
        ],
        "onlineMethod": "lastSeen"
      },
      {
        "id": "6785480049936630",
        "name": "aws-vpn-playground.tail6f660f.ts.net",
        "hostname": "ip-172-31-10-2",
        "addresses": [
          "100.100.31.10",
          "fd7a:115c:a1e0::4901:4e"
        ],
        "ipv4": "100.100.31.10",
        "ipv6": "fd7a:115c:a1e0::4901:4e",
        "os": "linux",
        "lastSeen": "2026-06-29T18:08:02Z",
        "authorized": true,
        "tags": [
          "tag:aws"
        ],
        "clientVersion": "1.98.8-t1241b225b-g0520dfda5",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-02-16T08:40:32Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "8226404080678551",
        "name": "aws-vpn-poc.tail6f660f.ts.net",
        "hostname": "pocvpngw",
        "addresses": [
          "100.100.31.2",
          "fd7a:115c:a1e0::b901:966a"
        ],
        "ipv4": "100.100.31.2",
        "ipv6": "fd7a:115c:a1e0::b901:966a",
        "os": "linux",
        "lastSeen": "2026-07-25T08:25:45Z",
        "authorized": true,
        "tags": [
          "tag:aws"
        ],
        "clientVersion": "1.98.3-ta16e0f20c-ge0c644472",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-02-16T09:21:12Z",
        "online": true,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen"
      },
      {
        "id": "3021158832210335",
        "name": "beta-test-1.tail6f660f.ts.net",
        "hostname": "beta-test-1",
        "addresses": [
          "100.96.174.55",
          "fd7a:115c:a1e0::d01:ae43"
        ],
        "ipv4": "100.96.174.55",
        "ipv6": "fd7a:115c:a1e0::d01:ae43",
        "os": "linux",
        "lastSeen": "2026-06-22T14:30:56Z",
        "authorized": true,
        "tags": [
          "tag:beta",
          "tag:jetson"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-05-06T17:11:10Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "8037448957411505",
        "name": "brian-thinkpad-p16-gen-2.tail6f660f.ts.net",
        "hostname": "brian-ThinkPad-P16-Gen-2",
        "addresses": [
          "100.101.139.123",
          "fd7a:115c:a1e0::8301:8b7b"
        ],
        "ipv4": "100.101.139.123",
        "ipv6": "fd7a:115c:a1e0::8301:8b7b",
        "os": "linux",
        "lastSeen": "2026-05-26T08:44:12Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.3-ta16e0f20c-ge0c644472",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-05-27T17:36:03Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "7720272081829622",
        "name": "chriss-macbook-air.tail6f660f.ts.net",
        "hostname": "Chris\u2019s MacBook Air",
        "addresses": [
          "100.122.190.47",
          "fd7a:115c:a1e0::9701:be32"
        ],
        "ipv4": "100.122.190.47",
        "ipv6": "fd7a:115c:a1e0::9701:be32",
        "os": "macOS",
        "lastSeen": "2026-07-17T08:42:45Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.90.8-tedc9d2245-ged5c52ee2",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2027-01-02T13:40:24Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "6762108904828657",
        "name": "dadh-thinkpad-p16-gen-2.tail6f660f.ts.net",
        "hostname": "dadh-ThinkPad-P16-Gen-2",
        "addresses": [
          "100.102.206.51",
          "fd7a:115c:a1e0::ff34:ce34"
        ],
        "ipv4": "100.102.206.51",
        "ipv6": "fd7a:115c:a1e0::ff34:ce34",
        "os": "linux",
        "lastSeen": "2026-07-14T18:08:11Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.8-t1241b225b-g0520dfda5",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-07-13T18:08:10Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "1475414567712272",
        "name": "dakshs-macbook-pro.tail6f660f.ts.net",
        "hostname": "Daksh\u2019s MacBook Pro",
        "addresses": [
          "100.93.148.44",
          "fd7a:115c:a1e0::7b34:942d"
        ],
        "ipv4": "100.93.148.44",
        "ipv6": "fd7a:115c:a1e0::7b34:942d",
        "os": "macOS",
        "lastSeen": "2026-07-14T18:01:59Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.8-t1241b225b-g0520dfda5",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-07-13T18:01:45Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "3794523276788815",
        "name": "deploy-1-4820-triton.tail6f660f.ts.net",
        "hostname": "Deploy-1-4820-Triton",
        "addresses": [
          "100.64.48.1",
          "fd7a:115c:a1e0::f01:af15"
        ],
        "ipv4": "100.64.48.1",
        "ipv6": "fd7a:115c:a1e0::f01:af15",
        "os": "linux",
        "lastSeen": "2026-06-07T14:15:39Z",
        "authorized": true,
        "tags": [
          "tag:deploy",
          "tag:studio",
          "tag:unifi"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-05-08T11:21:20Z",
        "online": false,
        "advertisedRoutes": [
          "10.44.48.0/20"
        ],
        "enabledRoutes": [
          "10.44.48.0/20"
        ],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "7862019592131729",
        "name": "deploy-2-6420-soho.tail6f660f.ts.net",
        "hostname": "Deploy-2-6420-SOHO",
        "addresses": [
          "100.64.64.1",
          "fd7a:115c:a1e0::2b01:c966"
        ],
        "ipv4": "100.64.64.1",
        "ipv6": "fd7a:115c:a1e0::2b01:c966",
        "os": "linux",
        "lastSeen": "2026-06-28T00:38:14Z",
        "authorized": true,
        "tags": [
          "tag:deploy",
          "tag:unifi"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-05-07T17:19:33Z",
        "online": false,
        "advertisedRoutes": [
          "10.44.64.0/20"
        ],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "6599479729927606",
        "name": "deploy-4-9620.tail6f660f.ts.net",
        "hostname": "Deploy-4-9620",
        "addresses": [
          "100.96.0.1",
          "fd7a:115c:a1e0::401:1984"
        ],
        "ipv4": "100.96.0.1",
        "ipv6": "fd7a:115c:a1e0::401:1984",
        "os": "linux",
        "lastSeen": "2026-06-20T22:59:11Z",
        "authorized": true,
        "tags": [
          "tag:deploy",
          "tag:unifi"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-04-29T16:07:39Z",
        "online": false,
        "advertisedRoutes": [
          "10.44.96.0/20"
        ],
        "enabledRoutes": [
          "10.44.96.0/20"
        ],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "61817917379891",
        "name": "hmnd-deploy-ksa-01.tail6f660f.ts.net",
        "hostname": "hmnd-deploy-ksa-01",
        "addresses": [
          "100.127.54.65",
          "fd7a:115c:a1e0::6901:3647"
        ],
        "ipv4": "100.127.54.65",
        "ipv6": "fd7a:115c:a1e0::6901:3647",
        "os": "linux",
        "lastSeen": "2026-05-13T07:00:08Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.96.4-t8cf541dfd-g62bc84ce7",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-11-03T10:52:43Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "3491843778094613",
        "name": "hmnd-deploy-ksa-gw.tail6f660f.ts.net",
        "hostname": "Deploy-3-8020-KSA",
        "addresses": [
          "100.80.0.1",
          "fd7a:115c:a1e0::7901:f983"
        ],
        "ipv4": "100.80.0.1",
        "ipv6": "fd7a:115c:a1e0::7901:f983",
        "os": "linux",
        "lastSeen": "2026-05-13T06:11:41Z",
        "authorized": true,
        "tags": [
          "tag:deploy",
          "tag:ksa",
          "tag:unifi"
        ],
        "clientVersion": "1.96.4-t8cf541dfd-g62bc84ce7",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-04-26T11:48:40Z",
        "online": false,
        "advertisedRoutes": [
          "10.44.80.0/20"
        ],
        "enabledRoutes": [
          "10.44.80.0/20"
        ],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "3953067551938999",
        "name": "hmnd-fleet.tail6f660f.ts.net",
        "hostname": "hmnd-fleet",
        "addresses": [
          "100.93.118.40",
          "fd7a:115c:a1e0::9d34:7629"
        ],
        "ipv4": "100.93.118.40",
        "ipv6": "fd7a:115c:a1e0::9d34:7629",
        "os": "linux",
        "lastSeen": "2026-06-11T17:58:44Z",
        "authorized": true,
        "tags": [
          "tag:deploy-pi"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-12-06T15:08:44Z",
        "online": false,
        "advertisedRoutes": [
          "10.44.64.0/20"
        ],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "3500277620822349",
        "name": "humanoid-seymur.tail6f660f.ts.net",
        "hostname": "Humanoid-Seymur",
        "addresses": [
          "100.122.203.95",
          "fd7a:115c:a1e0::db34:cb5f"
        ],
        "ipv4": "100.122.203.95",
        "ipv6": "fd7a:115c:a1e0::db34:cb5f",
        "os": "windows",
        "lastSeen": "2026-07-10T23:05:40Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-11-04T19:07:47Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "5387037406477040",
        "name": "inference-4090.tail6f660f.ts.net",
        "hostname": "inference-Predator-PO7-650",
        "addresses": [
          "100.80.0.49",
          "fd7a:115c:a1e0::1b01:8805"
        ],
        "ipv4": "100.80.0.49",
        "ipv6": "fd7a:115c:a1e0::1b01:8805",
        "os": "linux",
        "lastSeen": "2026-07-25T08:25:45Z",
        "authorized": true,
        "tags": [
          "tag:inference"
        ],
        "clientVersion": "1.98.3-ta16e0f20c-ge0c644472",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-02-10T12:11:46Z",
        "online": true,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen"
      },
      {
        "id": "3618390613988832",
        "name": "itmanager-thinkpad-p16-gen-2.tail6f660f.ts.net",
        "hostname": "itmanager-ThinkPad-P16-Gen-2",
        "addresses": [
          "100.77.85.105",
          "fd7a:115c:a1e0::af34:5569"
        ],
        "ipv4": "100.77.85.105",
        "ipv6": "fd7a:115c:a1e0::af34:5569",
        "os": "linux",
        "lastSeen": "2026-04-02T08:44:36Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.96.4-t8cf541dfd-g62bc84ce7",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-09-29T08:38:13Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "5328356529989055",
        "name": "jamesliuhmnd.tail6f660f.ts.net",
        "hostname": "JamesLiuHMND",
        "addresses": [
          "100.83.9.37",
          "fd7a:115c:a1e0::cf34:925"
        ],
        "ipv4": "100.83.9.37",
        "ipv6": "fd7a:115c:a1e0::cf34:925",
        "os": "windows",
        "lastSeen": "2026-07-16T19:04:11Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.2-taaf7caef1-gc4a37aed9",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-10-20T15:19:43Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "5140416881468771",
        "name": "laptop-26pj5csk.tail6f660f.ts.net",
        "hostname": "LAPTOP-26PJ5CSK",
        "addresses": [
          "100.98.229.94",
          "fd7a:115c:a1e0::7537:e55e"
        ],
        "ipv4": "100.98.229.94",
        "ipv6": "fd7a:115c:a1e0::7537:e55e",
        "os": "windows",
        "lastSeen": "2026-07-25T08:25:45Z",
        "authorized": true,
        "tags": [
          "tag:laptop"
        ],
        "clientVersion": "1.98.2-taaf7caef1-gc4a37aed9",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-09-15T16:08:01Z",
        "online": true,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen"
      },
      {
        "id": "6915215378760231",
        "name": "lenovo-p1.tail6f660f.ts.net",
        "hostname": "lenovo-p1",
        "addresses": [
          "100.65.10.84",
          "fd7a:115c:a1e0::2c32:a54"
        ],
        "ipv4": "100.65.10.84",
        "ipv6": "fd7a:115c:a1e0::2c32:a54",
        "os": "linux",
        "lastSeen": "2026-07-24T14:20:30Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-08-10T16:12:08Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "8278930493863134",
        "name": "lon-lpt-007076.tail6f660f.ts.net",
        "hostname": "LON-LPT-007076",
        "addresses": [
          "100.102.37.7",
          "fd7a:115c:a1e0::9b34:2507"
        ],
        "ipv4": "100.102.37.7",
        "ipv6": "fd7a:115c:a1e0::9b34:2507",
        "os": "linux",
        "lastSeen": "2026-07-24T16:38:42Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-10-27T10:20:20Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "1272174567771607",
        "name": "lon-lpt-7096.tail6f660f.ts.net",
        "hostname": "LON-LPT-7096",
        "addresses": [
          "100.108.137.3",
          "fd7a:115c:a1e0::5f34:8903"
        ],
        "ipv4": "100.108.137.3",
        "ipv6": "fd7a:115c:a1e0::5f34:8903",
        "os": "linux",
        "lastSeen": "2026-07-24T18:46:09Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.8-t1241b225b-g0520dfda5",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-10-12T15:22:52Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "858716182225445",
        "name": "luke-pi5-deploy-02.tail6f660f.ts.net",
        "hostname": "luke-pi5-deploy-02",
        "addresses": [
          "100.70.0.92",
          "fd7a:115c:a1e0::501:ee5e"
        ],
        "ipv4": "100.70.0.92",
        "ipv6": "fd7a:115c:a1e0::501:ee5e",
        "os": "linux",
        "lastSeen": "2026-05-11T13:51:18Z",
        "authorized": true,
        "tags": [
          "tag:deploy",
          "tag:deploy-pi",
          "tag:schaeffler"
        ],
        "clientVersion": "1.96.4-t8cf541dfd-g62bc84ce7",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-04-10T13:01:11Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "1732605191987126",
        "name": "luke-pi5-deploy-03.tail6f660f.ts.net",
        "hostname": "luke-pi5-deploy-03",
        "addresses": [
          "100.70.0.93",
          "fd7a:115c:a1e0::4e01:b714"
        ],
        "ipv4": "100.70.0.93",
        "ipv6": "fd7a:115c:a1e0::4e01:b714",
        "os": "linux",
        "lastSeen": "2026-05-11T13:51:11Z",
        "authorized": true,
        "tags": [
          "tag:deploy",
          "tag:deploy-pi",
          "tag:schaeffler"
        ],
        "clientVersion": "1.96.4-t8cf541dfd-g62bc84ce7",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-04-10T13:17:02Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "1422916793240723",
        "name": "lukes-iphone-15-pro-max.tail6f660f.ts.net",
        "hostname": "localhost",
        "addresses": [
          "100.70.0.75",
          "fd7a:115c:a1e0::d201:1e1b"
        ],
        "ipv4": "100.70.0.75",
        "ipv6": "fd7a:115c:a1e0::d201:1e1b",
        "os": "iOS",
        "lastSeen": "2026-06-23T04:31:36Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.5-t8f8fe6a2e-gc1619fb10",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-11-04T18:52:56Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "5347494900875955",
        "name": "lukes-macbook-pro.tail6f660f.ts.net",
        "hostname": "Luke\u2019s MacBook Pro",
        "addresses": [
          "100.70.0.71",
          "fd7a:115c:a1e0::3901:307e"
        ],
        "ipv4": "100.70.0.71",
        "ipv6": "fd7a:115c:a1e0::3901:307e",
        "os": "macOS",
        "lastSeen": "2026-07-07T06:01:08Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.8-t1241b225b-g0520dfda5",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-04-05T09:39:47Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "885503141612568",
        "name": "mhill.tail6f660f.ts.net",
        "hostname": "mhill",
        "addresses": [
          "100.96.50.68",
          "fd7a:115c:a1e0::734:3244"
        ],
        "ipv4": "100.96.50.68",
        "ipv6": "fd7a:115c:a1e0::734:3244",
        "os": "windows",
        "lastSeen": "2026-07-17T15:26:06Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.2-taaf7caef1-gc4a37aed9",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-11-15T16:19:55Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "1362743650479305",
        "name": "mpc.tail6f660f.ts.net",
        "hostname": "mpc",
        "addresses": [
          "100.68.66.112",
          "fd7a:115c:a1e0::8434:4271"
        ],
        "ipv4": "100.68.66.112",
        "ipv6": "fd7a:115c:a1e0::8434:4271",
        "os": "linux",
        "lastSeen": "2026-06-26T21:25:46Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-12-21T02:21:35Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "3746610956872468",
        "name": "orizaba.tail6f660f.ts.net",
        "hostname": "orizaba",
        "addresses": [
          "100.120.96.63",
          "fd7a:115c:a1e0::9232:603f"
        ],
        "ipv4": "100.120.96.63",
        "ipv6": "fd7a:115c:a1e0::9232:603f",
        "os": "linux",
        "lastSeen": "2026-07-08T12:37:35Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.8-t1241b225b-g0520dfda5",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-11-23T08:37:31Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "4795425596163207",
        "name": "pi5-1.tail6f660f.ts.net",
        "hostname": "pi5-1",
        "addresses": [
          "100.79.8.99",
          "fd7a:115c:a1e0::3a34:864"
        ],
        "ipv4": "100.79.8.99",
        "ipv6": "fd7a:115c:a1e0::3a34:864",
        "os": "linux",
        "lastSeen": "2026-07-25T08:25:45Z",
        "authorized": true,
        "tags": [
          "tag:deploy-pi"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-12-21T08:34:49Z",
        "online": true,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen"
      },
      {
        "id": "8312063297633255",
        "name": "pi5-2.tail6f660f.ts.net",
        "hostname": "pi5-2",
        "addresses": [
          "100.106.19.13",
          "fd7a:115c:a1e0::c34:130e"
        ],
        "ipv4": "100.106.19.13",
        "ipv6": "fd7a:115c:a1e0::c34:130e",
        "os": "linux",
        "lastSeen": "2026-07-25T08:25:45Z",
        "authorized": true,
        "tags": [
          "tag:deploy-pi"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-12-21T08:54:16Z",
        "online": true,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen"
      },
      {
        "id": "3367296356905012",
        "name": "pi5-deploy-02-soho.tail6f660f.ts.net",
        "hostname": "pi5-deploy-02-1",
        "addresses": [
          "100.111.179.125",
          "fd7a:115c:a1e0::8b34:b37d"
        ],
        "ipv4": "100.111.179.125",
        "ipv6": "fd7a:115c:a1e0::8b34:b37d",
        "os": "linux",
        "lastSeen": "2026-06-24T08:32:33Z",
        "authorized": true,
        "tags": [
          "tag:deploy-pi"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-11-29T13:44:27Z",
        "online": false,
        "advertisedRoutes": [
          "10.44.64.0/20"
        ],
        "enabledRoutes": [
          "10.44.64.0/20"
        ],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "4210686468355752",
        "name": "pi5-deploy-07-1.tail6f660f.ts.net",
        "hostname": "pi5-deploy-07-1",
        "addresses": [
          "100.107.142.6",
          "fd7a:115c:a1e0::de34:8e07"
        ],
        "ipv4": "100.107.142.6",
        "ipv6": "fd7a:115c:a1e0::de34:8e07",
        "os": "linux",
        "lastSeen": "2026-07-02T14:37:24Z",
        "authorized": true,
        "tags": [
          "tag:deploy-pi"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-12-09T10:52:40Z",
        "online": false,
        "advertisedRoutes": [
          "10.44.144.0/20"
        ],
        "enabledRoutes": [
          "10.44.144.0/20"
        ],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "2942700101077745",
        "name": "pixel-8.tail6f660f.ts.net",
        "hostname": "Pixel 8",
        "addresses": [
          "100.97.229.72",
          "fd7a:115c:a1e0::2e34:e54a"
        ],
        "ipv4": "100.97.229.72",
        "ipv6": "fd7a:115c:a1e0::2e34:e54a",
        "os": "android",
        "lastSeen": "2026-06-16T22:49:07Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.96.4-t8cf541dfd-g980f12083",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-12-13T09:58:24Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "5329296403068838",
        "name": "popocatepetl.tail6f660f.ts.net",
        "hostname": "popocatepetl",
        "addresses": [
          "100.127.129.105",
          "fd7a:115c:a1e0::9d01:8196"
        ],
        "ipv4": "100.127.129.105",
        "ipv6": "fd7a:115c:a1e0::9d01:8196",
        "os": "linux",
        "lastSeen": "2026-06-16T21:31:02Z",
        "authorized": true,
        "tags": [
          "tag:employee",
          "tag:laptop"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-06-20T15:49:04Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "283929436523843",
        "name": "rainbow3.tail6f660f.ts.net",
        "hostname": "Rainbow3",
        "addresses": [
          "100.96.157.86",
          "fd7a:115c:a1e0::2734:9d57"
        ],
        "ipv4": "100.96.157.86",
        "ipv6": "fd7a:115c:a1e0::2734:9d57",
        "os": "linux",
        "lastSeen": "2026-07-25T08:25:45Z",
        "authorized": false,
        "tags": [],
        "clientVersion": "1.98.9-t4fb758c39-g200941d74",
        "updateAvailable": false,
        "keyExpiryDisabled": false,
        "expires": "2026-12-05T14:19:16Z",
        "online": true,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen"
      },
      {
        "id": "1500205739673543",
        "name": "rainbow4.tail6f660f.ts.net",
        "hostname": "Rainbow4",
        "addresses": [
          "100.100.165.15",
          "fd7a:115c:a1e0::db34:a50f"
        ],
        "ipv4": "100.100.165.15",
        "ipv6": "fd7a:115c:a1e0::db34:a50f",
        "os": "linux",
        "lastSeen": "2026-06-16T12:46:28Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.96.4-t8cf541dfd-g62bc84ce7",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-10-17T07:55:04Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "6995663589422730",
        "name": "rainbow7.tail6f660f.ts.net",
        "hostname": "rainbow7",
        "addresses": [
          "100.70.136.121",
          "fd7a:115c:a1e0::2f37:8879"
        ],
        "ipv4": "100.70.136.121",
        "ipv6": "fd7a:115c:a1e0::2f37:8879",
        "os": "linux",
        "lastSeen": "2026-07-24T05:43:15Z",
        "authorized": true,
        "tags": [
          "tag:laptop"
        ],
        "clientVersion": "1.98.9-t4fb758c39-g200941d74",
        "updateAvailable": false,
        "keyExpiryDisabled": true,
        "expires": "2026-09-07T17:36:19Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "629651084367266",
        "name": "raspberrypi.tail6f660f.ts.net",
        "hostname": "raspberrypi",
        "addresses": [
          "100.87.89.89",
          "fd7a:115c:a1e0::9b37:5959"
        ],
        "ipv4": "100.87.89.89",
        "ipv6": "fd7a:115c:a1e0::9b37:5959",
        "os": "linux",
        "lastSeen": "2026-07-25T08:25:45Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.3-ta16e0f20c-ge0c644472",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-09-15T21:34:53Z",
        "online": true,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen"
      },
      {
        "id": "3621150113693641",
        "name": "rnzenha-humanoid.tail6f660f.ts.net",
        "hostname": "rnzenha-humanoid",
        "addresses": [
          "100.114.164.93",
          "fd7a:115c:a1e0::f134:a45e"
        ],
        "ipv4": "100.114.164.93",
        "ipv6": "fd7a:115c:a1e0::f134:a45e",
        "os": "linux",
        "lastSeen": "2026-07-22T13:50:40Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.9-t4fb758c39-g200941d74",
        "updateAvailable": false,
        "keyExpiryDisabled": false,
        "expires": "2027-01-16T10:42:18Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "6262914821689495",
        "name": "samuellehmannpc.tail6f660f.ts.net",
        "hostname": "SamuelLehmannPC",
        "addresses": [
          "100.121.22.17",
          "fd7a:115c:a1e0::7434:1611"
        ],
        "ipv4": "100.121.22.17",
        "ipv6": "fd7a:115c:a1e0::7434:1611",
        "os": "windows",
        "lastSeen": "2026-07-24T15:51:51Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.2-taaf7caef1-gc4a37aed9",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-10-20T19:11:38Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "2291660801273302",
        "name": "spark-24ff.tail6f660f.ts.net",
        "hostname": "spark-24ff",
        "addresses": [
          "100.64.48.100",
          "fd7a:115c:a1e0::a901:8d6d"
        ],
        "ipv4": "100.64.48.100",
        "ipv6": "fd7a:115c:a1e0::a901:8d6d",
        "os": "linux",
        "lastSeen": "2026-05-13T19:31:26Z",
        "authorized": true,
        "tags": [
          "tag:boa",
          "tag:deploy",
          "tag:inference",
          "tag:spark"
        ],
        "clientVersion": "1.96.4-t8cf541dfd-g62bc84ce7",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-05-08T12:30:54Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "8049691996565406",
        "name": "spark-897f.tail6f660f.ts.net",
        "hostname": "spark-897f",
        "addresses": [
          "100.64.64.100",
          "fd7a:115c:a1e0::a01:de88"
        ],
        "ipv4": "100.64.64.100",
        "ipv6": "fd7a:115c:a1e0::a01:de88",
        "os": "linux",
        "lastSeen": "2026-05-13T19:42:38Z",
        "authorized": true,
        "tags": [
          "tag:deploy",
          "tag:inference",
          "tag:spark",
          "tag:vegas"
        ],
        "clientVersion": "1.96.4-t8cf541dfd-g62bc84ce7",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-05-08T12:42:06Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "3580804566483995",
        "name": "stick.tail6f660f.ts.net",
        "hostname": "stick",
        "addresses": [
          "100.72.95.72",
          "fd7a:115c:a1e0::9e32:5f48"
        ],
        "ipv4": "100.72.95.72",
        "ipv6": "fd7a:115c:a1e0::9e32:5f48",
        "os": "linux",
        "lastSeen": "2026-07-25T08:25:45Z",
        "authorized": true,
        "tags": [
          "tag:alpha",
          "tag:jetson"
        ],
        "clientVersion": "1.98.3-ta16e0f20c-ge0c644472",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-08-10T12:04:18Z",
        "online": true,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen"
      },
      {
        "id": "4525610063016589",
        "name": "umi-0001.tail6f660f.ts.net",
        "hostname": "umi-0001",
        "addresses": [
          "100.119.254.73",
          "fd7a:115c:a1e0::c632:fe49"
        ],
        "ipv4": "100.119.254.73",
        "ipv6": "fd7a:115c:a1e0::c632:fe49",
        "os": "linux",
        "lastSeen": "2026-07-16T10:37:54Z",
        "authorized": true,
        "tags": [
          "tag:gripper-dc",
          "tag:jetson",
          "tag:jetson-nano"
        ],
        "clientVersion": "1.98.3-ta16e0f20c-ge0c644472",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-08-03T15:30:55Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "568357605798232",
        "name": "umi-0002-1.tail6f660f.ts.net",
        "hostname": "umi-0002",
        "addresses": [
          "100.80.209.102",
          "fd7a:115c:a1e0::2632:d166"
        ],
        "ipv4": "100.80.209.102",
        "ipv6": "fd7a:115c:a1e0::2632:d166",
        "os": "linux",
        "lastSeen": "2026-07-16T10:43:39Z",
        "authorized": true,
        "tags": [
          "tag:external",
          "tag:gripper-dc",
          "tag:jetson",
          "tag:jetson-nano"
        ],
        "clientVersion": "1.98.3-ta16e0f20c-ge0c644472",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-08-02T10:47:04Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "991340983889709",
        "name": "umi-0003.tail6f660f.ts.net",
        "hostname": "umi-0003",
        "addresses": [
          "100.95.188.76",
          "fd7a:115c:a1e0::4232:bc4c"
        ],
        "ipv4": "100.95.188.76",
        "ipv6": "fd7a:115c:a1e0::4232:bc4c",
        "os": "linux",
        "lastSeen": "2026-05-21T20:46:13Z",
        "authorized": true,
        "tags": [
          "tag:external",
          "tag:gripper-dc",
          "tag:jetson",
          "tag:jetson-nano"
        ],
        "clientVersion": "1.94.1-t62c6f1cd7-g09fea6572",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-08-04T11:31:35Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "3716584622411392",
        "name": "win-i61vm41q18d.tail6f660f.ts.net",
        "hostname": "WIN-I61VM41Q18D",
        "addresses": [
          "100.110.185.112",
          "fd7a:115c:a1e0::e332:b970"
        ],
        "ipv4": "100.110.185.112",
        "ipv6": "fd7a:115c:a1e0::e332:b970",
        "os": "windows",
        "lastSeen": "2026-07-24T13:45:26Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.8-t1241b225b-g0520dfda5",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2027-01-09T14:51:37Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "108528810469149",
        "name": "xdof-gripper-1.tail6f660f.ts.net",
        "hostname": "xdof-gripper-1",
        "addresses": [
          "100.80.3.61",
          "fd7a:115c:a1e0::9e32:33d"
        ],
        "ipv4": "100.80.3.61",
        "ipv6": "fd7a:115c:a1e0::9e32:33d",
        "os": "linux",
        "lastSeen": "2026-07-23T14:19:43Z",
        "authorized": true,
        "tags": [
          "tag:external",
          "tag:gripper-dc",
          "tag:jetson",
          "tag:jetson-nano"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-08-08T17:14:29Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "8138302359220289",
        "name": "xdof-gripper-2.tail6f660f.ts.net",
        "hostname": "xdof-gripper-2",
        "addresses": [
          "100.109.167.28",
          "fd7a:115c:a1e0::9032:a71c"
        ],
        "ipv4": "100.109.167.28",
        "ipv6": "fd7a:115c:a1e0::9032:a71c",
        "os": "linux",
        "lastSeen": "2026-07-25T08:25:45Z",
        "authorized": true,
        "tags": [
          "tag:external",
          "tag:gripper-dc",
          "tag:jetson",
          "tag:jetson-nano"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-07-14T14:17:02Z",
        "online": true,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen"
      },
      {
        "id": "1780184856490625",
        "name": "xdof-gripper-4.tail6f660f.ts.net",
        "hostname": "xdof-gripper-4",
        "addresses": [
          "100.120.166.17",
          "fd7a:115c:a1e0::b701:a611"
        ],
        "ipv4": "100.120.166.17",
        "ipv6": "fd7a:115c:a1e0::b701:a611",
        "os": "linux",
        "lastSeen": "2026-04-02T08:42:54Z",
        "authorized": true,
        "tags": [
          "tag:external",
          "tag:gripper-dc",
          "tag:jetson",
          "tag:jetson-nano"
        ],
        "clientVersion": "1.94.2-t0a29cf18b-g3f044c9f6",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-05-26T10:31:36Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "2226251972606262",
        "name": "xdof-gripper-5.tail6f660f.ts.net",
        "hostname": "xdof-gripper-5",
        "addresses": [
          "100.81.80.90",
          "fd7a:115c:a1e0::8a01:505b"
        ],
        "ipv4": "100.81.80.90",
        "ipv6": "fd7a:115c:a1e0::8a01:505b",
        "os": "linux",
        "lastSeen": "2026-01-09T17:38:59Z",
        "authorized": true,
        "tags": [
          "tag:gripper-dc",
          "tag:jetson",
          "tag:jetson-nano"
        ],
        "clientVersion": "1.90.9-t6e8a4f2de-g19196f361",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-06-08T10:47:32Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "7732312351527251",
        "name": "xdof-gripper-6.tail6f660f.ts.net",
        "hostname": "xdof-gripper-6",
        "addresses": [
          "100.107.241.42",
          "fd7a:115c:a1e0::8501:f177"
        ],
        "ipv4": "100.107.241.42",
        "ipv6": "fd7a:115c:a1e0::8501:f177",
        "os": "linux",
        "lastSeen": "2026-04-14T08:18:13Z",
        "authorized": true,
        "tags": [
          "tag:external",
          "tag:gripper-dc",
          "tag:jetson",
          "tag:jetson-nano"
        ],
        "clientVersion": "1.94.1-t62c6f1cd7-g09fea6572",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-06-10T11:04:22Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "3913788092930849",
        "name": "xdof-gripper-8.tail6f660f.ts.net",
        "hostname": "xdof-gripper-8",
        "addresses": [
          "100.78.108.120",
          "fd7a:115c:a1e0::8d01:6c85"
        ],
        "ipv4": "100.78.108.120",
        "ipv6": "fd7a:115c:a1e0::8d01:6c85",
        "os": "linux",
        "lastSeen": "2026-04-09T11:24:10Z",
        "authorized": true,
        "tags": [
          "tag:external",
          "tag:gripper-dc",
          "tag:jetson",
          "tag:jetson-nano"
        ],
        "clientVersion": "1.94.1-t62c6f1cd7-g09fea6572",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-06-16T17:34:12Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "3390725923546977",
        "name": "xdof-gripper-9.tail6f660f.ts.net",
        "hostname": "xdof-gripper-9",
        "addresses": [
          "100.104.241.42",
          "fd7a:115c:a1e0::7c34:f12a"
        ],
        "ipv4": "100.104.241.42",
        "ipv6": "fd7a:115c:a1e0::7c34:f12a",
        "os": "linux",
        "lastSeen": "2026-07-03T16:30:57Z",
        "authorized": true,
        "tags": [
          "tag:gripper-dc",
          "tag:jetson",
          "tag:jetson-nano"
        ],
        "clientVersion": "1.98.4-t9e69045b2-ged3a62f14",
        "updateAvailable": true,
        "keyExpiryDisabled": true,
        "expires": "2026-10-11T16:33:25Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      },
      {
        "id": "3512057773284932",
        "name": "xitle.tail6f660f.ts.net",
        "hostname": "xitle",
        "addresses": [
          "100.77.170.3",
          "fd7a:115c:a1e0::9801:aa08"
        ],
        "ipv4": "100.77.170.3",
        "ipv6": "fd7a:115c:a1e0::9801:aa08",
        "os": "linux",
        "lastSeen": "2026-07-24T16:30:21Z",
        "authorized": true,
        "tags": [],
        "clientVersion": "1.98.3-ta16e0f20c-ge0c644472",
        "updateAvailable": true,
        "keyExpiryDisabled": false,
        "expires": "2026-10-21T10:13:50Z",
        "online": false,
        "advertisedRoutes": [],
        "enabledRoutes": [],
        "onlineMethod": "lastSeen-stale"
      }
    ],
    "dns": {
      "nameservers": [],
      "searchPaths": [
        "lan.thehumanoid.ai",
        "thehumanoid.cloud",
        "hmnd.ai",
        "infra.hmnd.ai",
        "robots.hmnd.ai"
      ],
      "splitDns": {}
    },
    "subnetRouters": [
      {
        "name": "aws-gateway-2a.tail6f660f.ts.net",
        "hostname": "gateway-2a",
        "ipv4": "100.100.172.31",
        "online": true,
        "enabledRoutes": [
          "10.3.0.0/16",
          "10.253.0.0/16",
          "172.31.0.0/16"
        ],
        "advertisedRoutes": [
          "10.3.0.0/16",
          "10.253.0.0/16",
          "172.31.0.0/16"
        ],
        "tags": [
          "tag:aws"
        ]
      },
      {
        "name": "deploy-1-4820-triton.tail6f660f.ts.net",
        "hostname": "Deploy-1-4820-Triton",
        "ipv4": "100.64.48.1",
        "online": false,
        "enabledRoutes": [
          "10.44.48.0/20"
        ],
        "advertisedRoutes": [
          "10.44.48.0/20"
        ],
        "tags": [
          "tag:deploy",
          "tag:studio",
          "tag:unifi"
        ]
      },
      {
        "name": "deploy-2-6420-soho.tail6f660f.ts.net",
        "hostname": "Deploy-2-6420-SOHO",
        "ipv4": "100.64.64.1",
        "online": false,
        "enabledRoutes": [],
        "advertisedRoutes": [
          "10.44.64.0/20"
        ],
        "tags": [
          "tag:deploy",
          "tag:unifi"
        ]
      },
      {
        "name": "deploy-4-9620.tail6f660f.ts.net",
        "hostname": "Deploy-4-9620",
        "ipv4": "100.96.0.1",
        "online": false,
        "enabledRoutes": [
          "10.44.96.0/20"
        ],
        "advertisedRoutes": [
          "10.44.96.0/20"
        ],
        "tags": [
          "tag:deploy",
          "tag:unifi"
        ]
      },
      {
        "name": "hmnd-deploy-ksa-gw.tail6f660f.ts.net",
        "hostname": "Deploy-3-8020-KSA",
        "ipv4": "100.80.0.1",
        "online": false,
        "enabledRoutes": [
          "10.44.80.0/20"
        ],
        "advertisedRoutes": [
          "10.44.80.0/20"
        ],
        "tags": [
          "tag:deploy",
          "tag:ksa",
          "tag:unifi"
        ]
      },
      {
        "name": "hmnd-fleet.tail6f660f.ts.net",
        "hostname": "hmnd-fleet",
        "ipv4": "100.93.118.40",
        "online": false,
        "enabledRoutes": [],
        "advertisedRoutes": [
          "10.44.64.0/20"
        ],
        "tags": [
          "tag:deploy-pi"
        ]
      },
      {
        "name": "pi5-deploy-02-soho.tail6f660f.ts.net",
        "hostname": "pi5-deploy-02-1",
        "ipv4": "100.111.179.125",
        "online": false,
        "enabledRoutes": [
          "10.44.64.0/20"
        ],
        "advertisedRoutes": [
          "10.44.64.0/20"
        ],
        "tags": [
          "tag:deploy-pi"
        ]
      },
      {
        "name": "pi5-deploy-07-1.tail6f660f.ts.net",
        "hostname": "pi5-deploy-07-1",
        "ipv4": "100.107.142.6",
        "online": false,
        "enabledRoutes": [
          "10.44.144.0/20"
        ],
        "advertisedRoutes": [
          "10.44.144.0/20"
        ],
        "tags": [
          "tag:deploy-pi"
        ]
      }
    ],
    "robotMap": {
      "WA3": [
        {
          "name": "rainbow3.tail6f660f.ts.net",
          "hostname": "Rainbow3",
          "ipv4": "100.96.157.86",
          "online": true,
          "lastSeen": "2026-07-25T08:25:45Z",
          "component": "laptop",
          "os": "linux",
          "tags": [],
          "advertisedRoutes": [],
          "enabledRoutes": []
        }
      ],
      "WA4": [
        {
          "name": "rainbow4.tail6f660f.ts.net",
          "hostname": "Rainbow4",
          "ipv4": "100.100.165.15",
          "online": false,
          "lastSeen": "2026-06-16T12:46:28Z",
          "component": "laptop",
          "os": "linux",
          "tags": [],
          "advertisedRoutes": [],
          "enabledRoutes": []
        }
      ],
      "WA7": [
        {
          "name": "rainbow7.tail6f660f.ts.net",
          "hostname": "rainbow7",
          "ipv4": "100.70.136.121",
          "online": false,
          "lastSeen": "2026-07-24T05:43:15Z",
          "component": "laptop",
          "os": "linux",
          "tags": [
            "tag:laptop"
          ],
          "advertisedRoutes": [],
          "enabledRoutes": []
        }
      ]
    },
    "tagGroups": [
      {
        "tag": "tag:alpha",
        "label": "Robot RTPCs",
        "devices": [
          {
            "name": "stick.tail6f660f.ts.net",
            "hostname": "stick",
            "ipv4": "100.72.95.72",
            "online": true,
            "os": "linux",
            "lastSeen": "2026-07-25T08:25:45Z",
            "tags": [
              "tag:alpha",
              "tag:jetson"
            ],
            "advertisedRoutes": [],
            "enabledRoutes": []
          }
        ],
        "aclRules": []
      },
      {
        "tag": "tag:inference",
        "label": "Inference Servers",
        "devices": [
          {
            "name": "inference-4090.tail6f660f.ts.net",
            "hostname": "inference-Predator-PO7-650",
            "ipv4": "100.80.0.49",
            "online": true,
            "os": "linux",
            "lastSeen": "2026-07-25T08:25:45Z",
            "tags": [
              "tag:inference"
            ],
            "advertisedRoutes": [],
            "enabledRoutes": []
          },
          {
            "name": "spark-24ff.tail6f660f.ts.net",
            "hostname": "spark-24ff",
            "ipv4": "100.64.48.100",
            "online": false,
            "os": "linux",
            "lastSeen": "2026-05-13T19:31:26Z",
            "tags": [
              "tag:boa",
              "tag:deploy",
              "tag:inference",
              "tag:spark"
            ],
            "advertisedRoutes": [],
            "enabledRoutes": []
          },
          {
            "name": "spark-897f.tail6f660f.ts.net",
            "hostname": "spark-897f",
            "ipv4": "100.64.64.100",
            "online": false,
            "os": "linux",
            "lastSeen": "2026-05-13T19:42:38Z",
            "tags": [
              "tag:deploy",
              "tag:inference",
              "tag:spark",
              "tag:vegas"
            ],
            "advertisedRoutes": [],
            "enabledRoutes": []
          }
        ],
        "aclRules": []
      },
      {
        "tag": "tag:deploy-pi",
        "label": "Deploy Pis",
        "devices": [
          {
            "name": "hmnd-fleet.tail6f660f.ts.net",
            "hostname": "hmnd-fleet",
            "ipv4": "100.93.118.40",
            "online": false,
            "os": "linux",
            "lastSeen": "2026-06-11T17:58:44Z",
            "tags": [
              "tag:deploy-pi"
            ],
            "advertisedRoutes": [
              "10.44.64.0/20"
            ],
            "enabledRoutes": []
          },
          {
            "name": "luke-pi5-deploy-02.tail6f660f.ts.net",
            "hostname": "luke-pi5-deploy-02",
            "ipv4": "100.70.0.92",
            "online": false,
            "os": "linux",
            "lastSeen": "2026-05-11T13:51:18Z",
            "tags": [
              "tag:deploy",
              "tag:deploy-pi",
              "tag:schaeffler"
            ],
            "advertisedRoutes": [],
            "enabledRoutes": []
          },
          {
            "name": "luke-pi5-deploy-03.tail6f660f.ts.net",
            "hostname": "luke-pi5-deploy-03",
            "ipv4": "100.70.0.93",
            "online": false,
            "os": "linux",
            "lastSeen": "2026-05-11T13:51:11Z",
            "tags": [
              "tag:deploy",
              "tag:deploy-pi",
              "tag:schaeffler"
            ],
            "advertisedRoutes": [],
            "enabledRoutes": []
          },
          {
            "name": "pi5-1.tail6f660f.ts.net",
            "hostname": "pi5-1",
            "ipv4": "100.79.8.99",
            "online": true,
            "os": "linux",
            "lastSeen": "2026-07-25T08:25:45Z",
            "tags": [
              "tag:deploy-pi"
            ],
            "advertisedRoutes": [],
            "enabledRoutes": []
          },
          {
            "name": "pi5-2.tail6f660f.ts.net",
            "hostname": "pi5-2",
            "ipv4": "100.106.19.13",
            "online": true,
            "os": "linux",
            "lastSeen": "2026-07-25T08:25:45Z",
            "tags": [
              "tag:deploy-pi"
            ],
            "advertisedRoutes": [],
            "enabledRoutes": []
          },
          {
            "name": "pi5-deploy-02-soho.tail6f660f.ts.net",
            "hostname": "pi5-deploy-02-1",
            "ipv4": "100.111.179.125",
            "online": false,
            "os": "linux",
            "lastSeen": "2026-06-24T08:32:33Z",
            "tags": [
              "tag:deploy-pi"
            ],
            "advertisedRoutes": [
              "10.44.64.0/20"
            ],
            "enabledRoutes": [
              "10.44.64.0/20"
            ]
          },
          {
            "name": "pi5-deploy-07-1.tail6f660f.ts.net",
            "hostname": "pi5-deploy-07-1",
            "ipv4": "100.107.142.6",
            "online": false,
            "os": "linux",
            "lastSeen": "2026-07-02T14:37:24Z",
            "tags": [
              "tag:deploy-pi"
            ],
            "advertisedRoutes": [
              "10.44.144.0/20"
            ],
            "enabledRoutes": [
              "10.44.144.0/20"
            ]
          }
        ],
        "aclRules": []
      }
    ],
    "acl": []
  },
  "saas_probe": {
    "updated": "2026-07-25T08:25:48.326603+00:00",
    "region": "eu-central-1",
    "instance_id": "",
    "status": "ok",
    "offices": {
      "london": {
        "avg_latency_ms": null,
        "min_latency_ms": null,
        "max_latency_ms": null,
        "loss_pct": 100,
        "jitter_ms": null,
        "tcp_443_ms": null,
        "icmp_blocked": true,
        "samples": 60
      },
      "vancouver": {
        "avg_latency_ms": 144.6,
        "min_latency_ms": 144.5,
        "max_latency_ms": 144.8,
        "loss_pct": 0,
        "jitter_ms": 0.09,
        "tcp_443_ms": null,
        "icmp_blocked": false,
        "samples": 60
      }
    },
    "endpoints": {
      "/tc": {
        "ttfb_ms": 44.0,
        "tcp_ms": 3.3,
        "tls_ms": 14.8,
        "dns_ms": 2.4,
        "total_ms": 44.1,
        "bytes": 759,
        "http_code": 404
      },
      "/awc": {
        "ttfb_ms": 47.3,
        "tcp_ms": 1.5,
        "tls_ms": 12.9,
        "dns_ms": 0.6,
        "total_ms": 47.6,
        "bytes": 702,
        "http_code": 200
      },
      "/awc/loginservice/sa": {
        "ttfb_ms": 42.7,
        "tcp_ms": 1.3,
        "tls_ms": 13.0,
        "dns_ms": 0.6,
        "total_ms": 42.8,
        "bytes": 155,
        "http_code": 404
      },
      "dynamodb.eu-central-1.amazonaws.com": {
        "ttfb_ms": 16.9,
        "tcp_ms": 3.2,
        "tls_ms": 16.0,
        "dns_ms": 2.6,
        "total_ms": 17.0,
        "bytes": 45,
        "http_code": 200
      }
    },
    "burst": {
      "endpoint": "/tc",
      "requests": 10,
      "first_ttfb_ms": 44.0,
      "reuse_ttfb_ms": 36.5,
      "avg_ttfb_ms": 37.2,
      "connection_reuse_benefit_ms": 7.5
    },
    "idle_test": {
      "endpoint": "/tc",
      "idle_seconds": 30,
      "ttfb_after_idle_ms": 38.0,
      "reconnected": true
    },
    "dns": {
      "query_ms": 0,
      "answer_ip": ""
    },
    "mtr": {
      "london": {
        "timestamp": "2026-07-25T08:20:34Z",
        "hops": [
          {
            "hop": 1,
            "host": "242.1.92.161",
            "asn": "AS???",
            "avg_ms": 4.0,
            "best_ms": 1.7,
            "worst_ms": 12.4,
            "loss_pct": 0.0
          },
          {
            "hop": 2,
            "host": "99.82.179.174",
            "asn": "AS16509",
            "avg_ms": 1.9,
            "best_ms": 1.8,
            "worst_ms": 2.2,
            "loss_pct": 0.0
          },
          {
            "hop": 3,
            "host": "99.82.179.175",
            "asn": "AS16509",
            "avg_ms": 1.3,
            "best_ms": 1.3,
            "worst_ms": 1.4,
            "loss_pct": 0.0
          },
          {
            "hop": 4,
            "host": "???",
            "asn": "AS???",
            "avg_ms": 0.0,
            "best_ms": 0.0,
            "worst_ms": 0.0,
            "loss_pct": 100.0
          },
          {
            "hop": 5,
            "host": "212.133.44.18",
            "asn": "AS3356",
            "avg_ms": 14.2,
            "best_ms": 14.1,
            "worst_ms": 14.3,
            "loss_pct": 0.0
          },
          {
            "hop": 6,
            "host": "83.143.228.113",
            "asn": "AS5631",
            "avg_ms": 14.5,
            "best_ms": 14.4,
            "worst_ms": 14.5,
            "loss_pct": 0.0
          },
          {
            "hop": 7,
            "host": "83.143.228.9",
            "asn": "AS5631",
            "avg_ms": 14.9,
            "best_ms": 14.7,
            "worst_ms": 15.1,
            "loss_pct": 0.0
          },
          {
            "hop": 8,
            "host": "???",
            "asn": "AS???",
            "avg_ms": 0.0,
            "best_ms": 0.0,
            "worst_ms": 0.0,
            "loss_pct": 100.0
          }
        ],
        "analysis": "The path from Frankfurt to london traverses 8 hops across 3 autonomous systems (Amazon AWS, Lumen/Level3, Luminet), reaching 0.0ms total round-trip. The largest jump (+14ms) is at hop 5 (Lumen/Level3). Final hop shows 100.0% packet loss, which may affect NX performance."
      },
      "vancouver": {
        "timestamp": "2026-07-25T08:20:34Z",
        "hops": [
          {
            "hop": 1,
            "host": "242.1.101.35",
            "asn": "AS???",
            "avg_ms": 1.5,
            "best_ms": 1.3,
            "worst_ms": 1.6,
            "loss_pct": 0.0
          },
          {
            "hop": 2,
            "host": "100.100.2.66",
            "asn": "AS???",
            "avg_ms": 5.6,
            "best_ms": 1.0,
            "worst_ms": 22.0,
            "loss_pct": 0.0
          },
          {
            "hop": 3,
            "host": "62.115.58.120",
            "asn": "AS1299",
            "avg_ms": 16.3,
            "best_ms": 1.7,
            "worst_ms": 64.5,
            "loss_pct": 0.0
          },
          {
            "hop": 4,
            "host": "62.115.132.210",
            "asn": "AS1299",
            "avg_ms": 18.7,
            "best_ms": 18.6,
            "worst_ms": 18.8,
            "loss_pct": 40.0
          },
          {
            "hop": 5,
            "host": "62.115.122.138",
            "asn": "AS1299",
            "avg_ms": 27.3,
            "best_ms": 27.1,
            "worst_ms": 27.5,
            "loss_pct": 0.0
          },
          {
            "hop": 6,
            "host": "62.115.133.238",
            "asn": "AS1299",
            "avg_ms": 30.4,
            "best_ms": 30.3,
            "worst_ms": 30.6,
            "loss_pct": 0.0
          },
          {
            "hop": 7,
            "host": "62.115.139.246",
            "asn": "AS1299",
            "avg_ms": 84.0,
            "best_ms": 83.6,
            "worst_ms": 84.6,
            "loss_pct": 20.0
          },
          {
            "hop": 8,
            "host": "62.115.132.135",
            "asn": "AS1299",
            "avg_ms": 99.7,
            "best_ms": 99.4,
            "worst_ms": 99.9,
            "loss_pct": 0.0
          },
          {
            "hop": 9,
            "host": "62.115.132.155",
            "asn": "AS1299",
            "avg_ms": 141.2,
            "best_ms": 140.9,
            "worst_ms": 141.4,
            "loss_pct": 0.0
          },
          {
            "hop": 10,
            "host": "213.248.67.225",
            "asn": "AS1299",
            "avg_ms": 141.5,
            "best_ms": 141.2,
            "worst_ms": 141.7,
            "loss_pct": 0.0
          },
          {
            "hop": 11,
            "host": "66.163.76.65",
            "asn": "AS6327",
            "avg_ms": 144.7,
            "best_ms": 144.0,
            "worst_ms": 145.8,
            "loss_pct": 0.0
          },
          {
            "hop": 12,
            "host": "72.139.134.70",
            "asn": "AS812",
            "avg_ms": 144.8,
            "best_ms": 144.2,
            "worst_ms": 146.6,
            "loss_pct": 0.0
          },
          {
            "hop": 13,
            "host": "???",
            "asn": "AS???",
            "avg_ms": 0.0,
            "best_ms": 0.0,
            "worst_ms": 0.0,
            "loss_pct": 100.0
          },
          {
            "hop": 14,
            "host": "97.111.11.226",
            "asn": "AS812",
            "avg_ms": 144.9,
            "best_ms": 144.8,
            "worst_ms": 145.0,
            "loss_pct": 0.0
          }
        ],
        "analysis": "The path from Frankfurt to vancouver traverses 14 hops across 3 autonomous systems (Telia (backbone), Shaw, Rogers), reaching 144.9ms total round-trip. The largest latency jump (+145ms) occurs at hop 14 (Rogers), likely a long-distance fiber crossing."
      }
    },
    "trends": {
      "vancouver_latency": [
        144.6,
        144.7,
        144.7,
        144.6,
        144.7,
        144.6,
        144.6,
        144.6,
        144.6,
        144.7,
        144.7,
        144.7,
        144.7,
        144.6,
        144.6,
        144.6,
        144.6,
        144.6,
        144.7,
        144.5,
        144.6,
        144.6,
        144.5,
        144.6,
        144.7,
        144.6,
        144.6,
        144.7,
        144.7,
        144.7,
        144.6,
        144.6,
        144.7,
        144.7,
        144.6,
        144.7,
        144.8,
        144.6,
        144.6,
        144.6,
        144.7,
        144.7,
        144.7,
        144.6,
        144.7,
        144.6,
        144.6,
        144.6,
        144.7,
        144.6,
        144.6,
        144.8,
        144.6,
        144.6,
        144.6,
        144.8,
        144.7,
        144.7,
        144.6,
        144.6
      ],
      "tc_ttfb": [
        39.3,
        32.4,
        35.4,
        39.0,
        33.7,
        34.0,
        35.4,
        43.5,
        36.2,
        36.5,
        34.6,
        24.1,
        41.4,
        39.3,
        36.9,
        36.2,
        41.1,
        41.6,
        41.4,
        42.3,
        32.5,
        40.9,
        39.1,
        34.8,
        40.6,
        24.6,
        34.2,
        44.1,
        31.6,
        37.1,
        38.4,
        35.4,
        30.6,
        40.8,
        34.2,
        28.2,
        39.6,
        38.0,
        32.9,
        42.7,
        33.7,
        36.5,
        33.3,
        40.5,
        41.3,
        43.1,
        36.6,
        35.6,
        44.7,
        37.1,
        43.2,
        31.6,
        39.0,
        41.0,
        38.6,
        36.5,
        36.6,
        35.9,
        43.8,
        44.0
      ],
      "timestamps": [
        "07:26",
        "07:27",
        "07:28",
        "07:29",
        "07:30",
        "07:31",
        "07:32",
        "07:33",
        "07:34",
        "07:35",
        "07:36",
        "07:37",
        "07:38",
        "07:39",
        "07:40",
        "07:41",
        "07:42",
        "07:43",
        "07:44",
        "07:45",
        "07:46",
        "07:47",
        "07:48",
        "07:49",
        "07:50",
        "07:51",
        "07:52",
        "07:53",
        "07:54",
        "07:55",
        "07:56",
        "07:57",
        "07:58",
        "07:59",
        "08:00",
        "08:01",
        "08:02",
        "08:03",
        "08:04",
        "08:05",
        "08:06",
        "08:07",
        "08:08",
        "08:09",
        "08:10",
        "08:11",
        "08:12",
        "08:13",
        "08:14",
        "08:15",
        "08:16",
        "08:17",
        "08:18",
        "08:19",
        "08:20",
        "08:21",
        "08:22",
        "08:23",
        "08:24",
        "08:25"
      ]
    }
  },
  "confluence": {
    "updated": "2026-07-25T08:25:52.794255+00:00",
    "space_key": "ROBOT",
    "space_name": "Home",
    "total_pages": 551,
    "total_space_pages": 2222,
    "total_authors": 142,
    "last_page_modified": "2026-07-24T20:01:11.472Z",
    "sections": [
      {
        "id": "568131598",
        "title": "Active Programs",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/568131598",
        "last_modified": "2025-10-06T01:13:17.063Z",
        "children": []
      },
      {
        "id": "1232142338",
        "title": "App architecture",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1232142338",
        "last_modified": "2025-11-05T16:24:01.769Z",
        "children": []
      },
      {
        "id": "568229913",
        "title": "Build Units",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/568229913",
        "last_modified": "2025-05-01T12:42:29.890Z",
        "children": [
          {
            "id": "574783622",
            "title": "Actuators [IPT] -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783622",
            "last_modified": "2025-02-19T15:47:37.736Z",
            "children": [
              {
                "id": "574783667",
                "title": "Actuators - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783667",
                "last_modified": "2025-01-31T22:30:23.738Z",
                "children": []
              },
              {
                "id": "574783687",
                "title": "Actuators - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783687",
                "last_modified": "2025-01-31T22:30:24.002Z",
                "children": []
              }
            ]
          },
          {
            "id": "991363188",
            "title": "Alpha Manufacturing Process Flow",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/991363188",
            "last_modified": "2025-11-25T17:32:18.607Z",
            "children": []
          },
          {
            "id": "574783707",
            "title": "Arms [IPT] -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783707",
            "last_modified": "2025-02-19T15:43:15.425Z",
            "children": [
              {
                "id": "574783752",
                "title": "Arms - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783752",
                "last_modified": "2025-01-31T22:30:49.743Z",
                "children": []
              },
              {
                "id": "574783772",
                "title": "Arms - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783772",
                "last_modified": "2025-01-31T22:30:50.019Z",
                "children": []
              }
            ]
          },
          {
            "id": "574816376",
            "title": "Battery [IPT] -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574816376",
            "last_modified": "2025-02-19T15:44:48.491Z",
            "children": [
              {
                "id": "574816421",
                "title": "Battery - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574816421",
                "last_modified": "2025-01-31T22:28:56.051Z",
                "children": []
              },
              {
                "id": "574816441",
                "title": "Battery - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574816441",
                "last_modified": "2025-01-31T22:28:56.366Z",
                "children": []
              },
              {
                "id": "408748277",
                "title": "Power System",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/408748277",
                "last_modified": "2024-11-18T16:46:23.662Z",
                "children": [
                  {
                    "id": "471891972",
                    "title": "Battery Architecture and Specification Proposals (Draft)",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/471891972",
                    "last_modified": "2024-12-11T12:44:52.721Z",
                    "children": []
                  },
                  {
                    "id": "428539928",
                    "title": "Power System Functions",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/428539928",
                    "last_modified": "2024-11-18T17:02:38.194Z",
                    "children": []
                  },
                  {
                    "id": "698810426",
                    "title": "Status Updates",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/698810426",
                    "last_modified": "2025-03-14T11:39:19.296Z",
                    "children": []
                  },
                  {
                    "id": "428146701",
                    "title": "Suppliers",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/428146701",
                    "last_modified": "2024-11-18T16:33:31.764Z",
                    "children": []
                  },
                  {
                    "id": "427950115",
                    "title": "Syb-system High-level Expectations",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/427950115",
                    "last_modified": "2024-11-18T17:03:12.493Z",
                    "children": []
                  },
                  {
                    "id": "427131215",
                    "title": "System Architecture",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/427131215",
                    "last_modified": "2024-11-18T16:17:05.899Z",
                    "children": [
                      {
                        "id": "428572735",
                        "title": "Architecture proposals",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/428572735",
                        "last_modified": "2024-11-18T16:31:14.483Z",
                        "children": []
                      },
                      {
                        "id": "427098433",
                        "title": "Boundary diagram",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/427098433",
                        "last_modified": "2024-12-16T19:55:33.810Z",
                        "children": []
                      },
                      {
                        "id": "428605474",
                        "title": "HW Requirements",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/428605474",
                        "last_modified": "2024-11-18T16:16:10.627Z",
                        "children": []
                      },
                      {
                        "id": "428638223",
                        "title": "SW Requirements",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/428638223",
                        "last_modified": "2024-11-18T16:27:57.730Z",
                        "children": []
                      },
                      {
                        "id": "427819041",
                        "title": "Technical Implementation",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/427819041",
                        "last_modified": "2024-11-18T17:03:55.104Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "428343319",
                    "title": "System Devices/HW Components",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/428343319",
                    "last_modified": "2024-11-18T16:16:39.995Z",
                    "children": [
                      {
                        "id": "428277784",
                        "title": "BMS",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/428277784",
                        "last_modified": "2024-11-18T16:27:34.881Z",
                        "children": []
                      },
                      {
                        "id": "427851846",
                        "title": "Battery Module",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/427851846",
                        "last_modified": "2024-11-18T16:28:14.383Z",
                        "children": []
                      },
                      {
                        "id": "428408853",
                        "title": "Cell",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/428408853",
                        "last_modified": "2024-11-18T16:59:00.933Z",
                        "children": []
                      },
                      {
                        "id": "428212266",
                        "title": "Charger",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/428212266",
                        "last_modified": "2024-11-18T16:59:44.745Z",
                        "children": []
                      },
                      {
                        "id": "428146729",
                        "title": "System Harness",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/428146729",
                        "last_modified": "2024-11-18T17:00:14.967Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "427950102",
                    "title": "Technology Roadmap",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/427950102",
                    "last_modified": "2024-11-18T16:29:24.836Z",
                    "children": [
                      {
                        "id": "427917349",
                        "title": "Cell Technologies",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/427917349",
                        "last_modified": "2024-11-18T16:29:45.443Z",
                        "children": []
                      }
                    ]
                  }
                ]
              }
            ]
          },
          {
            "id": "574816461",
            "title": "Charging Station [IPT] -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574816461",
            "last_modified": "2025-02-19T15:45:28.883Z",
            "children": [
              {
                "id": "574816506",
                "title": "Charging Station - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574816506",
                "last_modified": "2025-01-31T22:29:25.700Z",
                "children": []
              },
              {
                "id": "574816526",
                "title": "Charging Station - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574816526",
                "last_modified": "2025-01-31T22:29:25.978Z",
                "children": []
              }
            ]
          },
          {
            "id": "609943603",
            "title": "Cloud/WAN Infra -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/609943603",
            "last_modified": "2025-02-27T22:33:16.181Z",
            "children": [
              {
                "id": "609943662",
                "title": "Cloud/WAN Infra - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/609943662",
                "last_modified": "2025-02-12T16:23:45.816Z",
                "children": []
              },
              {
                "id": "609943682",
                "title": "Cloud/WAN Infra - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/609943682",
                "last_modified": "2025-02-12T16:23:46.223Z",
                "children": []
              }
            ]
          },
          {
            "id": "609910835",
            "title": "Dev/ML Ops Infra -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/609910835",
            "last_modified": "2025-02-27T23:09:00.973Z",
            "children": [
              {
                "id": "609910894",
                "title": "Dev/ML Ops Infra - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/609910894",
                "last_modified": "2025-02-12T16:21:44.264Z",
                "children": []
              },
              {
                "id": "609910914",
                "title": "Dev/ML Ops Infra - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/609910914",
                "last_modified": "2025-02-12T16:21:44.537Z",
                "children": []
              },
              {
                "id": "974356634",
                "title": "VLA Batch jobs",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/974356634",
                "last_modified": "2025-07-23T09:34:58.338Z",
                "children": []
              },
              {
                "id": "484343862",
                "title": "\ud83d\udcdc Logging, Diagnostics and telemetry",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/484343862",
                "last_modified": "2025-01-13T12:03:02.702Z",
                "children": [
                  {
                    "id": "542048279",
                    "title": "Logging: data format",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/542048279",
                    "last_modified": "2025-01-30T08:42:51.103Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "574783877",
            "title": "End Effectors [IPT] -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783877",
            "last_modified": "2025-02-19T17:21:51.777Z",
            "children": [
              {
                "id": "574783922",
                "title": "Alpha - End Effectors - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783922",
                "last_modified": "2025-11-20T15:33:03.325Z",
                "children": [
                  {
                    "id": "967868488",
                    "title": "Alpha EE - 1st builds logbook",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/967868488",
                    "last_modified": "2025-08-26T16:37:39.417Z",
                    "children": []
                  },
                  {
                    "id": "1035534338",
                    "title": "Alpha EE - 5 Finger COTS hand integration",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1035534338",
                    "last_modified": "2025-08-29T08:52:21.205Z",
                    "children": [
                      {
                        "id": "1105723393",
                        "title": "Alpha EE - 5 Finger hand PCBA (Design feedback)",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1105723393",
                        "last_modified": "2025-09-16T14:44:32.594Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "965640236",
                    "title": "Alpha EE - Assembly instructions",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/965640236",
                    "last_modified": "2025-09-09T12:08:18.710Z",
                    "children": [
                      {
                        "id": "1131282635",
                        "title": "Alpha EE - Robot installation",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1131282635",
                        "last_modified": "2025-11-26T13:22:39.198Z",
                        "children": []
                      },
                      {
                        "id": "1088651267",
                        "title": "Alpha EE - Tactile sensor addressing",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1088651267",
                        "last_modified": "2026-01-23T11:59:44.260Z",
                        "children": [
                          {
                            "id": "1126924309",
                            "title": "Alpha EE - Tactile sensor address setting process",
                            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1126924309",
                            "last_modified": "2025-09-26T14:05:51.370Z",
                            "children": []
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "id": "916488210",
                    "title": "Alpha EE - Design reviews",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/916488210",
                    "last_modified": "2025-06-12T09:41:32.801Z",
                    "children": [
                      {
                        "id": "916193325",
                        "title": "Alpha EE - Cable routing design review",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/916193325",
                        "last_modified": "2025-06-16T09:07:22.048Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "685867028",
                    "title": "Alpha EE - FT Sensor selection",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/685867028",
                    "last_modified": "2025-04-02T09:49:03.650Z",
                    "children": []
                  },
                  {
                    "id": "881459206",
                    "title": "Alpha EE - Meeting minutes",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/881459206",
                    "last_modified": "2025-07-03T15:05:11.110Z",
                    "children": []
                  },
                  {
                    "id": "723910687",
                    "title": "Alpha EE - Packaging",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/723910687",
                    "last_modified": "2025-05-15T12:23:58.160Z",
                    "children": []
                  },
                  {
                    "id": "872841246",
                    "title": "Alpha EE - Procuremetn Tracker",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/872841246",
                    "last_modified": "2025-07-11T14:01:12.943Z",
                    "children": []
                  },
                  {
                    "id": "996245611",
                    "title": "Alpha EE - Psyonic vs Robotera hand",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/996245611",
                    "last_modified": "2025-07-21T12:12:14.354Z",
                    "children": []
                  },
                  {
                    "id": "800227392",
                    "title": "Alpha EE - Sensor List",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/800227392",
                    "last_modified": "2025-04-24T08:45:53.330Z",
                    "children": []
                  },
                  {
                    "id": "802095169",
                    "title": "Alpha EE - Tactile sensors",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/802095169",
                    "last_modified": "2025-05-16T16:36:02.628Z",
                    "children": [
                      {
                        "id": "892174340",
                        "title": "SingleTact sensor integration",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/892174340",
                        "last_modified": "2025-06-02T09:29:37.521Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "1541537803",
                    "title": "Alpha EE - Wrist bracket assembly",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1541537803",
                    "last_modified": "2026-01-22T13:45:25.466Z",
                    "children": []
                  },
                  {
                    "id": "908853339",
                    "title": "Alpha EE- Camera reselection",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/908853339",
                    "last_modified": "2025-06-12T16:15:53.007Z",
                    "children": [
                      {
                        "id": "962625566",
                        "title": "Alpha EE - Camera test",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/962625566",
                        "last_modified": "2025-07-11T12:59:22.934Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "1559920641",
                    "title": "Alpha UMI Devices",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1559920641",
                    "last_modified": "2026-01-29T17:02:10.607Z",
                    "children": [
                      {
                        "id": "1342963741",
                        "title": "ALPHA UMI Device - Assembly instructions",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1342963741",
                        "last_modified": "2026-01-06T11:56:21.968Z",
                        "children": [
                          {
                            "id": "1397293362",
                            "title": "Alpha UMI - QC",
                            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1397293362",
                            "last_modified": "2025-12-19T14:35:19.773Z",
                            "children": []
                          },
                          {
                            "id": "1571651661",
                            "title": "Alpha UMI 1.0 - Connection scheme",
                            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1571651661",
                            "last_modified": "2026-01-29T15:14:35.479Z",
                            "children": []
                          }
                        ]
                      }
                    ]
                  }
                ]
              },
              {
                "id": "574783942",
                "title": "End Effectors - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783942",
                "last_modified": "2025-01-31T22:31:46.649Z",
                "children": [
                  {
                    "id": "1067384844",
                    "title": "Alpha EE - Tactile sensor testing WIP",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1067384844",
                    "last_modified": "2025-09-16T15:02:10.937Z",
                    "children": []
                  },
                  {
                    "id": "1071022105",
                    "title": "Alpha EE/ Alpha UMI Tactile sensor trouble shooting",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1071022105",
                    "last_modified": "2025-09-01T08:45:37.788Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "437714969",
                "title": "OTS (Off-The-Shelf) End-Effectors",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/437714969",
                "last_modified": "2025-05-27T15:25:46.247Z",
                "children": [
                  {
                    "id": "996245554",
                    "title": "Comparison Hands",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/996245554",
                    "last_modified": "2025-08-05T08:53:05.821Z",
                    "children": []
                  },
                  {
                    "id": "506855448",
                    "title": "OTS End Effector Review",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/506855448",
                    "last_modified": "2025-01-07T16:45:52.161Z",
                    "children": []
                  },
                  {
                    "id": "436994072",
                    "title": "Robotera",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/436994072",
                    "last_modified": "2024-11-21T16:49:51.984Z",
                    "children": []
                  },
                  {
                    "id": "294387717",
                    "title": "\ud83e\udd0c Inspire-Robots",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/294387717",
                    "last_modified": "2024-09-13T17:25:09.359Z",
                    "children": [
                      {
                        "id": "294584341",
                        "title": "Dexterous hands",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/294584341",
                        "last_modified": "2024-09-13T17:23:38.269Z",
                        "children": []
                      },
                      {
                        "id": "310411265",
                        "title": "How to use (SW)",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/310411265",
                        "last_modified": "2024-11-27T15:57:38.331Z",
                        "children": []
                      }
                    ]
                  }
                ]
              },
              {
                "id": "687079426",
                "title": "Pre-Alpha End Effector - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/687079426",
                "last_modified": "2025-03-10T14:41:58.734Z",
                "children": []
              }
            ]
          },
          {
            "id": "568230015",
            "title": "Head [IPT]",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/568230015",
            "last_modified": "2025-09-30T08:53:05.692Z",
            "children": [
              {
                "id": "599523374",
                "title": "Head - Alpha Project",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/599523374",
                "last_modified": "2025-06-06T09:59:03.359Z",
                "children": [
                  {
                    "id": "689504279",
                    "title": "Head - Alpha Load Cases",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/689504279",
                    "last_modified": "2025-03-31T15:22:58.316Z",
                    "children": []
                  },
                  {
                    "id": "672661547",
                    "title": "Head - Alpha Requirements Development",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/672661547",
                    "last_modified": "2025-03-18T14:01:07.999Z",
                    "children": []
                  },
                  {
                    "id": "658702421",
                    "title": "Head - Alpha engineering documentation",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/658702421",
                    "last_modified": "2025-02-28T13:48:22.135Z",
                    "children": [
                      {
                        "id": "1050181690",
                        "title": "Alpa Head Interface Board rework notes",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1050181690",
                        "last_modified": "2025-09-02T15:57:22.225Z",
                        "children": []
                      },
                      {
                        "id": "717619255",
                        "title": "Alpha Head & Neck Concept Review",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/717619255",
                        "last_modified": "2025-03-21T09:33:46.776Z",
                        "children": []
                      },
                      {
                        "id": "1011875891",
                        "title": "Alpha Head Interface Board bring up instructions",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1011875891",
                        "last_modified": "2025-11-13T08:48:03.174Z",
                        "children": []
                      },
                      {
                        "id": "1050280006",
                        "title": "Alpha Head Interface Board revision notes",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1050280006",
                        "last_modified": "2025-08-21T18:28:26.490Z",
                        "children": []
                      },
                      {
                        "id": "1309999133",
                        "title": "Alpha Head Thermal Testing",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1309999133",
                        "last_modified": "2025-11-21T09:22:37.174Z",
                        "children": []
                      },
                      {
                        "id": "804028526",
                        "title": "Alpha head interfacing board (HIB) connectors definition",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/804028526",
                        "last_modified": "2025-05-15T13:55:01.487Z",
                        "children": []
                      },
                      {
                        "id": "670662694",
                        "title": "Four-Bar Linkage Torque Calculation Sheet",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/670662694",
                        "last_modified": "2025-03-04T15:03:47.933Z",
                        "children": []
                      },
                      {
                        "id": "821002367",
                        "title": "Head-Torso cable list",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/821002367",
                        "last_modified": "2025-05-12T15:56:18.292Z",
                        "children": []
                      },
                      {
                        "id": "665288725",
                        "title": "Humanoid HRI  (Audio subsystem)",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/665288725",
                        "last_modified": "2025-03-03T10:58:02.108Z",
                        "children": []
                      },
                      {
                        "id": "665026567",
                        "title": "Humanoid Head sensors interfaces overview",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/665026567",
                        "last_modified": "2025-03-03T11:03:16.668Z",
                        "children": []
                      },
                      {
                        "id": "693272577",
                        "title": "Mic array CODEC bringup prototype",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/693272577",
                        "last_modified": "2025-03-12T09:10:54.229Z",
                        "children": []
                      },
                      {
                        "id": "659685377",
                        "title": "Neck Conceptual Brainstorming",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/659685377",
                        "last_modified": "2025-03-03T13:20:58.185Z",
                        "children": []
                      },
                      {
                        "id": "822050871",
                        "title": "Samtec connectors pinout",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/822050871",
                        "last_modified": "2025-04-29T15:16:40.928Z",
                        "children": []
                      },
                      {
                        "id": "1004929120",
                        "title": "Visors- materials",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1004929120",
                        "last_modified": "2025-07-25T10:13:03.195Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "903774372",
                    "title": "Head Alpha - Assembly Instructions",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/903774372",
                    "last_modified": "2025-06-06T11:58:09.367Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "909639681",
                "title": "Head - Beta Industrial Project",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/909639681",
                "last_modified": "2025-10-07T08:55:12.323Z",
                "children": [
                  {
                    "id": "1138294852",
                    "title": "BETA Interesting RGB Sensor Solutions",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1138294852",
                    "last_modified": "2025-10-03T08:15:18.063Z",
                    "children": []
                  },
                  {
                    "id": "1093992450",
                    "title": "Beta - HW Implications for Display - Head Display Trade Study",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1093992450",
                    "last_modified": "2025-10-09T12:12:15.478Z",
                    "children": []
                  },
                  {
                    "id": "909443080",
                    "title": "Beta - Head Architecture Concept HECP-226",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/909443080",
                    "last_modified": "2025-08-07T15:37:34.922Z",
                    "children": []
                  },
                  {
                    "id": "1096941574",
                    "title": "Beta - Head Sensor Layout",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1096941574",
                    "last_modified": "2025-09-12T08:41:25.959Z",
                    "children": []
                  },
                  {
                    "id": "1044971584",
                    "title": "Beta - Head what do we need to solve to achieve beta targets?",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1044971584",
                    "last_modified": "2025-09-29T13:43:02.406Z",
                    "children": []
                  },
                  {
                    "id": "1075150862",
                    "title": "Beta - Neck DOF Trade Study",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1075150862",
                    "last_modified": "2026-06-30T08:19:36.417Z",
                    "children": [
                      {
                        "id": "1268482083",
                        "title": "Beta - Actuation Concept - WIP",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1268482083",
                        "last_modified": "2025-11-24T09:05:10.343Z",
                        "children": []
                      },
                      {
                        "id": "1223950337",
                        "title": "Beta - Neck Torque Estimation",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1223950337",
                        "last_modified": "2025-11-05T13:01:27.126Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "1047298117",
                    "title": "Beta BOM Cost Estimation",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1047298117",
                    "last_modified": "2025-10-09T07:13:40.709Z",
                    "children": []
                  },
                  {
                    "id": "1055621121",
                    "title": "Beta Head & Neck low cost structures",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1055621121",
                    "last_modified": "2025-09-19T10:41:28.146Z",
                    "children": []
                  },
                  {
                    "id": "967081985",
                    "title": "Beta Head HRI Support HECP-242",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/967081985",
                    "last_modified": "2025-08-18T08:20:41.004Z",
                    "children": []
                  },
                  {
                    "id": "1045790721",
                    "title": "Beta Industrial Workshop Display",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1045790721",
                    "last_modified": "2025-08-18T13:16:24.015Z",
                    "children": []
                  },
                  {
                    "id": "1307312164",
                    "title": "Beta head electrical architecture concepts study",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1307312164",
                    "last_modified": "2025-12-19T11:06:43.592Z",
                    "children": []
                  },
                  {
                    "id": "1068728342",
                    "title": "Modular Sensor Test Bed Development",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1068728342",
                    "last_modified": "2025-09-04T15:07:15.870Z",
                    "children": []
                  },
                  {
                    "id": "1134559239",
                    "title": "Rough Holoscan Sensor Bridge Spaceclaim",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1134559239",
                    "last_modified": "2025-10-02T09:28:05.224Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "568197158",
                "title": "Head - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/568197158",
                "last_modified": "2025-02-04T08:26:09.990Z",
                "children": [
                  {
                    "id": "762314782",
                    "title": "Alpha Head Thermal Calcs",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/762314782",
                    "last_modified": "2025-04-08T10:38:59.652Z",
                    "children": []
                  },
                  {
                    "id": "580091949",
                    "title": "Brainstorms and Concept Development",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/580091949",
                    "last_modified": "2025-02-03T17:50:50.787Z",
                    "children": []
                  },
                  {
                    "id": "580091936",
                    "title": "Meeting Notes [Actions and Decisions]",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/580091936",
                    "last_modified": "2025-09-25T17:05:25.184Z",
                    "children": []
                  },
                  {
                    "id": "599359500",
                    "title": "Neck 2DoF Discussion",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/599359500",
                    "last_modified": "2025-02-10T09:29:41.792Z",
                    "children": []
                  },
                  {
                    "id": "580091962",
                    "title": "Reviews",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/580091962",
                    "last_modified": "2025-02-03T17:51:12.472Z",
                    "children": [
                      {
                        "id": "658472999",
                        "title": "Design Reviews",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/658472999",
                        "last_modified": "2025-02-28T10:43:54.397Z",
                        "children": [
                          {
                            "id": "659062792",
                            "title": "Design Review Template",
                            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/659062792",
                            "last_modified": "2025-06-11T14:16:57.829Z",
                            "children": []
                          }
                        ]
                      },
                      {
                        "id": "591429643",
                        "title": "Sprint Reviews",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/591429643",
                        "last_modified": "2025-02-06T15:53:51.197Z",
                        "children": []
                      }
                    ]
                  }
                ]
              },
              {
                "id": "579305488",
                "title": "Head - PreAlpha Project",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/579305488",
                "last_modified": "2025-03-03T15:27:28.920Z",
                "children": [
                  {
                    "id": "478412856",
                    "title": "Head - PreAlpha Build Integration and Test",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/478412856",
                    "last_modified": "2025-02-06T15:50:51.188Z",
                    "children": []
                  },
                  {
                    "id": "579534931",
                    "title": "Head - PreAlpha Design & Analysis",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/579534931",
                    "last_modified": "2025-04-23T13:23:54.948Z",
                    "children": [
                      {
                        "id": "604110883",
                        "title": "Pre Alpha Head Thermal Calculations",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/604110883",
                        "last_modified": "2025-02-11T14:01:29.761Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "579829787",
                    "title": "Head - PreAlpha Requirements Development",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/579829787",
                    "last_modified": "2025-02-10T10:08:54.927Z",
                    "children": []
                  },
                  {
                    "id": "619053133",
                    "title": "Head - PreAlpha Spares Strategy",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/619053133",
                    "last_modified": "2025-02-17T12:50:22.488Z",
                    "children": []
                  },
                  {
                    "id": "679116813",
                    "title": "Pre-Alpha PCIe-to-USB3.x expansion cards testing",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/679116813",
                    "last_modified": "2025-05-06T18:38:19.509Z",
                    "children": []
                  },
                  {
                    "id": "609157146",
                    "title": "Pre-Alpha electronics architecture",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/609157146",
                    "last_modified": "2025-05-07T16:52:52.636Z",
                    "children": []
                  },
                  {
                    "id": "673316922",
                    "title": "Pre-Alpha head GPIO cable assembly",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/673316922",
                    "last_modified": "2025-05-07T16:46:16.200Z",
                    "children": []
                  },
                  {
                    "id": "566001698",
                    "title": "PreAlpha modular Head test platform",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/566001698",
                    "last_modified": "2025-02-06T15:51:38.059Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "567705793",
                "title": "Head - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/567705793",
                "last_modified": "2025-01-29T20:07:13.634Z",
                "children": [
                  {
                    "id": "594182146",
                    "title": "Camera Latency Test System (Draft)",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/594182146",
                    "last_modified": "2025-02-07T10:33:32.697Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "574783792",
            "title": "Legs (Bipedal Base) [IPT] -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783792",
            "last_modified": "2025-02-19T16:06:52.273Z",
            "children": [
              {
                "id": "574783837",
                "title": "Legs (Bipedal Base) - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783837",
                "last_modified": "2025-01-31T22:31:20.535Z",
                "children": []
              },
              {
                "id": "574783857",
                "title": "Legs (Bipedal Base) - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783857",
                "last_modified": "2025-01-31T22:31:20.811Z",
                "children": []
              }
            ]
          },
          {
            "id": "568000598",
            "title": "Low Level Control -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/568000598",
            "last_modified": "2025-03-03T16:31:38.992Z",
            "children": []
          },
          {
            "id": "199983105",
            "title": "Manipulation / VLA",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/199983105",
            "last_modified": "2026-03-06T18:33:27.394Z",
            "children": [
              {
                "id": "1499005050",
                "title": "ML Ideas",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1499005050",
                "last_modified": "2026-01-28T09:46:05.657Z",
                "children": []
              },
              {
                "id": "1499005060",
                "title": "Meeting Notes",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1499005060",
                "last_modified": "2026-01-13T08:26:47.500Z",
                "children": []
              },
              {
                "id": "1423474701",
                "title": "Onboarding to the Manipulation / VLA team",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1423474701",
                "last_modified": "2026-06-25T17:16:16.679Z",
                "children": []
              },
              {
                "id": "1627226152",
                "title": "To be archived (Manipulation / VLA) as of Feb 10, 2026",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1627226152",
                "last_modified": "2026-02-10T11:09:54.618Z",
                "children": [
                  {
                    "id": "1526333443",
                    "title": "Pre-training Status",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1526333443",
                    "last_modified": "2026-02-02T11:13:39.168Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "589922308",
            "title": "Mid-level control and integration - WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/589922308",
            "last_modified": "2025-03-17T15:51:51.717Z",
            "children": [
              {
                "id": "590446607",
                "title": "Mid-level control and integration - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/590446607",
                "last_modified": "2025-02-06T09:18:05.188Z",
                "children": []
              },
              {
                "id": "589529141",
                "title": "Mid-level control and integration - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/589529141",
                "last_modified": "2025-02-06T09:05:04.172Z",
                "children": []
              },
              {
                "id": "625115218",
                "title": "Scenarios, Pipelines, Actions",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/625115218",
                "last_modified": "2025-03-04T14:40:05.214Z",
                "children": [
                  {
                    "id": "652148971",
                    "title": "Rainbow manipulation data collection pipeline",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/652148971",
                    "last_modified": "2025-02-26T21:36:54.199Z",
                    "children": []
                  },
                  {
                    "id": "652181734",
                    "title": "Reasoning pick-n-place pipeline",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/652181734",
                    "last_modified": "2025-02-26T21:38:21.775Z",
                    "children": []
                  },
                  {
                    "id": "650870791",
                    "title": "Robot Modes and Actions",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/650870791",
                    "last_modified": "2025-03-19T19:02:44.036Z",
                    "children": [
                      {
                        "id": "668631081",
                        "title": "Action: Move mobile base to location",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/668631081",
                        "last_modified": "2025-03-04T14:36:27.794Z",
                        "children": []
                      },
                      {
                        "id": "669974529",
                        "title": "Action: Pick object (1) Classic",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/669974529",
                        "last_modified": "2025-03-04T14:34:23.020Z",
                        "children": []
                      },
                      {
                        "id": "670007297",
                        "title": "Action: Pick\u00a0object (2) Classic",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/670007297",
                        "last_modified": "2025-03-04T14:37:03.390Z",
                        "children": []
                      },
                      {
                        "id": "669188113",
                        "title": "Action: Pick\u00a0object (3) Learned",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/669188113",
                        "last_modified": "2025-03-04T14:37:17.622Z",
                        "children": []
                      },
                      {
                        "id": "670105604",
                        "title": "Action: Place object (1) Classic",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/670105604",
                        "last_modified": "2025-03-04T14:37:39.260Z",
                        "children": []
                      },
                      {
                        "id": "669876242",
                        "title": "Action: Place object (2) Learned",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/669876242",
                        "last_modified": "2025-03-04T14:38:31.679Z",
                        "children": []
                      },
                      {
                        "id": "652149012",
                        "title": "Action: QR-code scan",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/652149012",
                        "last_modified": "2025-03-04T14:39:37.757Z",
                        "children": []
                      },
                      {
                        "id": "670400513",
                        "title": "Action: Teleoperation",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/670400513",
                        "last_modified": "2025-03-04T14:35:07.811Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "652017958",
                    "title": "Sim / Real HW difference",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/652017958",
                    "last_modified": "2025-02-26T21:40:04.160Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "647168408",
                "title": "Third-Party Mid-level controllers",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/647168408",
                "last_modified": "2025-02-25T17:56:13.023Z",
                "children": [
                  {
                    "id": "646087217",
                    "title": "Versatile Robotics",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/646087217",
                    "last_modified": "2025-02-26T09:31:41.751Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "715587701",
                "title": "Whole-Body Control Frameworks",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/715587701",
                "last_modified": "2025-03-20T15:46:15.724Z",
                "children": []
              },
              {
                "id": "629997724",
                "title": "\ud83d\udcdd Telemetry, Diagnostic, Logging: Architecture",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/629997724",
                "last_modified": "2025-02-21T10:01:45.432Z",
                "children": [
                  {
                    "id": "657981465",
                    "title": "Datasets gathering system",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/657981465",
                    "last_modified": "2025-03-12T09:56:22.431Z",
                    "children": []
                  },
                  {
                    "id": "658014227",
                    "title": "Robot Monitoring & Diagnostic system",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/658014227",
                    "last_modified": "2025-02-28T10:20:52.462Z",
                    "children": []
                  },
                  {
                    "id": "629964884",
                    "title": "Robot logging system",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/629964884",
                    "last_modified": "2025-02-27T09:00:19.103Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "609910934",
            "title": "Perception System -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/609910934",
            "last_modified": "2025-02-28T19:25:33.283Z",
            "children": [
              {
                "id": "609910993",
                "title": "Perception System - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/609910993",
                "last_modified": "2025-02-12T16:29:21.301Z",
                "children": []
              },
              {
                "id": "609911013",
                "title": "Perception System - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/609911013",
                "last_modified": "2025-02-12T16:29:21.625Z",
                "children": []
              }
            ]
          },
          {
            "id": "610140161",
            "title": "Shared Autonomy -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/610140161",
            "last_modified": "2025-04-01T12:57:03.676Z",
            "children": [
              {
                "id": "735543358",
                "title": "Elementary UI Concept",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/735543358",
                "last_modified": "2025-04-01T13:06:27.519Z",
                "children": []
              },
              {
                "id": "736034848",
                "title": "Hi-Level Features",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/736034848",
                "last_modified": "2025-04-01T13:06:50.609Z",
                "children": []
              },
              {
                "id": "735707179",
                "title": "Metrics Model - Key Technological Components",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/735707179",
                "last_modified": "2025-04-01T13:07:14.853Z",
                "children": []
              },
              {
                "id": "736395270",
                "title": "OUTDATED - UX Information Structure of the Shared Autonomy",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/736395270",
                "last_modified": "2025-04-10T14:39:14.328Z",
                "children": []
              },
              {
                "id": "610140221",
                "title": "Shared Autonomy - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/610140221",
                "last_modified": "2025-02-12T16:35:49.842Z",
                "children": []
              },
              {
                "id": "610140241",
                "title": "Shared Autonomy - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/610140241",
                "last_modified": "2025-02-12T16:35:50.649Z",
                "children": []
              },
              {
                "id": "743440566",
                "title": "UX Flow",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/743440566",
                "last_modified": "2025-04-02T16:14:39.887Z",
                "children": []
              }
            ]
          },
          {
            "id": "610107492",
            "title": "Simulation Infra -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/610107492",
            "last_modified": "2025-04-28T08:33:56.791Z",
            "children": [
              {
                "id": "610107551",
                "title": "Simulation Infra - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/610107551",
                "last_modified": "2025-02-12T16:26:35.526Z",
                "children": []
              },
              {
                "id": "610107571",
                "title": "Simulation Infra - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/610107571",
                "last_modified": "2025-02-12T16:26:35.797Z",
                "children": []
              },
              {
                "id": "697204788",
                "title": "To Remove after pre-alhpa poc",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/697204788",
                "last_modified": "2025-03-13T16:59:06.460Z",
                "children": [
                  {
                    "id": "477003842",
                    "title": "Current State",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/477003842",
                    "last_modified": "2024-12-13T07:28:43.445Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "477397029",
                "title": "\ud83c\udfae Simulation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/477397029",
                "last_modified": "2025-04-29T19:27:47.620Z",
                "children": [
                  {
                    "id": "1624670224",
                    "title": "6. Gym",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1624670224",
                    "last_modified": "2026-02-09T15:02:40.335Z",
                    "children": []
                  },
                  {
                    "id": "631832639",
                    "title": "Meeting Notes - Simulation",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/631832639",
                    "last_modified": "2025-02-20T11:48:08.394Z",
                    "children": [
                      {
                        "id": "651395091",
                        "title": "2025-02-26 Meeting notes",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/651395091",
                        "last_modified": "2025-02-26T18:05:02.520Z",
                        "children": []
                      },
                      {
                        "id": "748224540",
                        "title": "2025-04-01 Meeting notes",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/748224540",
                        "last_modified": "2025-04-02T15:47:52.285Z",
                        "children": []
                      },
                      {
                        "id": "748126269",
                        "title": "2025-04-02 Meeting notes",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/748126269",
                        "last_modified": "2025-04-02T15:50:57.451Z",
                        "children": []
                      },
                      {
                        "id": "889389057",
                        "title": "Jira Retrospective",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/889389057",
                        "last_modified": "2025-05-30T07:21:41.418Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "1719730276",
                    "title": "Robo Final integration",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1719730276",
                    "last_modified": "2026-03-09T17:34:40.995Z",
                    "children": [
                      {
                        "id": "1719468148",
                        "title": "Policy Eval",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1719468148",
                        "last_modified": "2026-03-09T17:53:29.119Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "2056880278",
                    "title": "SKL \u2013 URDF Export Tool (Animation Designer Addon) \u2013 Work Report",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2056880278",
                    "last_modified": "2026-06-04T20:01:40.181Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "574783537",
            "title": "System Int, Test, and Labs [IPT] -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783537",
            "last_modified": "2025-02-20T10:41:24.579Z",
            "children": [
              {
                "id": "788594749",
                "title": "Alpha Integration Plan",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/788594749",
                "last_modified": "2025-04-17T14:54:27.068Z",
                "children": []
              },
              {
                "id": "574783582",
                "title": "System Int, Test, and Labs - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783582",
                "last_modified": "2025-01-31T22:27:46.160Z",
                "children": []
              },
              {
                "id": "574783602",
                "title": "System Int, Test, and Labs - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574783602",
                "last_modified": "2025-01-31T22:27:46.434Z",
                "children": [
                  {
                    "id": "591560710",
                    "title": "CLI tool for low level fieldbus test (Draft)",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/591560710",
                    "last_modified": "2025-02-06T16:24:36.529Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "574816291",
            "title": "Torso [IPT] -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574816291",
            "last_modified": "2025-02-19T15:44:03.050Z",
            "children": [
              {
                "id": "574816336",
                "title": "Torso - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574816336",
                "last_modified": "2025-01-31T22:28:12.577Z",
                "children": [
                  {
                    "id": "1119879179",
                    "title": "Alpha Torso IMU",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1119879179",
                    "last_modified": "2025-09-26T16:38:04.102Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "574816356",
                "title": "Torso - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574816356",
                "last_modified": "2025-01-31T22:28:12.872Z",
                "children": []
              }
            ]
          },
          {
            "id": "574849059",
            "title": "Wheeled Base [IPT] -  WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574849059",
            "last_modified": "2025-02-19T15:46:17.422Z",
            "children": [
              {
                "id": "655294485",
                "title": "Neobotix ROX-Argo Information",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/655294485",
                "last_modified": "2025-11-14T13:26:31.156Z",
                "children": []
              },
              {
                "id": "574849104",
                "title": "Wheeled Base - Eng Dev",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574849104",
                "last_modified": "2025-01-31T22:29:52.040Z",
                "children": []
              },
              {
                "id": "574849124",
                "title": "Wheeled Base - Test and Validation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574849124",
                "last_modified": "2025-01-31T22:29:52.285Z",
                "children": []
              }
            ]
          }
        ]
      },
      {
        "id": "894468131",
        "title": "EBOM Release Procedure - Core Platform",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/894468131",
        "last_modified": "2025-06-04T21:09:56.097Z",
        "children": []
      },
      {
        "id": "1056637019",
        "title": "Electronics",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1056637019",
        "last_modified": "2026-07-07T14:17:51.551Z",
        "children": [
          {
            "id": "1132724322",
            "title": "10005937 Gripper V8",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1132724322",
            "last_modified": "2025-10-02T23:00:14.248Z",
            "children": []
          },
          {
            "id": "1056669806",
            "title": "10021182 EtherCAT to CAN",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1056669806",
            "last_modified": "2026-01-06T22:39:41.349Z",
            "children": []
          },
          {
            "id": "1317371941",
            "title": "10021237 Foot Integration",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1317371941",
            "last_modified": "2025-11-20T19:19:51.277Z",
            "children": []
          },
          {
            "id": "1792704513",
            "title": "10042080 C1.3.2 Gripper Controller",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1792704513",
            "last_modified": "2026-06-19T16:27:42.646Z",
            "children": []
          },
          {
            "id": "1916010497",
            "title": "10042081 C1.3.2 Gripper EtherCAT Sensor",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1916010497",
            "last_modified": "2026-06-13T00:22:03.209Z",
            "children": []
          },
          {
            "id": "1338998792",
            "title": "1007543 Gripper Connector Board",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1338998792",
            "last_modified": "2026-02-10T12:15:36.888Z",
            "children": []
          },
          {
            "id": "2011889766",
            "title": "EE Design Review Document",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2011889766",
            "last_modified": "2026-05-25T21:24:59.706Z",
            "children": []
          },
          {
            "id": "1073086541",
            "title": "Humanoid Electronics Design Standards",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1073086541",
            "last_modified": "2026-07-07T14:17:14.142Z",
            "children": []
          },
          {
            "id": "2148991087",
            "title": "PCB Documentation Export Instructions",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2148991087",
            "last_modified": "2026-07-10T22:45:38.865Z",
            "children": []
          },
          {
            "id": "1973616749",
            "title": "PCB Project Life Cycle",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1973616749",
            "last_modified": "2026-05-13T19:25:43.280Z",
            "children": []
          },
          {
            "id": "1056637051",
            "title": "PCBA Information Template",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1056637051",
            "last_modified": "2025-08-22T20:38:18.228Z",
            "children": []
          },
          {
            "id": "2011562232",
            "title": "Test Points Design Rules",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2011562232",
            "last_modified": "2026-05-26T03:42:44.555Z",
            "children": []
          }
        ]
      },
      {
        "id": "204046363",
        "title": "Engineering Planning",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/204046363",
        "last_modified": "2024-09-24T08:42:46.090Z",
        "children": [
          {
            "id": "706379811",
            "title": "Alpha - Cross Functional Team - Activities and Notes",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/706379811",
            "last_modified": "2025-03-25T16:32:22.918Z",
            "children": []
          },
          {
            "id": "467501057",
            "title": "Alpha Planning Dec'2024",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/467501057",
            "last_modified": "2025-01-02T14:51:34.354Z",
            "children": []
          },
          {
            "id": "357564424",
            "title": "H1+ Planning 18/10/2024",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/357564424",
            "last_modified": "2024-10-22T15:46:30.350Z",
            "children": []
          },
          {
            "id": "713031684",
            "title": "PreAlpha - Cross Functional Team - Activities and Notes",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/713031684",
            "last_modified": "2025-03-19T15:36:01.222Z",
            "children": []
          },
          {
            "id": "242057226",
            "title": "Software Planning H2 2024",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/242057226",
            "last_modified": "2024-08-15T14:04:45.875Z",
            "children": [
              {
                "id": "242384904",
                "title": "August 2024",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/242384904",
                "last_modified": "2024-08-15T13:59:29.170Z",
                "children": []
              },
              {
                "id": "242810896",
                "title": "December 2024",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/242810896",
                "last_modified": "2024-08-15T14:01:16.455Z",
                "children": []
              },
              {
                "id": "242548747",
                "title": "November 2024",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/242548747",
                "last_modified": "2024-08-15T14:00:49.036Z",
                "children": []
              },
              {
                "id": "242810886",
                "title": "October 2024",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/242810886",
                "last_modified": "2024-08-15T14:00:26.796Z",
                "children": []
              },
              {
                "id": "242614283",
                "title": "September 2024",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/242614283",
                "last_modified": "2024-08-15T13:59:58.821Z",
                "children": []
              }
            ]
          }
        ]
      },
      {
        "id": "450658330",
        "title": "Engineering Team",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/450658330",
        "last_modified": "2024-11-27T21:52:39.310Z",
        "children": [
          {
            "id": "1108279297",
            "title": "Engineering Chapters",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1108279297",
            "last_modified": "2025-10-08T22:03:28.576Z",
            "children": [
              {
                "id": "1125908534",
                "title": "Chapter Firmware",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1125908534",
                "last_modified": "2026-07-13T21:54:04.533Z",
                "children": [
                  {
                    "id": "1692172298",
                    "title": "Firmware Onboarding",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1692172298",
                    "last_modified": "2026-07-16T16:47:03.049Z",
                    "children": []
                  },
                  {
                    "id": "1174929443",
                    "title": "Meetings Agendas",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1174929443",
                    "last_modified": "2025-10-22T16:21:17.694Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1108475905",
                "title": "Chapter Mechanical",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1108475905",
                "last_modified": "2025-09-29T17:11:24.726Z",
                "children": [
                  {
                    "id": "1111195664",
                    "title": "Chapter Mechanical Kick-Off Prep notes.",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1111195664",
                    "last_modified": "2025-09-18T16:00:56.557Z",
                    "children": []
                  },
                  {
                    "id": "1191608323",
                    "title": "Input for NX Business Requirements",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1191608323",
                    "last_modified": "2025-10-28T11:58:28.555Z",
                    "children": []
                  },
                  {
                    "id": "1498087533",
                    "title": "NX Part Design Training Jan 2026 (notes & questions)",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1498087533",
                    "last_modified": "2026-01-13T18:13:13.969Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1738473487",
                "title": "Design for Manufacturing and Assembly Guides and Training Resources",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1738473487",
                "last_modified": "2026-03-18T15:24:28.168Z",
                "children": []
              }
            ]
          },
          {
            "id": "187465741",
            "title": "Engineering demos",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/187465741",
            "last_modified": "2025-06-13T14:19:56.878Z",
            "children": [
              {
                "id": "920944676",
                "title": "2025 Controls_Sprint demos",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/920944676",
                "last_modified": "2025-07-11T10:21:04.342Z",
                "children": []
              },
              {
                "id": "920256605",
                "title": "2025 Core Platform_Sprint demos",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/920256605",
                "last_modified": "2025-06-13T15:45:06.230Z",
                "children": []
              },
              {
                "id": "920551555",
                "title": "2025 Locomanipulation_Sprint demos",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/920551555",
                "last_modified": "2025-06-14T01:14:03.776Z",
                "children": []
              },
              {
                "id": "920551516",
                "title": "2025 SEI&T_Sprint demos",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/920551516",
                "last_modified": "2025-06-13T15:46:35.001Z",
                "children": []
              },
              {
                "id": "920289369",
                "title": "2025 Schaeffler :: Demos",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/920289369",
                "last_modified": "2025-07-09T08:44:14.942Z",
                "children": [
                  {
                    "id": "969244756",
                    "title": "On-site Demos",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/969244756",
                    "last_modified": "2025-07-02T12:24:16.197Z",
                    "children": [
                      {
                        "id": "969080929",
                        "title": "Site 1st observation",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/969080929",
                        "last_modified": "2025-07-02T13:57:19.032Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "940638460",
                    "title": "S1W24 :: 13.06.25",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/940638460",
                    "last_modified": "2025-06-20T09:21:42.534Z",
                    "children": []
                  },
                  {
                    "id": "940540202",
                    "title": "S2W25 :: 20.06.25",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/940540202",
                    "last_modified": "2025-06-20T16:24:38.838Z",
                    "children": []
                  },
                  {
                    "id": "963969046",
                    "title": "S3W26 :: 27.06.25",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/963969046",
                    "last_modified": "2025-07-09T08:38:16.804Z",
                    "children": []
                  },
                  {
                    "id": "980385796",
                    "title": "S4W27 :: 07.07.25",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/980385796",
                    "last_modified": "2025-07-09T08:37:51.619Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "580616259",
            "title": "Lunch and Learn",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/580616259",
            "last_modified": "2025-03-19T16:15:50.027Z",
            "children": []
          },
          {
            "id": "180125722",
            "title": "Meeting minutes - Engineering",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/180125722",
            "last_modified": "2024-08-15T11:46:27.783Z",
            "children": [
              {
                "id": "180256769",
                "title": "2024.07.09 - Jira process review for Releases",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/180256769",
                "last_modified": "2024-09-22T20:21:19.324Z",
                "children": []
              },
              {
                "id": "180322305",
                "title": "2024.07.09 - Release Manifest proposal review",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/180322305",
                "last_modified": "2024-07-17T20:27:45.005Z",
                "children": []
              },
              {
                "id": "214401025",
                "title": "2024.07.31 - Product requirement framework and Jira tool",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/214401025",
                "last_modified": "2024-08-27T21:26:58.384Z",
                "children": []
              },
              {
                "id": "241532952",
                "title": "2024.08.09 - Planning Workshop",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/241532952",
                "last_modified": "2024-08-15T11:09:09.035Z",
                "children": []
              },
              {
                "id": "261652481",
                "title": "2024.08.27 - Product requirement framework review",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/261652481",
                "last_modified": "2025-02-05T09:13:16.233Z",
                "children": []
              },
              {
                "id": "242712619",
                "title": "2024.09.15 - Software engineering planning",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/242712619",
                "last_modified": "2024-08-28T14:08:11.944Z",
                "children": []
              },
              {
                "id": "309952688",
                "title": "2024.09.19 - Structure of Requirements (levels, information & terms)",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/309952688",
                "last_modified": "2024-09-22T20:49:52.155Z",
                "children": []
              },
              {
                "id": "323682305",
                "title": "2024.09.27 - Demo_Requirement management tool - Flow",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/323682305",
                "last_modified": "2024-10-16T12:36:45.029Z",
                "children": []
              },
              {
                "id": "342523906",
                "title": "2024.10.10 - High level vision of Product-> Feature process",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/342523906",
                "last_modified": "2024-10-11T11:01:42.849Z",
                "children": []
              },
              {
                "id": "348192769",
                "title": "2024.10.14 - Kick off meeting_Requirement tool_ Flow Trial",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/348192769",
                "last_modified": "2024-10-14T19:39:11.486Z",
                "children": []
              },
              {
                "id": "357335042",
                "title": "2024.10.17 - Kick off meeting_Engineering requirements_ Flow Trial",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/357335042",
                "last_modified": "2024-10-22T18:28:00.135Z",
                "children": []
              },
              {
                "id": "358711297",
                "title": "2024.10.17 - Product to feature release framework_alignment meeting",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/358711297",
                "last_modified": "2025-02-05T09:15:05.778Z",
                "children": []
              },
              {
                "id": "364642305",
                "title": "2024.10.21 - 1 week results_Requirement tool_ Flow Trial",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/364642305",
                "last_modified": "2024-10-22T12:58:29.271Z",
                "children": []
              },
              {
                "id": "371949569",
                "title": "2024.10.24 - Product to feature release process review meeting",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/371949569",
                "last_modified": "2024-10-28T18:28:16.055Z",
                "children": []
              },
              {
                "id": "377454595",
                "title": "2024.10.25 - How to structure things in Flow tool",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/377454595",
                "last_modified": "2024-12-10T09:27:16.407Z",
                "children": []
              },
              {
                "id": "376176642",
                "title": "2024.10.25 - Internal discussion_review of Flow tool_trial finished",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/376176642",
                "last_modified": "2024-10-30T14:52:26.753Z",
                "children": []
              },
              {
                "id": "385679361",
                "title": "2024.10.28 - Jira project for Pre-Alpha/Alpha development cycles",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/385679361",
                "last_modified": "2024-10-30T21:20:13.574Z",
                "children": []
              },
              {
                "id": "583860256",
                "title": "2025.02.04 - Meeting notes",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/583860256",
                "last_modified": "2025-02-07T09:25:16.387Z",
                "children": []
              },
              {
                "id": "599326757",
                "title": "2025.02.10 - Meeting notes",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/599326757",
                "last_modified": "2025-03-17T10:12:41.906Z",
                "children": []
              },
              {
                "id": "604045464",
                "title": "2025.02.11 - Meeting notes",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/604045464",
                "last_modified": "2025-03-17T10:12:54.762Z",
                "children": []
              },
              {
                "id": "1720647681",
                "title": "2025.03.06 - DFX Issue Management awareness",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1720647681",
                "last_modified": "2026-03-09T14:28:06.908Z",
                "children": []
              },
              {
                "id": "676921407",
                "title": "2025.03.06 - Meeting notes",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/676921407",
                "last_modified": "2025-03-17T10:13:01.614Z",
                "children": []
              }
            ]
          },
          {
            "id": "841810473",
            "title": "TLT Digest",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/841810473",
            "last_modified": "2025-06-13T14:51:54.812Z",
            "children": []
          },
          {
            "id": "841744975",
            "title": "Technology All Hands meetings",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/841744975",
            "last_modified": "2025-06-13T15:52:26.636Z",
            "children": []
          },
          {
            "id": "835452936",
            "title": "\ud83d\udcdd MuJoCo Legacy Simulation Setup with X11 Rendering",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/835452936",
            "last_modified": "2025-05-07T17:44:33.265Z",
            "children": []
          }
        ]
      },
      {
        "id": "1399291984",
        "title": "Error handling",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1399291984",
        "last_modified": "2025-12-09T15:14:34.287Z",
        "children": []
      },
      {
        "id": "1142718486",
        "title": "Phase Gates",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1142718486",
        "last_modified": "2025-10-09T12:33:11.455Z",
        "children": [
          {
            "id": "1142980656",
            "title": "Phase 1 - Product Requirements Defined",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1142980656",
            "last_modified": "2025-10-09T12:40:45.629Z",
            "children": []
          },
          {
            "id": "1142784038",
            "title": "Phase 2 - Architecture & Product Concept Agreed",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1142784038",
            "last_modified": "2025-10-09T12:45:32.012Z",
            "children": []
          },
          {
            "id": "1142751260",
            "title": "Phase 3 - Subsystem Concept Complete",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1142751260",
            "last_modified": "2025-10-09T12:46:35.589Z",
            "children": [
              {
                "id": "1532035301",
                "title": "Feasibility assessment of critical software technologies",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1532035301",
                "last_modified": "2026-01-20T19:11:41.215Z",
                "children": []
              }
            ]
          },
          {
            "id": "1142521866",
            "title": "Phase 4 - Detail Design Complete",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1142521866",
            "last_modified": "2025-10-09T12:47:08.469Z",
            "children": []
          },
          {
            "id": "1142947856",
            "title": "Phase 5 - Prototype Production First Article Complete",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1142947856",
            "last_modified": "2025-10-09T12:48:20.835Z",
            "children": []
          },
          {
            "id": "1143210040",
            "title": "Phase 6 - Verification& Validation Complete",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1143210040",
            "last_modified": "2025-10-09T12:49:00.798Z",
            "children": []
          },
          {
            "id": "1142947866",
            "title": "Phase 7 - Milestone Phase Exit",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1142947866",
            "last_modified": "2025-10-09T12:50:03.458Z",
            "children": []
          }
        ]
      },
      {
        "id": "905118356",
        "title": "PoC Projects Hub",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/905118356",
        "last_modified": "2025-06-09T05:47:53.256Z",
        "children": [
          {
            "id": "2250309657",
            "title": "Bosch PoC [Phase2] Project Tracker",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2250309657",
            "last_modified": "2026-07-23T18:31:12.229Z",
            "children": []
          },
          {
            "id": "904954446",
            "title": "Schaeffler-Humanoid",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/904954446",
            "last_modified": "2025-06-09T16:46:08.103Z",
            "children": [
              {
                "id": "952303690",
                "title": "E2E scenario preparation daily reports",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/952303690",
                "last_modified": "2025-06-24T15:34:51.089Z",
                "children": []
              },
              {
                "id": "952008740",
                "title": "New Policy Reports",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/952008740",
                "last_modified": "2025-06-25T09:29:15.787Z",
                "children": []
              }
            ]
          }
        ]
      },
      {
        "id": "568000541",
        "title": "Robot Configurations",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/568000541",
        "last_modified": "2025-05-01T12:42:26.155Z",
        "children": [
          {
            "id": "605913089",
            "title": "Alpha Roadkill 1 & 2 Configuration - WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/605913089",
            "last_modified": "2025-05-12T22:05:16.950Z",
            "children": [
              {
                "id": "841154589",
                "title": "Alpha Roadkill 1 & 2 Design Review",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/841154589",
                "last_modified": "2025-05-08T08:43:06.689Z",
                "children": []
              }
            ]
          },
          {
            "id": "574849025",
            "title": "Bipedal Alpha Configuration - WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574849025",
            "last_modified": "2025-03-14T15:58:33.451Z",
            "children": [
              {
                "id": "1497595905",
                "title": "Alpha Biped Safety",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1497595905",
                "last_modified": "2026-01-12T12:11:01.345Z",
                "children": []
              },
              {
                "id": "1400700929",
                "title": "Biped Alpha User Guide",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1400700929",
                "last_modified": "2026-04-23T08:36:21.209Z",
                "children": [
                  {
                    "id": "1498546189",
                    "title": "Alpha Biped Charging",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1498546189",
                    "last_modified": "2026-06-10T09:09:08.860Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "568000570",
            "title": "Pre-Alpha Configuration - WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/568000570",
            "last_modified": "2025-03-27T10:44:12.112Z",
            "children": []
          },
          {
            "id": "568229961",
            "title": "Project Charter - Alpha System Configurations",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/568229961",
            "last_modified": "2025-02-06T15:46:05.540Z",
            "children": []
          },
          {
            "id": "574816257",
            "title": "Wheeled Alpha Configuration - WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/574816257",
            "last_modified": "2025-03-14T15:58:53.924Z",
            "children": [
              {
                "id": "965804033",
                "title": "Alpha HRI - Critical Design Review",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/965804033",
                "last_modified": "2025-06-30T18:23:49.224Z",
                "children": []
              },
              {
                "id": "1123418241",
                "title": "Alpha Wheeled Base User Guides",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1123418241",
                "last_modified": "2025-12-09T11:17:06.790Z",
                "children": [
                  {
                    "id": "1123844250",
                    "title": "Alpha Robot Switch of",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1123844250",
                    "last_modified": "2025-10-31T10:45:35.424Z",
                    "children": []
                  },
                  {
                    "id": "1126793217",
                    "title": "Alpha Unit Information",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1126793217",
                    "last_modified": "2026-01-12T11:43:45.279Z",
                    "children": []
                  },
                  {
                    "id": "1124040764",
                    "title": "Alpha Wheeled Safety",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1124040764",
                    "last_modified": "2026-01-12T12:07:19.858Z",
                    "children": []
                  },
                  {
                    "id": "1124434007",
                    "title": "Base Break Release",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1124434007",
                    "last_modified": "2025-09-26T12:27:06.519Z",
                    "children": []
                  },
                  {
                    "id": "1124237370",
                    "title": "Estop Basics and Recovery Alpha Wheeled",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1124237370",
                    "last_modified": "2026-01-12T11:32:54.093Z",
                    "children": []
                  },
                  {
                    "id": "1124663361",
                    "title": "Issue logging",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1124663361",
                    "last_modified": "2025-10-28T10:58:05.493Z",
                    "children": []
                  },
                  {
                    "id": "1124433990",
                    "title": "Lidar System",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1124433990",
                    "last_modified": "2025-11-04T11:51:17.499Z",
                    "children": []
                  },
                  {
                    "id": "1676247208",
                    "title": "Linkage URDF to WA12 Mass Comparison",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1676247208",
                    "last_modified": "2026-03-05T15:36:55.303Z",
                    "children": []
                  },
                  {
                    "id": "1124663378",
                    "title": "Robot Booking System guide",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1124663378",
                    "last_modified": "2025-10-27T19:14:56.137Z",
                    "children": []
                  },
                  {
                    "id": "1273036811",
                    "title": "Robot total weight evidence",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1273036811",
                    "last_modified": "2026-03-02T16:17:28.068Z",
                    "children": []
                  },
                  {
                    "id": "1241677827",
                    "title": "Service Guides",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1241677827",
                    "last_modified": "2026-04-28T08:51:44.667Z",
                    "children": [
                      {
                        "id": "1242660888",
                        "title": "Battery replacement",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1242660888",
                        "last_modified": "2025-11-05T15:51:47.887Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "1123156152",
                    "title": "Switch On",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1123156152",
                    "last_modified": "2025-09-26T10:43:44.518Z",
                    "children": []
                  },
                  {
                    "id": "1198489619",
                    "title": "Wheeled Alpha Known Issues, Limitations and Workarounds",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1198489619",
                    "last_modified": "2026-06-12T15:16:21.864Z",
                    "children": []
                  },
                  {
                    "id": "1126137868",
                    "title": "Wheeled Base Light meaning",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1126137868",
                    "last_modified": "2025-09-26T10:41:46.099Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "874643457",
                "title": "Alpha Wheeled Core - Critical Design Review",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/874643457",
                "last_modified": "2025-05-29T22:12:12.970Z",
                "children": []
              },
              {
                "id": "766771202",
                "title": "Alpha Wheeled Core - Preliminary Design Review",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/766771202",
                "last_modified": "2025-06-11T19:34:04.805Z",
                "children": []
              },
              {
                "id": "764182627",
                "title": "Alpha e-BOM template and how to use it",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/764182627",
                "last_modified": "2026-01-27T22:33:50.434Z",
                "children": []
              },
              {
                "id": "965115905",
                "title": "Beta Wheeled Core - Release #1 Review",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/965115905",
                "last_modified": "2025-07-08T15:09:01.129Z",
                "children": []
              }
            ]
          },
          {
            "id": "1703116813",
            "title": "Wheeled Beta Configuration - WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1703116813",
            "last_modified": "2026-03-04T17:01:17.505Z",
            "children": []
          }
        ]
      },
      {
        "id": "399343626",
        "title": "Sensors",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/399343626",
        "last_modified": "2024-11-06T13:22:00.612Z",
        "children": [
          {
            "id": "781451290",
            "title": "Alpha Version Sensors",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/781451290",
            "last_modified": "2025-04-15T10:26:46.357Z",
            "children": [
              {
                "id": "720208367",
                "title": "Alpha EE - Camera location",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/720208367",
                "last_modified": "2025-04-29T16:07:31.338Z",
                "children": []
              },
              {
                "id": "745177197",
                "title": "Alpha Head Sensor Selection",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/745177197",
                "last_modified": "2025-06-05T13:14:09.481Z",
                "children": [
                  {
                    "id": "728662347",
                    "title": "IMU Selection",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/728662347",
                    "last_modified": "2025-05-21T16:07:18.535Z",
                    "children": []
                  },
                  {
                    "id": "518717468",
                    "title": "RGB Camera Selection",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/518717468",
                    "last_modified": "2025-05-07T12:14:23.924Z",
                    "children": []
                  },
                  {
                    "id": "727842821",
                    "title": "Sensor Aggregation Board Selection",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/727842821",
                    "last_modified": "2025-05-09T14:42:15.729Z",
                    "children": []
                  },
                  {
                    "id": "725712897",
                    "title": "ToF Camera Selection",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/725712897",
                    "last_modified": "2025-04-14T14:18:01.405Z",
                    "children": [
                      {
                        "id": "759529477",
                        "title": "ToF Comparison - NRobotics vs Cubeeye",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/759529477",
                        "last_modified": "2025-04-10T15:06:19.042Z",
                        "children": []
                      },
                      {
                        "id": "759332912",
                        "title": "ToF Selection - NRobotics Tests",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/759332912",
                        "last_modified": "2025-04-07T14:08:14.613Z",
                        "children": []
                      }
                    ]
                  }
                ]
              },
              {
                "id": "781418582",
                "title": "Alpha Perception sensing Development Documents",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/781418582",
                "last_modified": "2025-04-15T10:16:49.603Z",
                "children": [
                  {
                    "id": "781451303",
                    "title": "Alpha Perception sensing Concept development Documents",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/781451303",
                    "last_modified": "2025-04-16T15:36:15.118Z",
                    "children": []
                  },
                  {
                    "id": "782008364",
                    "title": "Sensing System Testing",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/782008364",
                    "last_modified": "2025-04-16T14:33:04.175Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "822083642",
                "title": "Alpha Perception sensing Risks and Mitigations",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/822083642",
                "last_modified": "2025-04-29T14:02:03.148Z",
                "children": []
              },
              {
                "id": "901185573",
                "title": "Alpha Sensors Detailed Software/Firmware Requirements.",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/901185573",
                "last_modified": "2025-06-05T09:01:31.510Z",
                "children": [
                  {
                    "id": "901349402",
                    "title": "End Effector Tactile Sensors DSR",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/901349402",
                    "last_modified": "2025-06-05T16:10:37.245Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "989397105",
                "title": "Alpha Sensors Progress Tracker",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/989397105",
                "last_modified": "2025-10-02T10:47:42.126Z",
                "children": []
              },
              {
                "id": "1110278163",
                "title": "Alpha Sensors Test Methods",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1110278163",
                "last_modified": "2025-09-23T08:21:19.706Z",
                "children": []
              },
              {
                "id": "455540745",
                "title": "Alpha Version Head Vision Sensors",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/455540745",
                "last_modified": "2024-12-02T18:20:24.223Z",
                "children": [
                  {
                    "id": "460423170",
                    "title": "Optical Investigation of the face shield Material",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/460423170",
                    "last_modified": "2025-01-22T11:34:09.082Z",
                    "children": []
                  },
                  {
                    "id": "460259345",
                    "title": "Questions on optical characteristics of PX522HT",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/460259345",
                    "last_modified": "2025-04-01T15:47:43.943Z",
                    "children": []
                  },
                  {
                    "id": "487456806",
                    "title": "Sensor Configuration Test Setup",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/487456806",
                    "last_modified": "2024-12-18T17:12:53.301Z",
                    "children": [
                      {
                        "id": "487555077",
                        "title": "Vision Sensor Components",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/487555077",
                        "last_modified": "2024-12-18T17:28:56.819Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "472383562",
                    "title": "Vision Sensors Configuration investigation for the Alpha Version Head",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/472383562",
                    "last_modified": "2025-04-01T15:46:38.613Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "781647933",
                "title": "NRobotics",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/781647933",
                "last_modified": "2025-04-15T10:27:21.097Z",
                "children": []
              },
              {
                "id": "777289750",
                "title": "Sensors Meetings",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/777289750",
                "last_modified": "2025-04-14T17:15:55.325Z",
                "children": [
                  {
                    "id": "777355273",
                    "title": "Alpha Head Sensors + ID Meeting",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/777355273",
                    "last_modified": "2025-04-15T10:07:05.717Z",
                    "children": []
                  },
                  {
                    "id": "777322575",
                    "title": "End Effector Sensors Meeting",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/777322575",
                    "last_modified": "2025-06-03T16:24:10.374Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "887423022",
            "title": "Beta Version Sensors",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/887423022",
            "last_modified": "2025-10-02T09:07:44.325Z",
            "children": [
              {
                "id": "1176141825",
                "title": "BEI Trade Study: Head IMU Architecture for BEI Wheeled Humanoid Robot",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1176141825",
                "last_modified": "2025-11-25T20:27:27.268Z",
                "children": []
              },
              {
                "id": "1182269464",
                "title": "BEI Wheeled Trade Study: Head Depth Sensing Technolgies",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1182269464",
                "last_modified": "2025-10-31T16:28:09.516Z",
                "children": []
              },
              {
                "id": "1330085889",
                "title": "Depth Sensor Testing",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1330085889",
                "last_modified": "2026-03-18T12:32:24.719Z",
                "children": [
                  {
                    "id": "1456963611",
                    "title": "Analog Devices ADTF3175D Time of Flight Sensor",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1456963611",
                    "last_modified": "2025-12-23T17:07:36.198Z",
                    "children": []
                  },
                  {
                    "id": "1330151425",
                    "title": "Pointcloud Visualiser Software",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1330151425",
                    "last_modified": "2025-12-17T15:51:03.834Z",
                    "children": []
                  },
                  {
                    "id": "1457586181",
                    "title": "ST VD55H1 Time of Flight Sensor",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1457586181",
                    "last_modified": "2025-12-23T15:30:49.173Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1255276560",
                "title": "Depth Sensors Meetings Notes",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1255276560",
                "last_modified": "2025-11-07T15:31:39.262Z",
                "children": []
              },
              {
                "id": "1123745907",
                "title": "DepthAnything Testing",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1123745907",
                "last_modified": "2025-09-26T12:54:31.096Z",
                "children": []
              },
              {
                "id": "1796603945",
                "title": "F/T sensor testing",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1796603945",
                "last_modified": "2026-03-25T17:50:52.246Z",
                "children": [
                  {
                    "id": "1797357631",
                    "title": "[WIP] Bota BFT-MH1-MLP-BD F/T sensor testing",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1797357631",
                    "last_modified": "2026-05-06T08:25:54.832Z",
                    "children": []
                  },
                  {
                    "id": "1951957031",
                    "title": "[WIP] F/T Sensor Selection",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1951957031",
                    "last_modified": "2026-06-19T13:44:58.489Z",
                    "children": [
                      {
                        "id": "2068840456",
                        "title": "Force/torque leakage test",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2068840456",
                        "last_modified": "2026-06-10T17:57:13.337Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "1861287937",
                    "title": "[WIP] ForceN DEV-6WA-S300  F/T sensor testing",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1861287937",
                    "last_modified": "2026-05-01T09:03:45.857Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1677852689",
                "title": "LIDAR Sensor Testing for Wheeled Beta",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1677852689",
                "last_modified": "2026-03-11T15:13:32.201Z",
                "children": [
                  {
                    "id": "1677066296",
                    "title": "LIDAR Sensor Selection",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1677066296",
                    "last_modified": "2026-03-03T12:31:48.158Z",
                    "children": []
                  },
                  {
                    "id": "2127626244",
                    "title": "OLEI LR-1BS5H LIDAR Bringup Notes",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2127626244",
                    "last_modified": "2026-06-22T14:30:16.241Z",
                    "children": []
                  },
                  {
                    "id": "1676411107",
                    "title": "OLEI LR-1BS5H LIDAR Safety Testing",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1676411107",
                    "last_modified": "2026-03-11T02:56:16.951Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1816330308",
                "title": "RGB Camera Testing",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1816330308",
                "last_modified": "2026-03-31T14:46:10.226Z",
                "children": [
                  {
                    "id": "1816526905",
                    "title": "OS04E10 RGB Camera Detailed Testing",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1816526905",
                    "last_modified": "2026-04-08T15:10:38.784Z",
                    "children": []
                  },
                  {
                    "id": "1816395849",
                    "title": "RGB Test Tooling",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1816395849",
                    "last_modified": "2026-04-09T10:59:13.901Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1813610509",
                "title": "Safety Sensors SW Meeting",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1813610509",
                "last_modified": "2026-04-01T13:56:06.284Z",
                "children": []
              }
            ]
          },
          {
            "id": "453967873",
            "title": "Cameras evaluation",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/453967873",
            "last_modified": "2024-12-02T09:00:02.453Z",
            "children": []
          },
          {
            "id": "455606273",
            "title": "Competitors Humanoid Robots Vision Systems",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/455606273",
            "last_modified": "2025-10-09T08:40:09.706Z",
            "children": []
          },
          {
            "id": "399671301",
            "title": "Pre-Alpha Version",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/399671301",
            "last_modified": "2024-11-06T14:17:46.440Z",
            "children": [
              {
                "id": "424607788",
                "title": "Data Asset Requirements to Inform Visual Sensing Needs",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/424607788",
                "last_modified": "2024-11-15T13:40:46.009Z",
                "children": []
              },
              {
                "id": "629112887",
                "title": "Pre-Alpha Head Integration Plan",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/629112887",
                "last_modified": "2025-04-02T10:11:18.200Z",
                "children": []
              },
              {
                "id": "400523266",
                "title": "Pre-Alpha Version Head",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/400523266",
                "last_modified": "2024-11-06T14:20:06.993Z",
                "children": [
                  {
                    "id": "400752666",
                    "title": "Sensing Technologies Matrix",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/400752666",
                    "last_modified": "2025-01-07T17:07:57.279Z",
                    "children": [
                      {
                        "id": "727908541",
                        "title": "Head Sensors Meeting Notes",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/727908541",
                        "last_modified": "2025-03-25T18:56:23.257Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "412581892",
                    "title": "Sensors Options for the Head",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/412581892",
                    "last_modified": "2024-11-11T16:33:21.810Z",
                    "children": []
                  },
                  {
                    "id": "415498257",
                    "title": "Steps for sensors strategy development for the head component",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/415498257",
                    "last_modified": "2024-11-12T17:42:25.547Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "786563131",
            "title": "Sensors Data BandWidth Calculator",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/786563131",
            "last_modified": "2025-04-16T09:33:27.552Z",
            "children": []
          },
          {
            "id": "424640588",
            "title": "Sensors Integration with Control Systems",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/424640588",
            "last_modified": "2024-11-15T12:04:28.363Z",
            "children": []
          },
          {
            "id": "728531094",
            "title": "Sensors Setup",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/728531094",
            "last_modified": "2025-04-15T09:32:52.971Z",
            "children": [
              {
                "id": "599588885",
                "title": "Jetson Bringup Notes",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/599588885",
                "last_modified": "2025-03-06T11:58:12.383Z",
                "children": []
              },
              {
                "id": "473497604",
                "title": "Sensor Bringup Notes",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/473497604",
                "last_modified": "2025-06-05T12:22:38.419Z",
                "children": []
              }
            ]
          },
          {
            "id": "451936463",
            "title": "Vision Sensor Selection Framework for Humanoid Head",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/451936463",
            "last_modified": "2025-01-24T16:31:00.395Z",
            "children": []
          }
        ]
      },
      {
        "id": "1385398310",
        "title": "Simulation-based HW design validation",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1385398310",
        "last_modified": "2026-02-24T12:33:30.653Z",
        "children": []
      },
      {
        "id": "1007976535",
        "title": "Software",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1007976535",
        "last_modified": "2025-08-04T09:30:23.848Z",
        "children": [
          {
            "id": "1027506232",
            "title": "Bushwhacking Software",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1027506232",
            "last_modified": "2025-08-06T09:17:39.727Z",
            "children": []
          },
          {
            "id": "2105475136",
            "title": "Fleet Software: Requirements \u2192 Services Mapping",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2105475136",
            "last_modified": "2026-06-17T10:45:34.534Z",
            "children": []
          },
          {
            "id": "1005027354",
            "title": "Integration and the Monorepo",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1005027354",
            "last_modified": "2025-07-25T16:01:03.615Z",
            "children": []
          },
          {
            "id": "1004732467",
            "title": "Move Fast and Merge Things",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1004732467",
            "last_modified": "2025-07-24T12:28:25.037Z",
            "children": []
          },
          {
            "id": "1840054289",
            "title": "OSS Licensing \"Audit\"",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1840054289",
            "last_modified": "2026-04-08T10:19:24.694Z",
            "children": [
              {
                "id": "1839693858",
                "title": "OSS Audit: hmnd_design, hmnd_playground, Root/Bazel",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1839693858",
                "last_modified": "2026-04-08T09:52:20.172Z",
                "children": []
              },
              {
                "id": "1840807976",
                "title": "OSS Audit: hmnd_fleet, hmnd_services, hmnd_update",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1840807976",
                "last_modified": "2026-04-08T09:51:46.738Z",
                "children": []
              },
              {
                "id": "1840873486",
                "title": "OSS Audit: hmnd_flywheel",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1840873486",
                "last_modified": "2026-04-08T09:50:51.744Z",
                "children": []
              },
              {
                "id": "1839071263",
                "title": "OSS Audit: hmnd_locomotion",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1839071263",
                "last_modified": "2026-04-08T09:51:17.061Z",
                "children": []
              },
              {
                "id": "1839038509",
                "title": "OSS Audit: hmnd_robot",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1839038509",
                "last_modified": "2026-04-08T10:20:47.149Z",
                "children": []
              },
              {
                "id": "1840775181",
                "title": "OSS Audit: hmnd_sim",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1840775181",
                "last_modified": "2026-04-08T09:50:21.482Z",
                "children": []
              },
              {
                "id": "1840807951",
                "title": "OSS Audit: hmnd_training",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1840807951",
                "last_modified": "2026-04-08T10:22:08.914Z",
                "children": []
              },
              {
                "id": "1839235107",
                "title": "OSS Audit: hmnd_wholebody",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1839235107",
                "last_modified": "2026-04-08T10:22:33.997Z",
                "children": []
              }
            ]
          },
          {
            "id": "1037926527",
            "title": "Overview of the codebase",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1037926527",
            "last_modified": "2025-08-13T10:48:56.788Z",
            "children": []
          },
          {
            "id": "1529577477",
            "title": "Platform Software",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1529577477",
            "last_modified": "2026-04-07T13:05:39.304Z",
            "children": [
              {
                "id": "1783889921",
                "title": "FAQ - Platform Software",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1783889921",
                "last_modified": "2026-03-27T16:04:41.883Z",
                "children": []
              },
              {
                "id": "1776386116",
                "title": "Immutable Operating Systems Applications Developer Guide",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1776386116",
                "last_modified": "2026-03-23T13:10:56.477Z",
                "children": []
              },
              {
                "id": "1783889930",
                "title": "Platform VM Development",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1783889930",
                "last_modified": "2026-03-30T16:03:16.882Z",
                "children": []
              },
              {
                "id": "1833107496",
                "title": "What Actually Is \"Jetson Linux\"",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1833107496",
                "last_modified": "2026-04-07T13:27:16.202Z",
                "children": []
              }
            ]
          },
          {
            "id": "1670709288",
            "title": "Robot Software Architecture (Current State)",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1670709288",
            "last_modified": "2026-04-30T22:30:39.255Z",
            "children": []
          },
          {
            "id": "1734115331",
            "title": "Sockpuppet WebRTC Investigation and Learnings",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1734115331",
            "last_modified": "2026-03-11T13:26:17.213Z",
            "children": []
          },
          {
            "id": "1167294522",
            "title": "Synapse",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1167294522",
            "last_modified": "2026-07-22T10:26:15.979Z",
            "children": [
              {
                "id": "1178599484",
                "title": "Ethernet Performance",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1178599484",
                "last_modified": "2025-10-23T21:47:31.821Z",
                "children": [
                  {
                    "id": "1678770202",
                    "title": "AM2612 Internal Switch Performance",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1678770202",
                    "last_modified": "2026-02-27T17:19:16.536Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1835401222",
                "title": "How to run Synapse on the host device with 4 fake devices",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1835401222",
                "last_modified": "2026-04-07T15:11:49.632Z",
                "children": []
              },
              {
                "id": "1179516973",
                "title": "Motivation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1179516973",
                "last_modified": "2025-10-23T21:49:44.596Z",
                "children": []
              },
              {
                "id": "1179910202",
                "title": "Synapse Protocol Overview",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1179910202",
                "last_modified": "2026-06-18T14:49:16.856Z",
                "children": []
              },
              {
                "id": "1935048906",
                "title": "System Software Architecture",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1935048906",
                "last_modified": "2026-05-01T20:56:00.649Z",
                "children": []
              }
            ]
          },
          {
            "id": "1004666903",
            "title": "Trunk-Based Development",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1004666903",
            "last_modified": "2025-07-24T12:28:43.349Z",
            "children": []
          },
          {
            "id": "1022394482",
            "title": "Welcome to the Jungle",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1022394482",
            "last_modified": "2025-08-04T12:17:26.957Z",
            "children": []
          },
          {
            "id": "1010335765",
            "title": "\ud83e\udea4 Robot Middleware",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1010335765",
            "last_modified": "2025-07-28T14:23:07.664Z",
            "children": []
          }
        ]
      },
      {
        "id": "482836487",
        "title": "TPM Adam - Priorities and Task Tracking",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/482836487",
        "last_modified": "2025-08-18T15:29:01.409Z",
        "children": []
      },
      {
        "id": "486473833",
        "title": "Welcome and Ways of Working",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/486473833",
        "last_modified": "2026-03-25T15:37:57.150Z",
        "children": [
          {
            "id": "548208654",
            "title": "Build Unit Homepage - Template - WIP",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/548208654",
            "last_modified": "2025-01-23T22:41:43.358Z",
            "children": [
              {
                "id": "500858897",
                "title": "Project Charter - Template",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/500858897",
                "last_modified": "2025-02-06T15:45:43.156Z",
                "children": []
              }
            ]
          },
          {
            "id": "1912700936",
            "title": "Process Hub",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1912700936",
            "last_modified": "2026-04-27T12:16:10.908Z",
            "children": []
          }
        ]
      },
      {
        "id": "610107393",
        "title": "[DCP] Data & Compute Platform",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/610107393",
        "last_modified": "2026-04-13T08:41:29.790Z",
        "children": [
          {
            "id": "2059436036",
            "title": "DBT Migration of ETL Silver \u2014 Implementation Summary",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2059436036",
            "last_modified": "2026-06-05T16:06:22.727Z",
            "children": []
          },
          {
            "id": "1732509777",
            "title": "DCP - ARCHIVE",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1732509777",
            "last_modified": "2026-03-11T16:13:52.225Z",
            "children": [
              {
                "id": "552665229",
                "title": "Data Volumes estimation",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/552665229",
                "last_modified": "2025-01-24T11:54:48.626Z",
                "children": []
              },
              {
                "id": "1039335437",
                "title": "[Archived] Debugging and redeploying the Console (quickly)",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1039335437",
                "last_modified": "2025-10-22T15:35:50.563Z",
                "children": []
              },
              {
                "id": "512229408",
                "title": "[Project] Cross-Embodiment / Human Action Retarget datasets",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/512229408",
                "last_modified": "2025-01-10T09:58:16.495Z",
                "children": []
              }
            ]
          },
          {
            "id": "1735196709",
            "title": "DCP - Overview",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1735196709",
            "last_modified": "2026-03-11T16:02:35.248Z",
            "children": [
              {
                "id": "1771700225",
                "title": "DCP - Onboarding",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1771700225",
                "last_modified": "2026-03-19T13:20:45.198Z",
                "children": []
              },
              {
                "id": "504430625",
                "title": "[Outdated] Data Platform Overview",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/504430625",
                "last_modified": "2026-03-11T16:16:50.790Z",
                "children": []
              }
            ]
          },
          {
            "id": "1731854466",
            "title": "DCP \u2013 Architecture",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1731854466",
            "last_modified": "2026-03-11T16:14:45.092Z",
            "children": [
              {
                "id": "1930428419",
                "title": "DCP - Cost Reports",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1930428419",
                "last_modified": "2026-07-03T13:16:45.042Z",
                "children": [
                  {
                    "id": "1928822799",
                    "title": "DCP - Cost Reports - April 2026",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1928822799",
                    "last_modified": "2026-07-03T15:24:40.580Z",
                    "children": []
                  },
                  {
                    "id": "2168651804",
                    "title": "DCP - Cost Reports - June 2026",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2168651804",
                    "last_modified": "2026-07-13T09:19:08.094Z",
                    "children": [
                      {
                        "id": "2170388481",
                        "title": "DCP - June 2026 - CPU Cost Deep Dive",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2170388481",
                        "last_modified": "2026-07-01T17:50:17.032Z",
                        "children": []
                      },
                      {
                        "id": "2171961362",
                        "title": "DCP - June 2026 - CloudWatch Cost Deep Dive",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2171961362",
                        "last_modified": "2026-07-02T13:06:16.173Z",
                        "children": []
                      },
                      {
                        "id": "2170519560",
                        "title": "DCP - June 2026 - GPU On-Demand Cost Deep Dive",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2170519560",
                        "last_modified": "2026-07-01T18:00:56.711Z",
                        "children": []
                      },
                      {
                        "id": "2178744337",
                        "title": "DCP - June 2026 - NAT Gateway Cost Deep Dive",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2178744337",
                        "last_modified": "2026-07-03T14:33:53.223Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "2118877188",
                    "title": "DCP - Cost Reports - May 2026",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2118877188",
                    "last_modified": "2026-07-03T15:24:33.232Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1470922783",
                "title": "Data Infra: Use-Cases & Math",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1470922783",
                "last_modified": "2026-01-05T15:55:52.463Z",
                "children": []
              },
              {
                "id": "1078820879",
                "title": "Data Infrastructure Costs forecasting for 2026",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1078820879",
                "last_modified": "2025-09-04T14:33:18.767Z",
                "children": []
              },
              {
                "id": "1689321493",
                "title": "Data and Compute Platform Registry",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1689321493",
                "last_modified": "2026-03-18T10:56:02.322Z",
                "children": []
              },
              {
                "id": "1892352039",
                "title": "GPU Compute Requirements",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1892352039",
                "last_modified": "2026-05-13T11:25:01.785Z",
                "children": []
              },
              {
                "id": "1471610898",
                "title": "Robotics Data Platforms Overview",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1471610898",
                "last_modified": "2026-01-20T12:28:48.392Z",
                "children": []
              },
              {
                "id": "614662211",
                "title": "[ADRs] Architecture Decision Records",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/614662211",
                "last_modified": "2025-02-14T10:46:06.392Z",
                "children": [
                  {
                    "id": "615120923",
                    "title": "[ADR]  Data Collection \u2013 How to Choose ROS Topics to Be Recorded",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/615120923",
                    "last_modified": "2025-02-26T10:04:50.910Z",
                    "children": []
                  },
                  {
                    "id": "647266324",
                    "title": "[ADR] Data Collection - Tasks and Subtasks",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/647266324",
                    "last_modified": "2025-02-25T09:59:24.493Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "1730576500",
            "title": "DCP \u2013 Operations",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1730576500",
            "last_modified": "2026-03-11T16:06:41.915Z",
            "children": [
              {
                "id": "1730805930",
                "title": "DCP - Access Management",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1730805930",
                "last_modified": "2026-03-11T16:07:38.552Z",
                "children": [
                  {
                    "id": "1774813220",
                    "title": "DCP - Cloudflare R2 API Tokens",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1774813220",
                    "last_modified": "2026-07-08T16:47:59.477Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1733197896",
                "title": "DCP - Observability",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1733197896",
                "last_modified": "2026-04-10T15:45:08.173Z",
                "children": [
                  {
                    "id": "1175912508",
                    "title": "[ECS] Humanoid Console - Operations & monitoring",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1175912508",
                    "last_modified": "2026-04-10T15:44:27.995Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1732280387",
                "title": "DCP - On-Call",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1732280387",
                "last_modified": "2026-03-11T16:20:28.883Z",
                "children": [
                  {
                    "id": "1985478659",
                    "title": "DCP - On-Call - Calendar",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1985478659",
                    "last_modified": "2026-07-23T12:34:17.434Z",
                    "children": []
                  },
                  {
                    "id": "1960378386",
                    "title": "DCP - On-Call - Postmortem Template",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1960378386",
                    "last_modified": "2026-05-11T10:07:50.083Z",
                    "children": []
                  },
                  {
                    "id": "1926430781",
                    "title": "DCP - On-Call - Postmortems",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1926430781",
                    "last_modified": "2026-06-05T10:05:40.371Z",
                    "children": [
                      {
                        "id": "1926922409",
                        "title": "[2026-04-27] Postmortem - Evicted pods/jobs are not restarted automatically",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1926922409",
                        "last_modified": "2026-05-18T13:00:46.844Z",
                        "children": []
                      },
                      {
                        "id": "1925480484",
                        "title": "[2026-04-27] Postmortem - Pintel lost connection to Humanoid Console",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1925480484",
                        "last_modified": "2026-05-18T12:58:31.258Z",
                        "children": []
                      },
                      {
                        "id": "1983971370",
                        "title": "[2026-05-18] Postmortem - Prefect Key Reset",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1983971370",
                        "last_modified": "2026-05-22T09:42:48.207Z",
                        "children": []
                      },
                      {
                        "id": "2003435572",
                        "title": "[2026-05-22] Postmortem - CICD major issues because of EKS GPU MIGs",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2003435572",
                        "last_modified": "2026-05-29T09:35:48.148Z",
                        "children": []
                      },
                      {
                        "id": "2030469144",
                        "title": "[2026-05-29] Postmortem - HC is slow",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2030469144",
                        "last_modified": "2026-06-02T13:34:32.082Z",
                        "children": []
                      },
                      {
                        "id": "2030764059",
                        "title": "[2026-05-29] Postmortem - Prefect Worker didn't restart",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2030764059",
                        "last_modified": "2026-05-29T10:10:10.066Z",
                        "children": []
                      },
                      {
                        "id": "2059960333",
                        "title": "[2026-06-05] Weekly Postmortem",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2059960333",
                        "last_modified": "2026-06-05T10:03:20.538Z",
                        "children": []
                      },
                      {
                        "id": "2088796162",
                        "title": "[2026-06-12] Weekly Postmortem",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2088796162",
                        "last_modified": "2026-06-19T09:41:25.112Z",
                        "children": []
                      },
                      {
                        "id": "2119434246",
                        "title": "[2026-06-19] Weekly Postmortem",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2119434246",
                        "last_modified": "2026-06-19T09:45:50.984Z",
                        "children": []
                      },
                      {
                        "id": "2133295166",
                        "title": "[2026-06-26] Weekly Postmortem",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2133295166",
                        "last_modified": "2026-06-26T10:06:00.797Z",
                        "children": []
                      },
                      {
                        "id": "2177302541",
                        "title": "[2026-07-03] Weekly Postmortem",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2177302541",
                        "last_modified": "2026-07-10T09:58:34.646Z",
                        "children": []
                      },
                      {
                        "id": "2204172301",
                        "title": "[2026-07-10] Weekly Postmortem",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2204172301",
                        "last_modified": "2026-07-10T16:05:24.527Z",
                        "children": []
                      },
                      {
                        "id": "2232778759",
                        "title": "[2026-07-17] Weekly Postmortems",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2232778759",
                        "last_modified": "2026-07-17T09:59:25.267Z",
                        "children": []
                      },
                      {
                        "id": "2259550216",
                        "title": "[2026-07-24] Weekly Postmortem",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2259550216",
                        "last_modified": "2026-07-24T09:34:47.188Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "1959297040",
                    "title": "DCP - On-Call Proceedures",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1959297040",
                    "last_modified": "2026-05-11T11:28:30.679Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1731199110",
                "title": "DCP - Runbooks",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1731199110",
                "last_modified": "2026-03-11T16:10:26.939Z",
                "children": [
                  {
                    "id": "1912438833",
                    "title": "Diagnose connection issue from Pintel or Prime-Burger to humanoid-console APIs",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1912438833",
                    "last_modified": "2026-04-27T12:18:03.805Z",
                    "children": []
                  },
                  {
                    "id": "1705639970",
                    "title": "Fix nonexistent package in Humanoid Console",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1705639970",
                    "last_modified": "2026-03-05T12:35:43.071Z",
                    "children": []
                  },
                  {
                    "id": "1886158867",
                    "title": "Set up new Cluster",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1886158867",
                    "last_modified": "2026-04-20T11:05:57.594Z",
                    "children": [
                      {
                        "id": "2013724709",
                        "title": "New cluster setup - Lambda POC",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2013724709",
                        "last_modified": "2026-05-28T13:27:58.951Z",
                        "children": []
                      }
                    ]
                  }
                ]
              }
            ]
          },
          {
            "id": "1732509768",
            "title": "DCP \u2013 Team Space",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1732509768",
            "last_modified": "2026-05-12T08:50:29.029Z",
            "children": [
              {
                "id": "1967128579",
                "title": "DCP - Developer Guide",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1967128579",
                "last_modified": "2026-05-12T08:50:14.736Z",
                "children": []
              },
              {
                "id": "1966866437",
                "title": "DCP - Meeting Minutes",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1966866437",
                "last_modified": "2026-05-12T08:51:11.538Z",
                "children": [
                  {
                    "id": "2149548042",
                    "title": "DCP - MM - Capability Factory",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2149548042",
                    "last_modified": "2026-07-13T09:09:55.438Z",
                    "children": []
                  },
                  {
                    "id": "1965490190",
                    "title": "DCP - MM - Compute & Data Platform Sync with Customers",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1965490190",
                    "last_modified": "2026-07-21T19:47:07.738Z",
                    "children": [
                      {
                        "id": "2071265306",
                        "title": "Jun 7 Oleg pretrain failures",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2071265306",
                        "last_modified": "2026-06-09T09:15:59.167Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "1968799759",
                    "title": "DCP - MM - GPU Providers 2026",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1968799759",
                    "last_modified": "2026-05-13T10:06:49.272Z",
                    "children": [
                      {
                        "id": "1967554593",
                        "title": "[2026-05-07] DCP - MM - Lambda",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1967554593",
                        "last_modified": "2026-05-13T17:24:56.849Z",
                        "children": []
                      },
                      {
                        "id": "1968078870",
                        "title": "[2026-05-12] DCP - MM - Together",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1968078870",
                        "last_modified": "2026-05-18T16:46:22.712Z",
                        "children": []
                      },
                      {
                        "id": "1970602045",
                        "title": "[2026-05-13] DCP - MM - CoreWeave",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1970602045",
                        "last_modified": "2026-05-13T10:08:28.997Z",
                        "children": []
                      },
                      {
                        "id": "1970634821",
                        "title": "[2026-05-13] DCP - MM - Crusoe",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1970634821",
                        "last_modified": "2026-05-13T11:17:46.530Z",
                        "children": []
                      },
                      {
                        "id": "1984462912",
                        "title": "[2026-05-18] DCP - MM - AWS",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1984462912",
                        "last_modified": "2026-05-18T16:01:49.010Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "1972076576",
                    "title": "DCP - MM - General",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1972076576",
                    "last_modified": "2026-05-13T09:29:12.562Z",
                    "children": [
                      {
                        "id": "1971093552",
                        "title": "[2026-05-13] DCP - MM - GPU priorities requirements",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1971093552",
                        "last_modified": "2026-05-19T13:19:48.163Z",
                        "children": []
                      },
                      {
                        "id": "1987870749",
                        "title": "[2026-05-19] How to get rid of NFS for checkpoints",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1987870749",
                        "last_modified": "2026-05-19T11:01:38.781Z",
                        "children": []
                      },
                      {
                        "id": "1991933973",
                        "title": "[2026-05-19] Run jobs from HC",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1991933973",
                        "last_modified": "2026-05-19T15:03:25.151Z",
                        "children": []
                      },
                      {
                        "id": "2015395976",
                        "title": "[2026-06-16] DBT Demo",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2015395976",
                        "last_modified": "2026-06-16T14:18:58.862Z",
                        "children": []
                      },
                      {
                        "id": "2232025136",
                        "title": "[2026-07-17] dev/training pod evictions and PR to fix",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2232025136",
                        "last_modified": "2026-07-17T15:16:30.476Z",
                        "children": []
                      },
                      {
                        "id": "2244870147",
                        "title": "[2026-07-21, 22] Managing Thor's - hmnd-os, deployments",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2244870147",
                        "last_modified": "2026-07-22T13:43:03.204Z",
                        "children": []
                      }
                    ]
                  },
                  {
                    "id": "2038759428",
                    "title": "DCP - MM - On-Call Handover",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2038759428",
                    "last_modified": "2026-07-08T12:23:28.281Z",
                    "children": []
                  },
                  {
                    "id": "1964867683",
                    "title": "DCP - MM - Weekly Plannings",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1964867683",
                    "last_modified": "2026-05-12T10:33:56.044Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1978630201",
                "title": "DCP - Team - Personal Notes",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1978630201",
                "last_modified": "2026-05-15T09:22:44.024Z",
                "children": [
                  {
                    "id": "1966800923",
                    "title": "Denis\u2019s Daily Drain",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1966800923",
                    "last_modified": "2026-05-13T12:16:44.776Z",
                    "children": [
                      {
                        "id": "2174124053",
                        "title": "For the  love of god, stop using CPU limits",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2174124053",
                        "last_modified": "2026-07-02T16:00:53.032Z",
                        "children": []
                      },
                      {
                        "id": "1976336414",
                        "title": "New K8S Deployment Pitfalls",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1976336414",
                        "last_modified": "2026-05-15T09:17:21.491Z",
                        "children": []
                      },
                      {
                        "id": "1966440507",
                        "title": "Running Prefect Jobs From HMND Console",
                        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1966440507",
                        "last_modified": "2026-05-13T12:16:58.953Z",
                        "children": []
                      }
                    ]
                  }
                ]
              },
              {
                "id": "1960214556",
                "title": "DCP - Team Retros",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1960214556",
                "last_modified": "2026-06-01T10:41:13.131Z",
                "children": [
                  {
                    "id": "1960411167",
                    "title": "DCP - Retros - March & Apr",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1960411167",
                    "last_modified": "2026-05-11T10:10:00.399Z",
                    "children": []
                  },
                  {
                    "id": "1960214566",
                    "title": "[2026-05-11] DCP - Retro",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1960214566",
                    "last_modified": "2026-05-18T10:11:37.186Z",
                    "children": []
                  },
                  {
                    "id": "1984102418",
                    "title": "[2026-05-18] DCP - Retro",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1984102418",
                    "last_modified": "2026-05-18T11:03:11.244Z",
                    "children": []
                  },
                  {
                    "id": "2037284893",
                    "title": "[2026-06-01] DCP - Retro",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2037284893",
                    "last_modified": "2026-06-01T10:58:54.305Z",
                    "children": []
                  },
                  {
                    "id": "2065563653",
                    "title": "[2026-06-08] DCP - Retro",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2065563653",
                    "last_modified": "2026-06-22T10:30:28.782Z",
                    "children": []
                  },
                  {
                    "id": "2122023113",
                    "title": "[2026-06-22] DCP - Retro",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2122023113",
                    "last_modified": "2026-07-06T10:26:23.026Z",
                    "children": []
                  },
                  {
                    "id": "2184445976",
                    "title": "[2026-07-06] DCP - Retro",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2184445976",
                    "last_modified": "2026-07-06T11:00:16.347Z",
                    "children": []
                  },
                  {
                    "id": "2212429863",
                    "title": "[2026-07-13] DCP - Retro",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2212429863",
                    "last_modified": "2026-07-20T10:21:18.069Z",
                    "children": []
                  },
                  {
                    "id": "2238054408",
                    "title": "[2026-07-20] DCP - Retro",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2238054408",
                    "last_modified": "2026-07-20T11:05:15.732Z",
                    "children": []
                  }
                ]
              }
            ]
          },
          {
            "id": "1732968545",
            "title": "DCP \u2013 Users",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1732968545",
            "last_modified": "2026-05-14T14:40:04.599Z",
            "children": [
              {
                "id": "938901796",
                "title": "DCP - User Guide - Data Platform",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/938901796",
                "last_modified": "2026-05-01T10:37:40.841Z",
                "children": [
                  {
                    "id": "1071644723",
                    "title": "DCP - User Guide - Build LeRobot datasets",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1071644723",
                    "last_modified": "2026-03-19T17:22:00.270Z",
                    "children": []
                  },
                  {
                    "id": "1934196842",
                    "title": "DCP - User Guide - Enable Foxglove Playback on macOS Without Disabling VPN",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1934196842",
                    "last_modified": "2026-05-01T10:35:41.951Z",
                    "children": []
                  },
                  {
                    "id": "1930461193",
                    "title": "DCP - User Guide - Episodes Preprocessor",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1930461193",
                    "last_modified": "2026-04-30T10:27:22.724Z",
                    "children": []
                  },
                  {
                    "id": "1854668807",
                    "title": "DCP - User Guide - Ray Workbench",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1854668807",
                    "last_modified": "2026-04-13T08:49:08.421Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1744502839",
                "title": "DCP - User Guide - DevPods",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1744502839",
                "last_modified": "2026-03-13T16:40:00.781Z",
                "children": []
              },
              {
                "id": "1916141569",
                "title": "DCP - User Guide - How to add new users to Humanoid AWS account",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1916141569",
                "last_modified": "2026-04-27T20:12:15.861Z",
                "children": []
              },
              {
                "id": "1916796929",
                "title": "DCP - User Guide - How to add new users to VPN",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1916796929",
                "last_modified": "2026-04-27T20:14:25.454Z",
                "children": []
              },
              {
                "id": "1771372601",
                "title": "DCP - User Guide - Loki (logs)",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1771372601",
                "last_modified": "2026-03-20T11:16:39.579Z",
                "children": []
              },
              {
                "id": "1770160181",
                "title": "DCP - User Guide - Prefect",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1770160181",
                "last_modified": "2026-04-17T09:32:41.673Z",
                "children": []
              },
              {
                "id": "1925316627",
                "title": "DCP - User Guide - aws s3 and cloudflare r2",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1925316627",
                "last_modified": "2026-07-16T23:20:38.717Z",
                "children": []
              },
              {
                "id": "2052554775",
                "title": "DCP - Users - Episode Metrics Framework",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2052554775",
                "last_modified": "2026-07-21T12:12:36.053Z",
                "children": []
              },
              {
                "id": "1976827939",
                "title": "DCP - Users - Reports",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1976827939",
                "last_modified": "2026-05-14T14:39:47.813Z",
                "children": [
                  {
                    "id": "2139947030",
                    "title": "DCP - Custom Reports - Training Data Consumption per GPU",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2139947030",
                    "last_modified": "2026-06-24T17:23:02.288Z",
                    "children": []
                  },
                  {
                    "id": "1977352222",
                    "title": "DCP - Reports - Job Scheduling SLI, Jan-May 2026",
                    "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1977352222",
                    "last_modified": "2026-05-28T18:18:56.499Z",
                    "children": []
                  }
                ]
              },
              {
                "id": "1713242377",
                "title": "First pull request on a devpod with Cursor on a clean mac",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1713242377",
                "last_modified": "2026-06-25T18:44:47.257Z",
                "children": []
              }
            ]
          }
        ]
      },
      {
        "id": "613318735",
        "title": "\ud83e\udded Navigation & Perception",
        "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/613318735",
        "last_modified": "2026-07-24T14:35:23.691Z",
        "children": [
          {
            "id": "2205188105",
            "title": "2D Collision Detection & Prevention - What We Learned",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2205188105",
            "last_modified": "2026-07-20T10:44:48.875Z",
            "children": []
          },
          {
            "id": "1280311304",
            "title": "Beta Head \u2013 Sensors Configuration",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1280311304",
            "last_modified": "2025-11-14T15:15:22.130Z",
            "children": [
              {
                "id": "1293647884",
                "title": "Meeting notes on horizontal vs vertical",
                "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1293647884",
                "last_modified": "2025-11-20T14:16:46.216Z",
                "children": []
              }
            ]
          },
          {
            "id": "1348829206",
            "title": "Camera Timestamping",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1348829206",
            "last_modified": "2025-11-26T14:57:30.127Z",
            "children": []
          },
          {
            "id": "2244444175",
            "title": "RecoveryPilot - recovery for the local planners",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2244444175",
            "last_modified": "2026-07-21T09:41:51.199Z",
            "children": []
          },
          {
            "id": "1234468878",
            "title": "VI-SLAM Testing and Benchmarking",
            "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1234468878",
            "last_modified": "2025-11-17T18:25:03.868Z",
            "children": []
          }
        ]
      }
    ],
    "authors": [
      {
        "id": "712020:388385db-5b1b-441f-b863-6b3792c69ee3",
        "name": "Eugene Victorov",
        "pages_created": 205,
        "pages_last_edited": 358,
        "recent_edits": 61,
        "last_active": "2026-07-22T14:11:51.993Z"
      },
      {
        "id": "712020:702a7f31-a522-4a9e-a17e-c4b8beed6d7a",
        "name": "Anastasia Savelyeva (Deactivated)",
        "pages_created": 172,
        "pages_last_edited": 85,
        "recent_edits": 0,
        "last_active": "2026-05-28T18:18:58.621Z"
      },
      {
        "id": "712020:9c4fae5e-69b1-4159-8641-41f0a3e98f9e",
        "name": "Natalia Uttsova (Deactivated)",
        "pages_created": 113,
        "pages_last_edited": 94,
        "recent_edits": 0,
        "last_active": "2026-04-30T14:29:33.277Z"
      },
      {
        "id": "712020:0a41c0f4-871a-4fcb-a0b5-a76cb1fbadf5",
        "name": "Artem Shutak",
        "pages_created": 102,
        "pages_last_edited": 99,
        "recent_edits": 23,
        "last_active": "2026-07-24T16:27:52.113Z"
      },
      {
        "id": "712020:267d8dc5-ff84-464a-9540-7d7a5dda9f60",
        "name": "Jason Kline",
        "pages_created": 84,
        "pages_last_edited": 70,
        "recent_edits": 1,
        "last_active": "2026-07-01T07:58:25.907Z"
      },
      {
        "id": "712020:a8861672-8fc5-4664-8717-14add60bb0e1",
        "name": "Adam Cantor (Deactivated)",
        "pages_created": 76,
        "pages_last_edited": 59,
        "recent_edits": 0,
        "last_active": "2025-11-25T20:27:27.268Z"
      },
      {
        "id": "712020:15d56293-96ff-40d2-a06d-912f776e2042",
        "name": "Cody Griffin",
        "pages_created": 76,
        "pages_last_edited": 70,
        "recent_edits": 1,
        "last_active": "2026-07-15T14:25:16.476Z"
      },
      {
        "id": "712020:82bbf049-c4d4-4e76-b96c-6cf6c3edfca2",
        "name": "Claudiu Filip",
        "pages_created": 73,
        "pages_last_edited": 40,
        "recent_edits": 1,
        "last_active": "2026-07-07T08:59:57.236Z"
      },
      {
        "id": "712020:4b0b8f62-bb33-4ff4-adc3-a014657a7ba9",
        "name": "Fredrik Larsen",
        "pages_created": 51,
        "pages_last_edited": 52,
        "recent_edits": 1,
        "last_active": "2026-06-30T08:19:36.417Z"
      },
      {
        "id": "712020:7766f2fb-e92b-40c6-b7e2-d6dba4140086",
        "name": "Sandi Smole",
        "pages_created": 46,
        "pages_last_edited": 41,
        "recent_edits": 0,
        "last_active": "2026-02-03T10:18:47.895Z"
      },
      {
        "id": "712020:c7eb70c8-c41f-44d0-bc02-6a41533fa6f3",
        "name": "Vladimir Ershov (Deactivated)",
        "pages_created": 45,
        "pages_last_edited": 122,
        "recent_edits": 0,
        "last_active": "2025-07-24T10:28:28.999Z"
      },
      {
        "id": "712020:7df6d5c9-5e81-453f-8af7-45995ec2cdfc",
        "name": "Dmitriy Shingarey",
        "pages_created": 41,
        "pages_last_edited": 39,
        "recent_edits": 4,
        "last_active": "2026-07-21T15:45:30.492Z"
      },
      {
        "id": "712020:cc27aab1-4402-495a-b83e-b23a4ff69104",
        "name": "Mohammed Diab (Deactivated)",
        "pages_created": 40,
        "pages_last_edited": 14,
        "recent_edits": 0,
        "last_active": "2025-07-11T13:26:38.228Z"
      },
      {
        "id": "712020:68640094-4ae6-474f-9526-81b69f91013a",
        "name": "Nia Oloyede",
        "pages_created": 39,
        "pages_last_edited": 44,
        "recent_edits": 4,
        "last_active": "2026-07-22T15:55:05.965Z"
      },
      {
        "id": "712020:abbae0a7-cc91-44b8-911e-131490bbeed9",
        "name": "Igor Kotenkov (Deactivated)",
        "pages_created": 38,
        "pages_last_edited": 16,
        "recent_edits": 0,
        "last_active": "2025-06-16T23:04:02.852Z"
      },
      {
        "id": "712020:a1aa3066-59fe-4411-b004-fbd8e76c3c07",
        "name": "Brian Delhaisse",
        "pages_created": 36,
        "pages_last_edited": 37,
        "recent_edits": 2,
        "last_active": "2026-07-13T17:39:52.299Z"
      },
      {
        "id": "712020:aac64401-545a-4eb1-b886-079834e8cfb4",
        "name": "Yoo-Jin Jung",
        "pages_created": 34,
        "pages_last_edited": 36,
        "recent_edits": 5,
        "last_active": "2026-07-24T15:13:30.541Z"
      },
      {
        "id": "712020:167492ee-e5c2-4a20-a8e2-93db25067d13",
        "name": "Nima Ebrahimzade",
        "pages_created": 33,
        "pages_last_edited": 22,
        "recent_edits": 0,
        "last_active": "2025-11-07T15:31:39.262Z"
      },
      {
        "id": "712020:1950d396-c339-49fb-ae27-2a7d112b9c22",
        "name": "Wilberth Solano",
        "pages_created": 32,
        "pages_last_edited": 39,
        "recent_edits": 6,
        "last_active": "2026-07-23T14:35:50.318Z"
      },
      {
        "id": "712020:4a88ef3e-c1fc-40ec-945f-1ad7efb95080",
        "name": "Yuriy Strezhik",
        "pages_created": 27,
        "pages_last_edited": 25,
        "recent_edits": 1,
        "last_active": "2026-07-15T16:27:26.927Z"
      }
    ],
    "highlighted_author": {
      "id": "712020:15d56293-96ff-40d2-a06d-912f776e2042",
      "name": "Cody Griffin",
      "pages_created": 76,
      "pages": [
        {
          "id": "2064842814",
          "title": "Spec: Switchboard State Model & Fleet Registry",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2064842814",
          "last_modified": "2026-07-15T14:25:16.476Z",
          "created_at": "2026-06-07T20:55:41.959Z",
          "body_html": "<h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-Spec:SwitchboardStateModel&amp;FleetRegistry\">Spec: Switchboard State Model &amp; Fleet Registry</h1><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-1.ProblemDefinition\">1. Problem Definition</h2><p>A site is run by many agents acting at once \u2014 several robots, the fleet agents that assign and monitor them, human operators, and System-3 integrations (a customer WMS, a SynaOS AGV fleet). They share work, space, and equipment, and nothing keeps them from unknowingly stepping on each other unless something records what is being done and what is believed to be true. Switchboard is that something: the one place those agents synchronize. This spec defines the state model that makes the synchronization honest \u2014 what a subject is, what a fact is and where its truth lives, how fresh it is, who may write it, and where it is authoritative versus merely cached.</p><p>Two framings have to be rejected up front, because both are quietly assumed in the current system. The first is that Switchboard <em>is</em> the workflow: a robot comes up already bound to a workflow and is expected to fire transitions even while unlocalized, mislocated, or holding stale beliefs. The second is that Switchboard is the world model \u2014 that its Petri net is authoritative over reality. It is neither. <strong>It coordinates agents and replicates the state they need to coordinate against; the truth lives at the edge, and the net is one valid view of the work, not the territory.</strong> The robot knows reality better than Switchboard does, and the model is explicitly allowed to be a schematic approximation that reality is permitted to diverge from.</p><p>Getting this layer right also gives every other system one legible place to plug in. A WMS, a SynaOS AGV master, an operator console, and a robot are all just agents that read and write the same state through the same surface \u2014 which is what keeps integrations at arm's length from the robot stack instead of threaded through it.</p><p>The prototype makes the cost of <em>not</em> having this layer concrete:</p><ul><li><p>A robot sat <code>localizing</code>, unable to resolve <code>tf map \u2192 base_link</code>, while coordination still counted it a participant.</p></li><li><p>Per-robot facts collided because the key namespace had no notion of <em>which</em> robot (<code>push_facts</code> had to be hand-namespaced <code>robot1/foo</code>).</p></li><li><p>Coordinator-side map/tag edits got clobbered because robots re-sync map data and &quot;there is no clear ownership over map/tags between robots and coordinator.&quot;</p></li><li><p>A <strong>single-workflow-at-a-time regression</strong> crept in when map-sharing was implemented, because <em>workflow</em> and <em>map</em> were treated as interchangeable \u2014 &quot;I thought it was interchangeable&quot; \u2014 when in fact a robot should self-register to a workflow, pull its map, and decide its own assignments.</p></li><li><p>The whole stack assumes a single always-on coordinator, which does not survive a customer site where the VPN flaps.</p></li></ul><p>These are all symptoms of an absent state model: no subject identity, no ownership, no freshness, no authority placement, no clean separation of the logical (workflow) and physical (map) axes.</p><p>The anchor is the Schaeffler pilot (Herzogenaurach, end of 2026; Schweinfurt to follow), which forces every one of these: small fleets that must coordinate without colliding, intermittent and locked-down connectivity, a SynaOS / SAP customer, navigation built on recorded trajectories and visual localization, and operators who need to see where everything is on a map.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-2.WhatSwitchboardIs\">2. What Switchboard Is</h2><p>Switchboard is the <strong>coordination primitive</strong> for everything that acts on a site \u2014 robots, fleet agents, operators, and System-3 integrations (SAP/WMS, the SynaOS AGV fleet). It is deliberately dumb: &quot;it doesn't really do anything but answer queries and update its internal state.&quot; It does not plan, schedule, or optimize, and the Petri net is not authoritative over reality \u2014 multiple assignments may be valid at once and the robot agent (Reverb) chooses among them. It does not hold any agent's private context or reasoning; it holds only the shared state agents coordinate against. Switchboard's job is to ensure two agents never <em>unknowingly</em> do conflicting work, to preserve what actually happened, and to be the one legible place every agent plugs into.</p><p><strong>&quot;Dumb&quot; applies to the coordination plane, not the config plane.</strong> Switchboard answers coordination queries and serializes coordination state without intelligence. It <em>does</em> hold registry and authorization configuration (fleets, sites, maps, workflows, groups) \u2014 but that is static data pushed from a cloud-authoritative config plane, never logic on the robot hot path. The doctrine &quot;the registry is data, not schema&quot; (\u00a714) applies to identity as much as to coordination.</p><p>The reframing this spec makes explicit: <strong>Switchboard is authoritative for almost nothing.</strong> It owns the coordination it computes \u2014 markings and leases \u2014 strongly and transactionally, and replicates everything else from a source of truth that lives at the edge.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" width=\"1536\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/2064842814/image-20260607-205726.png?version=1&amp;modificationDate=1780865848116&amp;cacheVersion=1&amp;api=v2&amp;width=1536&amp;height=1024\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/2064842814/image-20260607-205726.png?version=1&amp;modificationDate=1780865848116&amp;cacheVersion=1&amp;api=v2\" data-height=\"1024\" data-width=\"1536\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"2063990915\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20260607-205726.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"2064842814\" data-linked-resource-container-version=\"5\" data-media-id=\"4c41b978-75b7-406b-87de-12c1a5c8c255\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/2064842814/image-20260607-205726.png?version=1&amp;modificationDate=1780865848116&amp;cacheVersion=1&amp;api=v2&amp;width=1536&amp;height=1024 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/2064842814/image-20260607-205726.png?version=1&amp;modificationDate=1780865848116&amp;cacheVersion=1&amp;api=v2&amp;width=1536&amp;height=1024 1x\"></span><p><br/>\u200c</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-3.TwoRegistries:BackboneandSwitchboard\">3. Two Registries: Backbone and Switchboard</h2><p>Identity and coordination are separated by lifetime and blast radius.</p><p><strong>Backbone</strong> is global and owns <strong>device identity</strong>: every physical chassis as a hardware identity, its attestation, SPIFFE SVID, and certificate lifecycle (it already federates auth through Cognito). A device keeps its Backbone identity wherever it is deployed; nothing else mints device identity.</p><p><strong>Switchboard</strong> is per-deployment and owns the <strong>fleet registry</strong> plus coordination state \u2014 fleets, sites, robot site deployments, maps, workflow definitions, workflow instances, executors, and assignments. It holds device identity only as a reference outward to Backbone and authorizes against its own registry. <strong>Identity is global; authorization is local.</strong></p><p>Four identity/authority lifetimes are kept distinct (consistent with the Outpost spec): <strong>device identity</strong> (what hardware this is \u2014 long-lived), <strong>fleet identity</strong> (which fleet it may join \u2014 rotated), <strong>entitlement</strong> (what it may do \u2014 policy), and <strong>lease</strong> (what it may do <em>right now</em> \u2014 short-lived). This spec governs the last three as they appear in coordination; device identity is Backbone's.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-4.TheHierarchy:Enroll,Deploy,Assign\">4. The Hierarchy: Enroll, Deploy, Assign</h2><p><strong>This section exists to kill the single-workflow regression.</strong> That bug happened because <em>workflow</em> and <em>map</em> were conflated. They are distinct axes, joined by three explicit actions, and robots are never <em>pushed</em> a workflow \u2014 they <strong>poll</strong> for their assignment and pull what they need.</p><ul><li><p><strong>Fleet</strong> is the <em>logical</em> unit \u2014 the coordination domain and isolation/RLS boundary; all markings, leases, and facts live inside one fleet. Robots are fleet resources.</p></li><li><p><strong>Site</strong> is the <em>physical</em> unit \u2014 a building. Maps describe a site; workflows move robots within a site.</p></li><li><p>A <strong>robot site deployment</strong> records which site a physical robot is currently operating at. Fleet\u00d7site deployment is deferred until there is a real site-sharing requirement.</p></li><li><p>A <strong>map</strong> is a versioned spatial model of (part of) a site. A site may have <strong>more than one map</strong> \u2014 different configurations, or deliberately broken up for reliability/stability \u2014 but a <strong>workflow definition belongs to exactly one site map</strong>.</p></li><li><p>An <strong>assignment</strong> binds an executor to a running workflow instance (and therefore, transitively, to that instance's workflow definition and pinned map version).</p></li></ul><p><strong>Implementation note from the Rust MVP.</strong> Maps and workflows are intentionally not packaged as a single durable &quot;bundle&quot; yet. A running instance records the workflow definition version and map it started against, and validation checks that a definition's referenced places exist on its target map. Studio or Reverb may later introduce import/export bundles for convenience, but Switchboard's coordination model keeps maps and workflow definitions independently versioned.</p><p>The three actions:</p><ol start=\"1\"><li><p><strong>Enroll</strong> \u2014 a robot joins a <em>fleet</em> via its Backbone device cert and receives a fleet cert. Durable. From this point its resource facts (pose, power, localization) replicate at fleet scope whether or not it is doing anything.</p></li><li><p><strong>Deploy</strong> \u2014 a robot is deployed to a <em>site</em>, constraining which maps and workflows can be assigned to its executor.</p></li><li><p><strong>Assign</strong> \u2014 an executor is bound to a running <em>workflow instance</em> (via <code>executor_instance_assignments</code>, \u00a7A.1). The robot <strong>polls</strong> to discover its assignment, then pulls the workflow's map and the workflow itself from Switchboard.</p></li></ol><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"57abfce4-1ed8-4ce8-bebb-5277c643af97\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">fleet \u2500\u2500 robot \u2500\u2500(site deployment)\u2500\u2500 site \u2500\u2500 site_map \u2500\u2500 workflow_definition\n  \u2514\u2500\u2500 executor \u2500\u2500(assignment)\u2500\u2500\u2500\u2500\u2500\u2500 workflow_instance \u2500\u2500 pins definition version + map version\n\ndeployment = robot \u00d7 site          assignment = executor \u00d7 workflow_instance</pre>\n</div></div><p>Switchboard <strong>never pushes</strong> a workflow onto a robot. A human, UI, or System-3 agent records an <em>assignment</em> in Switchboard; the robot discovers it by polling. (A future push channel is permitted only if latency/bandwidth ever demands it, as an explicit exception \u2014 not the default.) Two robots in different workcells therefore run two workflows on two maps in one site, coordinated by per-robot assignment rather than by forcing a single shared map \u2014 exactly the &quot;develop in workcell A while the other works in workcell B&quot; case the regression broke.</p><p>A fleet deploys to <strong>one site at a time</strong> (coordination requires a shared site). It does <strong>not</strong> require a single shared map \u2014 &quot;they must share the same map while operating in the same space,&quot; but distinct spaces within a site may use distinct maps. This resolves the v0 open question &quot;is one-fleet-per-site a hard rule?&quot;: <strong>one site per fleet deployment, not one map.</strong></p><p>The <code>map</code> registry row holds the <strong>version, metadata, and named places</strong>; the heavy map <em>assets</em> (occupancy grid, 3D semantic mesh, recorded trajectories) live in object storage and are referenced by URI. Switchboard does not store map rasters.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-5.Subjects,Identifiers,andState\">5. Subjects, Identifiers, and State</h2><p>State attaches to a <strong>subject</strong>. A subject's <em>kind</em> is a plain logistics noun:</p><ul><li><p><strong>resource</strong> \u2014 equipment with live state: robots (location, power, localization).</p></li><li><p><strong>load</strong> \u2014 things moved: totes, items, goods.</p></li><li><p><strong>place</strong> \u2014 fixed locatable things: slots, tables, chargers, conveyors, zones \u2014 <em>and map landmarks</em>. A tag is just a place a map owns.</p></li><li><p><strong>work</strong> \u2014 orders, tasks, locks, reservations (the tokens that flow through the net).</p></li><li><p><strong>scope</strong> \u2014 tenant, fleet, site, map, workflow.</p></li></ul><h3 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-Identifiers\">Identifiers</h3><p>A subject's identity is a <strong>UUIDv7</strong> \u2014 a time-ordered RFC 9562 id, <strong>generated app-side</strong> in the Rust service and stored as the built-in 16-byte <code>uuid</code> type. The millisecond-timestamp prefix keeps inserts local in the B-tree and recently-created rows sorted together, where random v4 scatters writes and fragments the index. App-side generation removes any dependency on a specific Postgres version or extension being present at every (often locked-down) customer site, and the service already mints ids for claims and leases. The scheme is forward-compatible: a site on Postgres 18 may switch to native <code>uuidv7()</code> with no schema change, since it is the same type and layout.</p><p>The id <em>is</em> the identity; <code>kind</code> is a separate column; a subject also carries a mutable <code>label</code> (a human name like <code>r12</code>) and an <code>external_ref</code> (a customer/protocol id \u2014 AGV serial, SAP order number, tote barcode). <strong>Identity is never parsed out of a string</strong>, and a physical thing keeps <strong>one durable subject identity</strong> for its whole life regardless of how it is currently represented (see \u00a76 \u2014 a tote is the same subject whether sitting on a table or being carried).</p><p>Display and logs <strong>render</strong> a subject by composing kind + label (or a short id): <code>robot:r12</code>, <code>load:0197f96c\u2026</code>. Throughout this doc, <code>robot:r12</code>-style strings are that <em>rendered</em> form, not the stored key. Integrations map their external ids onto <code>external_ref</code> without colliding with internal identity, so relabeling a robot or re-barcoding a tote never breaks a reference. (Registry scopes keep stable human <strong>slugs</strong> instead of UUIDs, because they appear in SPIFFE paths and URLs.)</p><h3 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-Statekinds\">State kinds</h3><p>Three kinds of state attach to a subject:</p><ul><li><p><strong>Markings</strong> \u2014 a token's place in a net. Changed only by transitions; owned by Switchboard; <strong>strongly consistent</strong>; <strong>bounded</strong> (sink places reap, \u00a712).</p></li><li><p><strong>Facts</strong> \u2014 observed/declared/derived state; many writers; an <strong>eventually-consistent replica</strong>; inform guards. At MVP, <strong>links are just facts</strong> too (a <code>carried_by</code> fact whose value is the carrier's id); a typed link table is a later optimization.</p></li><li><p><strong>Leases</strong> \u2014 exclusive claims to act; <strong>strongly consistent</strong>; serialize dispatch (\u00a710).</p></li></ul><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-6.FactsAreReplicas\u2014andWhoOwnsDynamicTruth\">6. Facts Are Replicas \u2014 and Who Owns Dynamic Truth</h2><p>The central principle: <strong>a fact is an eventually-consistent replica of state whose source of truth lives elsewhere.</strong> Switchboard does not originate facts; it holds a cached copy for coordination, and that copy is allowed to lag its source.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"717315f6-23f5-4b7f-8323-99c072a1c9b1\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">source of truth            replicated into Switchboard as     governed by\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500             \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500      \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nrobot (self-telemetry)  \u2500\u2500\u25b6 resource facts (pose, power, loc.)  TTL   (perishable)\nrobot (perception)      \u2500\u2500\u25b6 observed facts (load locations)     TTL   (perishable)\nmap version             \u2500\u2500\u25b6 place facts   (tags, zones)         epoch (versioned, static)\noperator                \u2500\u2500\u25b6 declared facts (overrides)          TTL or sticky\nSwitchboard             \u2500\u2500\u25b6 markings, leases                    authoritative + strong</pre>\n</div></div><p><strong>Static vs. dynamic ownership \u2014 the key division.</strong> The map / world-model owns <strong>static</strong> truth: tags, places, zones, semantic anchors. <strong>Robot perception</strong> owns <strong>dynamic</strong> truth: where movable objects actually are right now. A tote does not self-report and the map is not expected to track it; instead a robot is told (loosely, by an order or a prior) that a tote is at a table, goes there, and its perception answers <em>present or not</em> \u2014 and if present, picks it up and carries it. This deliberately does <strong>not</strong> centralize dynamic object location in a single world-model writer; each robot reports what it sees, duplicates are expected, and the model is not required to be perfect. A stale or missing load fact fails a guard closed (safe) and surfaces as an exception (\u00a78), never as a fleet-wide bottleneck.</p><p><strong>Tags and poses are the same kind of thing, differing in volatility and source.</strong> Both are locatable facts replicated from an external source. A pose is perishable \u2192 TTL-governed, source must keep re-asserting (a replica that stops refreshing goes stale \u2014 the desired behavior). A tag is static \u2192 epoch-governed, invalidated only when the map version bumps. &quot;Inherit semantics from the map&quot; and &quot;replicate pose from the robot&quot; are the <em>same operation</em>; TTL/epoch fall out of replication rather than being bolted on. This is why tags are not first-class: a tag is a map-sourced place fact, nothing more.</p><p><strong>Many writers, no collisions.</strong> Every fact has an authorized writer, and authority is granted <em>per subject</em>, not per fact kind. A fleet runs one Reverb per robot; each publishes <code>pose</code>, <code>power</code>, and <code>localization.current</code> only about its own robot (self-bound, \u00a7B.6), keyed by <code>(subject, key)</code> (\u00a75). Twelve Reverbs writing <code>pose</code> are twelve writes to twelve different subjects \u2014 not contention for one row. The map server is a different writer with different authority: it publishes the <strong>place</strong> facts the map owns (tags, zones). So a <code>pose</code> about a robot and a location about a tote both exist, written by different authorized writers, never in each other's way \u2014 and the tote's location comes from <strong>robot perception</strong>, not the map.</p><h3 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-Carriedthings:locationisatokenmode,resolvedbyasnapshotonplace\">Carried things: location is a token <em>mode</em>, resolved by a snapshot on place</h3><p>A tote is a <code>load</code>, and a load is locatable \u2014 but <strong>location is a fact (a pose); what the token encodes is the </strong><em><strong>mode</strong></em><strong>: relative-located or absolute-located.</strong></p><ul><li><p><strong>Absolute-located</strong> (sitting at a place): the tote has a real, frozen absolute pose fact. It does not re-derive and so cannot go stale by drift; it changes only when the tote is next moved.</p></li><li><p><strong>Relative-located</strong> (carried): the <strong>pick</strong> transition consumes the absolute-located token and produces a relative-located one whose pose is <em>derived from the carrier's</em> pose for as long as a <code>carried_by</code> link (a fact whose value is the carrier id, \u00a75) holds. The <strong>place</strong> transition consumes the relative-located token and produces an absolute-located token by <strong>collapsing</strong> the derived pose into a frozen absolute snapshot at the robot's current location.</p></li></ul><p>The consequence for freshness: <strong>carrier-pose staleness can only mislocate a tote while it is being carried</strong>, never once it is set down \u2014 placement snapshots the pose. The staleness surface is bounded to the carry window, and it fails closed because a stale carried-token's derivation dies with the carrier's epoch (\u00a711). Through all of this the tote is <strong>one subject</strong> (stable UUIDv7); only its token's mode and place change \u2014 that stable identity is the continuity thread that lets us refer to &quot;the same tote&quot; as it moves between standalone and carrier-linked representations. A <strong>dropped</strong> tote is not silent staleness but an explicit <code>carried \u2192 dropped</code> transition that records last-known position and flags for an operator (\u00a78). (Conveyors \u2014 where a tote moves with no carrier holding it \u2014 are the genuinely tricky case and are out of scope here.)</p><p>The link is just another fact, so it rides the same replication, freshness, and authorization machinery as everything else: the executor that owns the pick transition is the one authorized to assert <code>carried_by</code> (\u00a7B.6).</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-7.ScopeandProjection\">7. Scope and Projection</h2><p>Two mechanisms resolve where facts live and the idle-robot question:</p><p><strong>Ingress replica (a real cached copy).</strong> A robot's pose/power/localization lives at <strong>fleet scope</strong> \u2014 the robot is a fleet resource, so its facts exist whether or not it is assigned to a workflow. <em>That is the idle-robot answer:</em> an idle robot's power is a fleet-scoped resource fact, no workflow required. Map places live at <strong>map scope</strong>, versioned. These are real rows replicated from an external SoT, hence TTL/epoch.</p><p><strong>Workflow projection (a logical join, no copy).</strong> A running workflow instance does not own these facts and does not duplicate them. It <strong>projects</strong> the relevant subset \u2014 the resource facts of its assigned robots, the place facts of its map, the observed loads in scope \u2014 alongside the markings it owns, so guards evaluate against one consistent snapshot. &quot;Assigned to a workflow&quot; means projected-into, not stored-under.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"0ed56330-73b5-4afd-8634-c9e8d6e9736c\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">fleet \u2500\u2500 robot (resource) \u2500\u2500 pose/power/loc facts \u2510  fleet-scoped replica\n                                                   \u251c\u2500\u25b6 workflow projects both + owns markings\nsite \u2500\u2500 map \u2500\u2500 place facts (tags, zones) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518  map-scoped replica\n        \u2514\u2500 workflow (running instance)</pre>\n</div></div><p>The deployment (fleet \u00d7 site) and assignment (robot \u00d7 workflow) together make the join coherent: the fleet's robots, assigned to a workflow, projected onto that workflow's map.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-8.ThreeQueryLenses,andtheExceptionPrinciple\">8. Three Query Lenses, and the Exception Principle</h2><p>Because facts live at their owning scope and workflows only project, the same replicated facts are reachable three ways \u2014 different join paths, one underlying store:</p><ul><li><p><strong>By fleet / robots (operations lens):</strong> every robot's resource facts \u2014 pose, power, localization, status \u2014 <em>valid when idle</em>. &quot;Show me my fleet.&quot; No workflow needed.</p></li><li><p><strong>By map (spatial / plotting lens):</strong> every locatable subject resolvable on <code>map@v</code> \u2014 the map's own places plus the resources and loads localized on it. &quot;Plot the floor.&quot; Needs a map and fresh poses, not a workflow. This is the operator map view.</p></li><li><p><strong>By workflow (coordination lens):</strong> the instance's markings plus the projected facts for its participating subjects. &quot;Why isn't this transition firing.&quot; Needs a running instance.</p></li></ul><h3 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-Theexceptionprinciple\">The exception principle</h3><p>Reality diverges from the schematic constantly. There is <strong>no single exception mechanism</strong>; there is a single <strong>principle</strong>: <em>degrade to keep operating as reliably as possible, and flag the exception for a remote operator to resolve.</em> Each case gets its own most-graceful local behavior, and all of them log a domain event and raise an operator-visible flag. They never hard-stop the fleet.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Anomaly</p></th><th class=\"confluenceTh\"><p>Graceful local behavior</p></th><th class=\"confluenceTh\"><p>Surfaced as</p></th></tr><tr><td class=\"confluenceTd\"><p>Map update removes/moves a tag a running instance uses</p></td><td class=\"confluenceTd\"><p>Guards referencing it fail closed (wrong epoch/missing)</p></td><td class=\"confluenceTd\"><p>Operator flag; resolve by migration or re-tag</p></td></tr><tr><td class=\"confluenceTd\"><p>Robot claims a non-conforming transition</p></td><td class=\"confluenceTd\"><p>Accepted and recorded (loud); token may move to <code>__quarantine__</code>/<code>__illegal__</code> (\u00a710)</p></td><td class=\"confluenceTd\"><p>Conformance event; operator can resolve</p></td></tr><tr><td class=\"confluenceTd\"><p>Robot drops a carried tote</p></td><td class=\"confluenceTd\"><p>Explicit <code>carried \u2192 dropped</code> transition with last-known pose</p></td><td class=\"confluenceTd\"><p>Operator flag</p></td></tr><tr><td class=\"confluenceTd\"><p>Leased task abandoned (never claimed)</p></td><td class=\"confluenceTd\"><p>Lease TTL-expires; work returns to the pool</p></td><td class=\"confluenceTd\"><p>Conformance/timeout event</p></td></tr><tr><td class=\"confluenceTd\"><p>Perception asserts something implausible</p></td><td class=\"confluenceTd\"><p>Fact fails plausibility/freshness; guard fails closed</p></td><td class=\"confluenceTd\"><p>Operator flag</p></td></tr><tr><td class=\"confluenceTd\"><p>Token stranded by migration</p></td><td class=\"confluenceTd\"><p><code>__quarantine__</code> (\u00a79)</p></td><td class=\"confluenceTd\"><p>Operator/agent resolves</p></td></tr></tbody></table></div><p>Quarantine and other reserved-place residents are bounded the same way as sink places (\u00a712): they are visible, alertable, and reaped on a policy so they don't become silent WIP leaks.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-9.Definitions,Instances,andMigration\">9. Definitions, Instances, and Migration</h2><p>A workflow exists at two levels, and the data model must keep them distinct.</p><p>A <strong>definition</strong> is an immutable, versioned template \u2014 the canonical Petri net, authored against a particular map. The net is <strong>evaluated from a Starlark source</strong> (Appendix I): the author (human or agent) writes Starlark, the server evaluates it once into a normalized Petri net (the canonical IR) and hashes that, and the <strong>immutable artifact is the evaluated net, not the source text</strong>. New versions are appended; a version is never mutated. An <strong>instance</strong> is a running instantiation of one definition version on a map within a deployment. The instance holds the strongly-consistent markings and leases; the definition is just the template it currently conforms to. One definition may have many instances (testing, simulation, physical twins).</p><p>Starlark rather than hand-written YAML because definitions are now mostly machine-authored and increasingly parametric: a Python-subset language gives loops, conditionals, and reusable macros (one source emits N near-identical work cells), evaluates hermetically and deterministically (no clocks, no I/O \u2014 see Appendix I), and is far easier and more familiar for an authoring agent to emit, diff, and validate than soupy YAML. The runtime never sees Starlark; it sees the evaluated IR, so execution, conformance, and migration are unchanged from the Coordinator spec. <strong>Existing YAML workflows</strong> (the <code>symphony2_*.yaml</code> corpus) are handled by <strong>conversion tooling</strong> into Starlark/IR; YAML is not maintained as a perpetual first-class authoring input.</p><p><strong>Map\u2194workflow references are soft.</strong> A workflow references its map's places by name/identity, but there is <strong>no hard foreign-key constraint</strong> between map and workflow \u2014 their lifecycles are decoupled (definitions immutable, maps versioned independently). References are <strong>validated on save</strong> (advisory): publishing a definition checks that every place it references resolves to a real place in the target map version, and rejects on a stale <code>from</code> version. If a <em>later</em> map update removes a place a running instance uses, that is handled by the exception principle (\u00a78), not by a constraint that would couple the two lifecycles. (The deeper authoring-agent issue \u2014 the agent omitting map tags so edits don't round-trip, HECO-3376 \u2014 is out of scope here and owned by the forthcoming Studio workflow-editing spec.)</p><p><strong>Versioning a definition migrates its instances.</strong> Publishing a new version does not silently change anything running. Each live instance migrates <em>explicitly</em>: its markings move from the old version's places to the new version's places, a recorded action, not an automatic rewrite. The migration is a <strong>place mapping</strong> (old \u2192 new) produced by the same authoring agent that edits the definition, which validates and symbolically simulates the result before proposing it. Migration is advisory: inference proposes, a human approves, the version is published. Switchboard's role is narrow and mechanical \u2014 it <em>applies</em> the agent-supplied mapping transactionally to the strong markings and records it. <strong>Unmapped tokens quarantine, they don't vanish</strong> (<code>__quarantine__</code>).</p><p><strong>In-flight leases during migration.</strong> Default is <strong>drain</strong>: stop admitting new transitions, let in-flight leased tasks finish (or expire), then rewrite markings in one transaction and bump <code>definition_version</code>. An operator may <strong>force</strong> migration, which reclaims outstanding leases (via the same transactional <code>release \u2192 reacquire</code> primitive used for intervention, \u00a710) and quarantines any token whose task was interrupted. Migration rewrites markings only \u2014 <strong>facts are untouched</strong> (subject/map-scoped, not instance-scoped) and re-project against the new places.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-10.Consistency:StrongCore,RelaxedReplica\u2014SerializeDispatch,RecordReality\">10. Consistency: Strong Core, Relaxed Replica \u2014 Serialize Dispatch, Record Reality</h2><p>Two stores, two contracts. The <strong>coordination core \u2014 markings and leases \u2014 is strongly consistent</strong>, the authoritative transactional store. The <strong>fact replica \u2014 pose, power, places, everything from robots and maps \u2014 is relaxed</strong>, eventually consistent, bounded only by TTL and epoch.</p><p>The safety model splits cleanly into two concerns that are often both called &quot;illegal,&quot; and separating them is the whole trick:</p><p><strong>1. Exclusivity (leases) \u2014 strict, always. Leases </strong><em><strong>serialize dispatch</strong></em><strong>.</strong> The only hard safety property is that Switchboard must never <em>offer/hand out</em> the same exclusive claim to two agents. A lease serializes dispatch: one agent wins it, the other is not offered the conflicting work. This never relaxes. Note the precise claim \u2014 leases prevent Switchboard from <strong>dispatching</strong> conflicting work; they cannot and should not prevent a robot from doing something physical out-of-band and reporting it.</p><p><strong>2. Conformance \u2014 advisory and loud.</strong> Switchboard is a schematic approximation; the robot knows reality. A robot may claim a transition that does not conform to the current net (wrong place, structural deviation). Switchboard <strong>accepts it, records it, moves the token (possibly to</strong> <code>__illegal__</code>/<code>__quarantine__</code>), and is loud about it \u2014 it does not silently reject reality. If the robot physically did the thing, refusing to log it only makes Switchboard lie. Two robots that somehow both grabbed the same tote is a real-world event that <em>already happened</em>; recording both loudly is more honest than pretending one didn't. Conformance becomes a metric computed over the event log (Coordinator-spec stance), not a gate.</p><p><strong>Deviation is gated by capability.</strong> <em>Who</em> may fire a non-conforming transition is an authz decision (\u00a7B):</p><ul><li><p><code>robot-exec</code> may deviate on <strong>its own</strong> subject (it knows reality).</p></li><li><p><strong>operators</strong> may intervene and force-resolve.</p></li><li><p><strong>adapters</strong> (SAP/SynaOS) may <strong>not</strong> deviate \u2014 they only fire their permitted source transitions.</p></li></ul><p><strong>Intervention primitive: transactional</strong> <code>release \u2192 reacquire</code>. Handing a stuck robot's leased task to another agent (or a teleoperator), or reclaiming a lease during forced migration, is a single atomic reassignment \u2014 release the held lease and reacquire it under the new holder in one transaction \u2014 not an ad-hoc hack.</p><p><strong>Marking intervention and reset.</strong> Operators may also edit an instance marking directly when recovering from a mismatch between reality and the net: move a token to another valid place, remove a token, reset an instance's marking from an explicit seed, or retire the instance and start a replacement. These are operator-only interventions, authorized by policy, validated against the compiled workflow when possible, and recorded as events. Normal restarts should prefer &quot;start a new instance and retire the old one&quot;; reset exists for the prototype-style recovery/debug path where preserving the same instance identity is useful.</p><p>Guard evaluation runs in two phases:</p><ul><li><p><strong>Eligibility (relaxed, fast).</strong> Compute which transitions <em>could</em> fire from the instance's projected facts (\u00a77), freshness applied (stale / wrong-epoch / wrong-map facts fail closed). A read against a relaxed view; may lag.</p></li><li><p><strong>Commit (strong, transactional).</strong> A <strong>claim</strong> fires the claimed transition: re-read the marking, check the definition's <strong>place capacity</strong>, compare-and-set on <code>marking.version</code> (optimistic concurrency \u2014 a failed CAS is a <em>retry</em>, not a rejection of intent), acquire/clear/serialize the <strong>lease</strong>, write the event, update the marking \u2014 all in one transaction. Claims are <strong>idempotent</strong> by claim id, so a retried <code>/work</code> over flaky WiFi does not double-fire. A relaxed read can only cause a transition to be <em>offered</em> that then fails its strong dispatch check; it can never cause two agents to be dispatched the same exclusive work.</p></li></ul><p><strong>Per-instance guard cache.</strong> The coordinator already loads a marking and definition per instance to compute Petri updates; extend that working set with the instance's projected facts. Markings stay authoritative (read strongly at commit); projected facts are the relaxed, cached part serving <strong>eligibility only</strong>, so cache lag is never a correctness risk. The strong core shards by token/subject, so independent transitions don't contend.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-11.Pose,Frames,andFreshness\">11. Pose, Frames, and Freshness</h2><p>Poses are reasoned about in the ROS2 <code>map</code> frame \u2014 globally consistent (it jumps on localization corrections but does not drift), unlike smooth-but-drifting <code>odom</code>. <strong>Frame identity is</strong> <code>(frame, map_id)</code> and it is a correctness constraint: two poses are only comparable within the same map version, and Schaeffler will re-record maps (<code>update_map</code> is planned, and SynaOS supplies its own LIF map), so distance/zone guards must require matching <code>(frame, map_id)</code> and fail closed otherwise.</p><p>Every fact carries <code>observed_at</code> (sensor time \u2014 what guards compare against), <code>written_at</code>, <code>expires_at</code>/TTL, <code>epoch</code>, and <code>source</code>. Stale facts remain stored but stop satisfying guards. <strong>Epoch</strong> invalidates cleanly across lifecycle changes: on reconnect a robot bumps its epoch and prior-epoch facts stop counting as fresh even inside their TTL \u2014 so a robot that blinked out can't have its old pose silently satisfy a guard. Epoch also bumps as a tote's token crosses pick/place transitions (\u00a76), which is what makes a stale carried derivation die at the carrier's epoch.</p><p><strong>Clock skew.</strong> <code>observed_at</code> is the source's sensor time, and robot/server clocks drift; we have already seen <code>tf</code> extrapolation errors and <code>use_sim_time</code> leakage produce nonsensical timestamps. The server treats <code>observed_at</code> as advisory for ordering but enforces freshness against its own clock at write by clamping timestamps too far in the future, and requires <code>observed_at</code> to be monotonic per <code>(subject, epoch)</code>. Guards fail closed on stale, wrong-epoch, wrong-map, or implausibly-timestamped facts.</p><blockquote><p><strong>External precondition \u2014 reverb localization cache.</strong> Switchboard's freshness guarantees assume that nothing <em>else</em> resurrects stale truth behind its back. Today reverb persists pose to on-disk caches (<code>~/.cache/reverb_localization_cache.json</code>, <code>/tmp/localization_last_pose.yaml</code>) and republishes a setpose every ~2s, overriding manual init \u2014 which can revive a stale pose across a reboot, exactly the zombie this model is meant to kill. <strong>The reverb localization cache must be removed, or made epoch-aware (a cached pose carries its epoch and is invalidated by a bump), before the epoch/TTL guarantees here hold in practice.</strong> This is a reverb-side dependency, not solved by Switchboard alone; G.9 is its acceptance test.</p></blockquote><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-12.RobotLifecycle:Enroll,Deploy,Poll,Assign,Work\">12. Robot Lifecycle: Enroll, Deploy, Poll, Assign, Work</h2><p>A robot's durable relationship is to the <strong>fleet</strong>, not a workflow. It enrolls once, then <em>polls</em> for site and workflow assignment.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"b4f40a5c-89b0-45c0-8c58-fe91d81b5823\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">enrolled (fleet member, Backbone-rooted, holds fleet cert)\n   \u2502  poll deployment\n   \u25bc\nunassigned / idle        \u2500\u2500 no workflow; resource facts still replicated at fleet scope\n   \u2502  deployed to a site (gains active map(s))\n   \u25bc\nlocalizing               \u2500\u2500 pulls site map; visual + lidar localization\n   \u2502  localization.current fresh AND score \u2265 threshold AND map_id matches\n   \u25bc\nlocalized                \u2500\u2500 eligible for work\n   \u2502  assigned to a workflow (assignment join; robot polls and pulls map+workflow)\n   \u25bc\nworking                  \u2500\u2500 runs the acquire-work loop</pre>\n</div></div><p>Three fixes fall out. <strong>A robot cannot execute transitions while delocalized</strong> \u2014 eligibility is gated on a <code>localization.current</code> fact (fresh, above threshold, for the active map), <strong>written by reverb as the self-bound</strong> <code>robot-exec</code> (the localization node <em>computes</em> confidence; reverb <em>publishes</em> the fact, same machinery as pose/power). The <code>localizing</code>-stuck case becomes an enrolled-but-idle robot, not a phantom participant. <strong>Enrollment is decoupled from tasking</strong> \u2014 a robot joins the fleet via its device cert; only then is it deployed and assigned. <strong>Assignment is poll-discovered, never pushed.</strong></p><p><strong>The work loop is robot-initiated and idempotent.</strong> Robots poll <code>POST /work</code> (outbound only \u2014 zero inbound to robots, which suits site NAT/firewalls), carrying facts, lease refreshes, and claims. Fact writes are latest-wins per <code>(subject, key)</code>; lease refreshes are idempotent by <code>lease_id</code>; claims are idempotent by claim id. The loop is safe to retry through the WiFi saturation and AP flaps seen on site (pings &gt;300 ms, &quot;bumping&quot; wifi). Switchboard stays dumb: it accepts registrations/assignments and answers &quot;what may I do.&quot;</p><p><strong>Bounded markings \u2014 sink places.</strong> Markings encode current state and must stay bounded. A place may be flagged a <strong>sink</strong>; tokens that land in a sink expire and are <strong>reaped</strong> from the marking table after a TTL, and transient subjects (<code>work</code>, <code>load</code>) are reaped with their tokens. Durable subjects (<code>robot</code>, <code>place</code>, <code>scope</code>) persist. History is <strong>not</strong> kept in the live marking \u2014 the append-only <strong>event log is the forever-history</strong> and ships to the OLAP/ClickHouse path (Appendix D) for audit and analytics. Schaeffler order history lives in the event log, not in the hot tables. (The prototype does this in-memory; the SQL translation is a periodic reap job / TTL on sink-resident tokens.)</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-13.MVP&amp;ImplementationShape\">13. MVP &amp; Implementation Shape</h2><p>The MVP is a <strong>single Rust service</strong> (Tokio, axum) over a <strong>single PostgreSQL</strong> (<code>sqlx</code>) for deployed stacks, while the standalone development binary can run against an in-memory store for rapid iteration. Local full-stack testing uses k3s/k3d so the runtime shape matches the EKS deployment path. <strong>HTTP/JSON is the main API</strong> \u2014 for the work loop too \u2014 because third parties (SAP, SynaOS adapters, operator UIs) integrate far more easily without being handed gRPC protos, and it caches/load-balances cleanly. JSON on the hot path is a deliberate <em>simplicity</em> bet, not a performance one (if JSON serialization is what brings a robot down, we have much bigger problems); a binary/gRPC framing for the work loop specifically is a possible later, internal-only optimization, never the partner-facing surface.</p><p>MVP scope: the single-<code>fact</code>-table schema (\u00a7A.1), no PostGIS and no per-type tables, pose math in the service; <strong>app-side UUIDv7</strong>; one Postgres primary, no sharding, fleet-as-RLS for isolation; the strong commit path (capacity + <code>marking.version</code> CAS + lease) in one transaction; sink-place reaping; the three actions (enroll/deploy/assign) and idempotent <code>/work</code>. <strong>Identity is static</strong> (\u00a7B): mTLS robots, a Cognito user pool with static scoped groups (HMND cross-site roles; customer fleet-scoped roles assigned in-app), service-account tokens for adapters \u2014 no customer-IdP federation yet. The same service is <code>k8s</code>-deployable for the cloud single-pane-of-glass and for a future site-authoritative deployment; the typed/PostGIS evolution (\u00a7A.2), read replicas, the per-instance guard cache, customer-IdP federation, and the full VDA5050 layer come only when measured or contractually required.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-14.Doctrine\">14. Doctrine</h2><p>Subjects persist; a physical thing has one durable identity. Markings coordinate and are bounded; sink places reap. Facts replicate. Static truth is the map's; dynamic object location is the robot's perception. Coordination is strongly consistent; the fact replica is relaxed. <strong>Leases serialize dispatch; facts inform; the robot knows reality.</strong> Conformance is advisory and loud, not a gate; deviation is gated by capability. Definitions are versioned and immutable; instances migrate explicitly; map\u2194workflow references are soft. Exceptions degrade-and-flag, never hard-stop. Events preserve history; the OLAP log is the forever-record. TTL and epochs prevent zombie truth. Identity is global; authorization is local and, for now, static \u2014 federation is designed-for and deferred. Config authority is central; coordination authority is wherever the robots physically are; authority <em>placement</em> is the Outpost spec's call, and this model accommodates either. At the System-3 boundary, integration is zoned: we obey a partner's traffic authority only inside the regions it owns. Integrations bridge at the System-3 boundary, never into the robot. The coordination plane stays dumb and the registry is data, not schema.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-15.Milestones\">15. Milestones</h2><ul><li><p><strong>S0</strong> \u2014 single Rust/Tokio service + Postgres in k3s/EKS, plus a standalone in-memory binary for rapid iteration; registry tables; <strong>enroll/deploy/assign</strong> with the <code>assignment</code> join; single <code>fact</code> table (\u00a7A.1); app-side UUIDv7; definition (Starlark-evaluated, Appendix I) / instance / marking / lease; sink-place reaping; fleet-as-RLS; static Cognito groups; idempotent <code>/work</code>.</p></li><li><p><strong>S1</strong> \u2014 three query lenses; strong-commit / relaxed-eligibility guard path with <strong>serialize-dispatch / conformance-advisory</strong> semantics; <code>(frame, map_id)</code> identity; operator map view; the exception table (\u00a78) wired to operator flags.</p></li><li><p><strong>S2</strong> \u2014 robot lifecycle (enroll \u2192 deploy \u2192 poll \u2192 localize-gate \u2192 assign \u2192 work); <code>localization.current</code> written by reverb (reverb cache precondition resolved); epoch invalidation; carried-tote mode/snapshot + <code>carried \u2192 dropped</code>; map-version + workflow-place layering; instance migration with quarantine; transactional <code>release \u2192 reacquire</code> intervention.</p></li><li><p><strong>S3</strong> \u2014 SAP source adapter (Appendix E.1); SynaOS coexistence floor \u2192 mid (occupancy facts \u2192 virtual-fleet broadcast, Appendix E.2); typed snapshot evolution where measured (\u00a7A.2); per-instance materialized guard cache; site-authoritative placement with the Outpost spec; customer-IdP federation when contractually required.</p></li></ul><hr/><h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-AppendixA\u2014StorageModel\">Appendix A \u2014 Storage Model</h1><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-A.1Startsimple:onefacttable\">A.1 Start simple: one fact table</h2><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"3c87830b-699c-443f-9e7b-c93a63306e35\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: sql; gutter: false; theme: Confluence\" data-theme=\"Confluence\">-- Registry (config; mostly static; scopes use human slugs)\ncreate table tenant   ( id text primary key, name text not null );\ncreate table fleet    ( id text primary key, tenant_id text not null references tenant, name text not null );\ncreate table site     ( id text primary key, tenant_id text not null references tenant, name text not null );\ncreate table map      ( id text primary key, site_id text not null references site, version int not null,\n                        assets_uri text, recorded_by text, unique (site_id, version) ); -- many maps per site; rasters in object store\ncreate table workflow ( id text primary key, map_id text not null references map,\n                        version int not null,\n                        source_starlark text not null,         -- authored source (Appendix I)\n                        definition jsonb not null,             -- canonical net (IR) evaluated from source\n                        canonical_hash text not null,\n                        unique (id, version) );                -- immutable per version\n\ncreate table deployment ( id text primary key, fleet_id text not null references fleet,\n                          site_id text not null references site, active_map_id text references map,\n                          status text not null default 'active' );  -- one site per fleet deployment; multiple maps allowed\n\n-- Robots are fleet resources; device_ref points outward to Backbone\ncreate table robot ( id uuid primary key, fleet_id text not null references fleet,\n                     device_ref text not null, label text, role text not null );\n\n-- NEW: robot -&gt; workflow assignment (the third action; poll-discovered, never pushed)\ncreate table assignment ( id uuid primary key, fleet_id text not null,\n                          robot_id uuid not null references robot(id),\n                          workflow_id text not null references workflow(id),\n                          instance_id uuid,                    -- the running instance, once instantiated\n                          status text not null default 'active',\n                          assigned_by text not null, assigned_at timestamptz default now(),\n                          unique (robot_id) where status = 'active' );  -- a robot runs one active assignment at a time\n\n-- A running instantiation of a definition version on a map (holds the strong markings)\ncreate table instance ( id uuid primary key, fleet_id text not null,\n                        workflow_id text not null references workflow(id), definition_version int not null,\n                        map_id text not null references map(id), deployment_id text references deployment(id),\n                        status text not null default 'active', created_at timestamptz default now() );\n\n-- Subjects: app-side uuidv7 identity, kind + label + external_ref; one durable identity per physical thing\ncreate table subject (\n  id           uuid primary key,      -- uuidv7, generated app-side (plain uuid column)\n  fleet_id     text not null,\n  kind         text not null,         -- resource | load | place | work | scope\n  label        text,                  -- human name ('r12'); mutable, not identity\n  external_ref text,                  -- customer/protocol id (AGV serial, SAP order, barcode)\n  status       text not null default 'active',   -- active | terminal (left the building / fulfilled)\n  epoch        int not null default 0 );\ncreate index on subject (fleet_id, kind) where status = 'active';\ncreate index on subject (fleet_id, external_ref);   -- integration lookup\n\n-- Replicated facts: ONE table, JSONB bodies, RELAXED. SoT at robot self-telemetry / robot perception / map.\ncreate table fact (\n  fleet_id    text not null,\n  subject_id  uuid not null references subject(id),\n  key         text not null,          -- 'pose.current', 'power.current', 'localization.current', 'carried_by', 'tag', 'occupancy', ...\n  value       jsonb not null,\n  mode        text,                   -- locatable facts: 'absolute' | 'relative' (relative = derived from carrier, \u00a76)\n  source      text not null,          -- writing executor: 'robot:r12' | 'map:herzo@v17' | 'operator' | 'sap-adapter'\n  observed_at timestamptz not null,\n  written_at  timestamptz not null default now(),\n  expires_at  timestamptz,            -- null = non-perishable (map-sourced static, or collapsed absolute snapshot)\n  epoch       int not null default 0,\n  map_id      text,                   -- set on locatable facts; carries frame identity\n  primary key (fleet_id, subject_id, key) );\ncreate index on fact (fleet_id, key);\ncreate index on fact (fleet_id, map_id) where map_id is not null;\n\n-- Switchboard-authoritative coordination state: STRONG. Bounded: sink-resident tokens are reaped (\u00a712).\ncreate table marking (\n  fleet_id text not null, instance_id uuid not null references instance(id), subject_id uuid not null,\n  net text not null, place text not null,    -- place may be '__quarantine__' / '__illegal__' / a sink place\n  token_type text, payload jsonb not null default '{}',\n  version bigint not null,            -- optimistic concurrency (CAS at commit)\n  entered_at timestamptz default now(),       -- for sink-place TTL reaping\n  primary key (instance_id, subject_id, net) );\n\ncreate table lease (\n  fleet_id text not null, instance_id uuid not null references instance(id), lease_id uuid primary key,\n  subject_id uuid not null, task text not null, holder text not null,\n  acquired_at timestamptz not null default now(), expires_at timestamptz not null );\n\n-- Places may be sinks; sink-resident tokens reap after ttl (def can also be derived from the IR)\ncreate table place_meta (\n  map_id text not null, place text not null, is_sink boolean not null default false,\n  sink_ttl interval, capacity int, primary key (map_id, place) );\n\n-- History (transitions + migrations; NOT high-frequency facts \u2014 see Appendix D). Ships to OLAP = forever-history.\ncreate table event (\n  fleet_id text not null, event_id bigserial primary key, instance_id uuid not null,\n  transition text,                    -- a workflow transition, '__migrate__', or a recorded deviation\n  conformant boolean not null default true,   -- false = recorded illegal/deviation (loud), \u00a710\n  subject_id uuid, claim_id uuid, old_value jsonb, new_value jsonb,\n  actor text, source text, observed_at timestamptz, written_at timestamptz default now(),\n  trace_id text );\ncreate unique index on event (instance_id, claim_id) where claim_id is not null;  -- claim idempotency</pre>\n</div></div><p>The three lenses over this:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"f9856505-4a6c-4ff2-b018-1530ef492a28\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: sql; gutter: false; theme: Confluence\" data-theme=\"Confluence\">create view fact_fresh as       -- freshness applied once (relaxed read)\n  select f.* from fact f join subject s on s.id = f.subject_id\n  where (f.expires_at is null or f.expires_at &gt; now()) and f.epoch = s.epoch and s.status = 'active';\n\nselect * from fact_fresh f join subject s on s.id=f.subject_id where f.fleet_id=:f and s.kind='resource'; -- fleet lens\nselect * from fact_fresh where fleet_id=:f and map_id=:m and key='pose.current';                          -- map lens\n-- workflow lens: marking for the instance \u2295 projected facts for its subjects</pre>\n</div></div><p>Pose is JSONB (<code>value-&gt;&gt;'x'</code>); spatial math is in the service. A migration is one transaction over <code>marking</code> (rewrite <code>place</code> per the agent's mapping, unmapped \u2192 <code>__quarantine__</code>, bump <code>instance.definition_version</code>) plus a <code>__migrate__</code> event. A reap job deletes sink-resident tokens past <code>sink_ttl</code> and marks their transient subjects <code>terminal</code>. This schema carries the pilot.</p><blockquote><p><strong>Versioning note.</strong> Three counters could exist \u2014 map <code>version</code>, fact <code>epoch</code>, and the v0 <code>tag_set_version</code>. This revision drops <code>tag_set_version</code>: tag/place currency is fully captured by the map <code>version</code> (tags are map-sourced place facts, invalidated on map-version bump) and per-fact <code>epoch</code> (lifecycle/reconnect). A separate tag-set counter is redundant.</p></blockquote><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-A.2Evolve:typedsnapshotsandPostGIS(whenmeasured)\">A.2 Evolve: typed snapshots and PostGIS (when measured)</h2><p>The read interface (<code>fact</code> / <code>fact_fresh</code>) is invariant to where a fact physically lives, so a fact graduates <code>arbitrary \u2192 registered (schema + TTL) \u2192 promoted built-in</code> without breaking consumers. Promotion moves a hot/spatial fact family into a <strong>typed snapshot table</strong> clustered by co-write group:</p><ul><li><p><code>pose_current</code> \u2014 kinematic snapshot, <code>geometry(PointZ, 0)</code> (SRID 0 = local Cartesian meters), GiST on the many static places (not the few hot robots), frame columns, <code>mode</code> for absolute/relative; attached-pose composition in the client.</p></li><li><p><code>device_current</code> \u2014 telemetry snapshot (battery/power/health) as columns; a new scalar built-in is <code>ADD COLUMN</code>, not a new table.</p></li><li><p><code>link_carried_by</code> \u2014 promote links from facts to a typed table with FK integrity (<code>carrier_id references subject</code>).</p></li></ul><p>Each promoted table gets a <code>UNION ALL</code> arm in the <code>fact</code>/<code>fact_fresh</code> view, so the lens query count doesn't grow with built-ins. <strong>Do not promote until the generic table is a measured bottleneck.</strong></p><hr/><h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-AppendixB\u2014AuthorizationModel\">Appendix B \u2014 Authorization Model</h1><p>Identity is established at the door (Appendix H) and reduced to a <strong>principal</strong>. Everything past that is one model with four enforcement tiers, with a Cedar policy engine for the fine-grained tier. <strong>For MVP the model is static</strong> \u2014 no customer-IdP federation, no claim mapping; the scoped-group/containment structure below is the seam that lets federation drop in later (~2027, EU posture) without reshaping anything.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-B.1Fourenforcementtiers\">B.1 Four enforcement tiers</h2><ol start=\"1\"><li><p><strong>Authn (ALB).</strong> Robots by mTLS, humans by OIDC (Cognito), adapters by a service-account token (Appendix H).</p></li><li><p><strong>Isolation (Postgres RLS) \u2014 the hard fleet wall.</strong> The principal's fleet is a session GUC; every table carries <code>fleet_id</code>; even a policy bug cannot cross fleets.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"7b5a9623-7df9-4f8f-9148-72177d50142d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: sql; gutter: false; theme: Confluence\" data-theme=\"Confluence\">select set_config('app.fleet', 'fleet:herzogenaurach', false);\nalter table fact enable row level security;\ncreate policy fleet_isolation on fact\n  using (fleet_id = current_setting('app.fleet', true))\n  with check (fleet_id = current_setting('app.fleet', true));</pre>\n</div></div></li><li><p><strong>Capability (Cedar) \u2014 the policy brain.</strong> Fine-grained <code>permit</code>/<code>forbid</code> over <code>(principal, action, resource, context)</code>, evaluated per route.</p></li><li><p><strong>Integrity (commit).</strong> Capacity / lease-serialize / <code>marking.version</code> CAS at strong commit (\u00a710).</p></li></ol><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-B.2Principalsandstaticgroups\">B.2 Principals and static groups</h2><p>Three principal types, each built at the door: <strong>Robot</strong> (mTLS SVID), <strong>User</strong> (OIDC token), <strong>Service</strong> (adapter tokens).</p><p>Groups are <strong>static</strong> and scoped, with a containment hierarchy:</p><ul><li><p><strong>HMND users</strong> get cross-site roles: <code>admin</code>, <code>teleoperator</code>, <code>operator</code> (members of HMND-tenant groups).</p></li><li><p><strong>Customer users</strong> get fleet-scoped roles: <code>fleet-admin</code>, <code>fleet-operator</code>, assigned in-app by someone with the right.</p></li></ul><p>Cedar's entity hierarchy gives transitivity on two axes:</p><ul><li><p><strong>Group membership</strong> (<code>principal in Group</code>): a robot's <code>role</code> bundles capabilities; user groups nest (<code>fleet-operator@herzo in fleet-admin@herzo</code>). Membership is <strong>directly assigned</strong> (<code>group_membership</code>), not derived from external claims (federation deferred).</p></li><li><p><strong>Resource containment</strong> (<code>resource in Scope</code>): <code>Subject in Fleet in Tenant</code>; <code>Instance in Workflow in Map in Site in Tenant</code>; <code>Fact in Subject</code>; <code>Lease in Instance</code>. A policy at <code>Fleet</code>/<code>Tenant</code> transitively covers everything beneath.</p></li></ul><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-B.3Resourcesandactions\">B.3 Resources and actions</h2><p><strong>Resources:</strong> <code>Tenant</code>, <code>Fleet</code>, <code>Site</code>, <code>Map</code>, <code>Workflow</code>, <code>Deployment</code>, <code>Assignment</code>, <code>Instance</code>, <code>Subject</code>, <code>Fact</code>, <code>Lease</code>.</p><p><strong>Actions:</strong> <code>Enroll</code>, <code>Deploy</code>, <code>Assign</code>, <code>PollDeployment</code>, <code>WriteFact</code>, <code>FireTransition</code>, <code>Deviate</code>, <code>AcquireLease</code>, <code>Claim</code>, <code>Intervene</code>, <code>InjectWork</code>, <code>PublishDefinition</code>, <code>Migrate</code>, <code>AddPlace</code>, <code>ReadFleet</code>, <code>ReadMap</code>, <code>ReadInstance</code>, and <code>Admin*</code>. <code>Deviate</code> (fire a non-conforming transition, \u00a710) and <code>Intervene</code> (transactional release\u2192reacquire) are distinct, capability-gated actions.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-B.4Policies(Cedar)\">B.4 Policies (Cedar)</h2><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"faf32402-7790-4efb-a348-4a21300e279a\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">// A robot acts only on its own subject, within its fleet \u2014 including deviation\npermit (principal, action in\n  [Action::&quot;WriteFact&quot;, Action::&quot;FireTransition&quot;, Action::&quot;Deviate&quot;, Action::&quot;AcquireLease&quot;, Action::&quot;Claim&quot;], resource)\nwhen { resource in principal.fleet &amp;&amp; context.subject == principal.subject };\n\n// Operators: fleet-scoped operator actions + intervention (release-&gt;reacquire)\npermit (principal in Group::&quot;operators&quot;, action in [Action::&quot;OperatorActions&quot;, Action::&quot;Intervene&quot;], resource)\nwhen { resource in principal.fleet };\n\n// Adapters may inject work / read status \u2014 and may NOT deviate (hard cap via forbid)\npermit (principal == Service::&quot;sap-adapter&quot;,\n        action in [Action::&quot;InjectWork&quot;, Action::&quot;ReadInstance&quot;], resource);\nforbid (principal == Service::&quot;sap-adapter&quot;, action, resource)\nunless { action in [Action::&quot;InjectWork&quot;, Action::&quot;ReadInstance&quot;] };</pre>\n</div></div><p>The subject-binding condition (<code>context.subject == principal.subject</code>) keeps a robot from writing or deviating on another robot's subject \u2014 the same intent hand-namespacing (<code>robot1/foo</code>) approximated, now enforced.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-B.5Audit\">B.5 Audit</h2><p>Two correlated, append-only logs (a regulated customer like Schaeffler expects this):</p><ul><li><p><strong>Authz decision log.</strong> Every Cedar decision: principal, action, resource, context, allow/deny, determining policy ids, timestamp, <code>trace_id</code>. <em>Who was permitted to do what.</em></p></li><li><p><strong>Domain event log</strong> (<code>event</code>). <code>actor</code>/<code>source</code>/<code>claim_id</code>/<code>conformant</code>/<code>trace_id</code> on every transition (conformant or recorded-deviation) and migration. <em>What actually changed, and by whom.</em></p></li></ul><p>Correlate by <code>trace_id</code>. Both are high-volume on the hot path (every <code>/work</code> authorizes) and therefore ship to the <strong>OLAP path</strong>, not the OLTP store. RLS bounds reads to the fleet.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-B.6Executorsandfact-writeauthorization\">B.6 Executors and fact-write authorization</h2><p>A workflow definition names an <strong>executor</strong> on every <code>work_type</code> and task \u2014 the actor that owns a token class and is bound to the transitions it may fire. Executors are not robot-only: a robot is <code>robot-exec</code>, a WMS is <code>wms-exec</code>, an operator console <code>operator-exec</code>, a button/PLC <code>button-exec</code>. The executor maps onto a Cedar principal; the subject-binding policy (B.4) holds a <code>robot-exec</code> to its own token. External executors carry no token \u2014 they drive a transition by writing a guarding fact or claiming completion. This is the System-3 boundary expressed as authorization rather than a special case.</p><p>Because facts are keyed by <code>(subject, key)</code>, the writer is not part of the key \u2014 so <strong>fact-write authority must be declared, not inferred</strong>. Per fact key (or prefix), the definition states which executor(s) may assert it about which subject kinds:</p><ul><li><p><code>robot-exec</code> writes its own <code>pose</code>, <code>power</code>, <code>localization.current</code> (self-bound; the localization node computes, reverb publishes), and its own perceived <code>load</code> locations (dynamic object location is the robot's, \u00a76).</p></li><li><p>the <strong>map version</strong> writes static place facts (tags, zones).</p></li><li><p>an <strong>operator</strong> writes overrides.</p></li></ul><p>The writing executor is recorded as the fact's <code>source</code>. Within the authorized set, last-write-wins by <code>written_at</code>; two <em>different</em> executors contending for the same <code>(subject, key)</code> is a definition smell to catch at validation, not a runtime race \u2014 facts inform, they never enforce.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-B.7Usersandgroups(static;federationdeferred)\">B.7 Users and groups (static; federation deferred)</h2><p>Authentication and authorization stay split. <strong>Cognito is the identity provider</strong> \u2014 the Backbone-owned pool that holds human credentials and emits the OIDC token; <strong>Switchboard never stores a credential.</strong> It stores the authorization projection: its own scoped Cedar groups, the containment graph, direct group memberships, and a thin user record for audit.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"cec38a8b-6ee3-408e-a1b2-bf223ea03c87\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: sql; gutter: false; theme: Confluence\" data-theme=\"Confluence\">create table app_group (\n  id         text primary key,           -- slug: 'fleet-operator@herzo' or 'operator' (HMND cross-site)\n  tenant_id  text not null references tenant,\n  scope_kind text not null,              -- 'tenant' | 'fleet' | 'site'\n  scope_id   text not null,\n  name       text not null,\n  unique (tenant_id, name) );\n\ncreate table group_parent (              -- containment edges (Cedar parents); no cross-tenant nesting\n  child_id text not null references app_group(id),\n  parent_id text not null references app_group(id),\n  primary key (child_id, parent_id) );\n\ncreate table app_user (                  -- one row per Cognito subject, for audit + direct grants\n  id uuid primary key,                   -- uuidv7\n  tenant_id text not null references tenant,\n  idp_sub text not null unique,          -- Cognito 'sub'\n  email text, display_name text,\n  is_internal boolean not null default false,   -- HMND staff vs customer user\n  status text not null default 'active' );\n\ncreate table group_membership (          -- DIRECT, in-app assignment (no claim mapping at MVP)\n  user_id uuid not null references app_user(id),\n  group_id text not null references app_group(id),\n  granted_by text not null, granted_at timestamptz not null default now(),\n  primary key (user_id, group_id) );</pre>\n</div></div><blockquote><p><strong>Deferred \u2014 customer-IdP federation (~2027).</strong> Brokered federation (customer SAML/OIDC \u2192 Cognito external provider, per-tenant), claim\u2192group mapping, and SCIM deprovision are <strong>designed-for but not built</strong>. The scoped-group + containment structure above is precisely what lets them drop in: a future <code>idp_provider</code> + <code>idp_group_mapping</code> resolve external claims onto these same scoped groups at request time, structurally tenant-bound (an IdP can only map onto groups in its own tenant). EU security posture makes this likely next year; it is out of MVP scope. Until then, all membership is direct in-app assignment, and HMND staff authenticate against our own pool (break-glass independent of any customer SSO).</p></blockquote><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-B.8Identityadminsurface(staticMVP)\">B.8 Identity admin surface (static MVP)</h2><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"8c23e7c3-d187-40fe-9f63-f36da57a0758\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">GET    /v1/admin/users                       # list users in the caller's tenant (status, groups)\nPATCH  /v1/admin/users/$id                    # enable / disable\nGET    /v1/admin/groups\nPOST   /v1/admin/groups/$g/members            # direct grant a user into a group\nDELETE /v1/admin/groups/$g/members/$user      # revoke\nPOST   /v1/admin/robots/$r/role               # robot capability group</pre>\n</div></div><p>Two admin tiers from one hierarchy: <strong>tenant admins</strong> (a customer's own, or our deployment engineers acting within that tenant) manage direct grants inside their tenant; <strong>HMND super-admins</strong> authenticate against our pool, administer the <code>hmnd</code> tenant, and are the only principals who may cross tenants. Every call writes both audit logs. The federation/IdP-broker endpoints arrive with the deferred work in B.7.</p><blockquote><p>Refines the Coordinator spec's &quot;tenant = RLS&quot; to <strong>fleet = RLS</strong> (a tenant may own several fleets); the capability tier is Cedar. Site is not in the identity path, so redeployment doesn't reissue certs. SPIFFE segments use scope slugs and the robot label; the internal id is the app-side uuidv7.</p></blockquote><hr/><h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-AppendixC\u2014APIResourcesandActions\">Appendix C \u2014 API Resources and Actions</h1><p>HTTP/JSON (cacheable, easy third-party integration; main API including the hot path). Fleet always from the SVID, never the path.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"a8accebb-9c53-477c-9634-0adb9d4eb6dd\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\"># Registry (cloud-authoritative config)\nPOST /v1/fleets   POST /v1/sites   POST /v1/maps   POST /v1/workflows\nPUT  /v1/workflows/$id?from=$ver            # publish a new definition version (Starlark source; evaluated to IR + validated vs map places, Appendix I)\nGET  /v1/deployment                         # what the robot polls (site, active map, assigned instance)\n\n# The three actions\nPOST /v1/fleets/$f/enrollments              # ENROLL: mTLS = Backbone device SVID -&gt; fleet cert\nPOST /v1/robots/$r/deployments              # DEPLOY: robot -&gt; site\nPOST /v1/assignments                        # ASSIGN: executor/robot -&gt; running workflow instance (poll-discovered; never pushed)\nGET  /v1/robots/$r/assignment               # what the robot polls to learn its workflow + map\n\n# Instances, migration, intervention\nPOST /v1/instances                          # instantiate a definition version on a map\nPOST /v1/instances/$id/migrate              # apply agent-authored place mapping; quarantines unmapped\nPOST /v1/instances/$id/intervene            # transactional release -&gt; reacquire of a lease (operator)\n\n# Work loop (hot path) \u2014 facts + lease refreshes + claims; idempotent\nPOST /v1/instances/$id/work\n\n# Reads (the three lenses)\nGET  /v1/robots                             # fleet lens (resource facts; idle ok)\nGET  /v1/locatables?map=$m&amp;zone=$z&amp;fresh=true   # map lens (plotting)\nGET  /v1/instances/$id/state                # workflow lens (markings \u2295 projected facts)\n\n# Places (a workflow may add an operator-owned place; map places come from the map version)\nPOST /v1/workflows/$w/places</pre>\n</div></div><p><code>POST /work</code> body carries <code>facts</code> (routed to their home by registry, stamped with the subject's epoch and sensor <code>observed_at</code>; locatable facts carry <code>mode</code>), <code>leases</code> (refreshes, idempotent by <code>lease_id</code>), and <code>claims</code> (idempotent by <code>claim_id</code>; a claim may be a recorded deviation, \u00a710). Eligibility is computed from the relaxed projection; the claim commits strongly. Subjects are addressed by uuidv7, or resolved server-side from <code>(kind, external_ref)</code> for integrations.</p><hr/><h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-AppendixD\u2014RateLimitingandPerformance(withROM)\">Appendix D \u2014 Rate Limiting and Performance (with ROM)</h1><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p /></th><th class=\"confluenceTh\"><p>Pilot (Herzogenaurach)</p></th><th class=\"confluenceTh\"><p>Design envelope</p></th></tr><tr><td class=\"confluenceTd\"><p>Robots per fleet</p></td><td class=\"confluenceTd\"><p>~2\u20138</p></td><td class=\"confluenceTd\"><p>50\u2013200</p></td></tr><tr><td class=\"confluenceTd\"><p>Pose write</p></td><td class=\"confluenceTd\"><p>~10 Hz/robot</p></td><td class=\"confluenceTd\"><p>~10 Hz/robot</p></td></tr><tr><td class=\"confluenceTd\"><p>Telemetry write</p></td><td class=\"confluenceTd\"><p>~1 Hz/robot</p></td><td class=\"confluenceTd\"><p>~1 Hz/robot</p></td></tr><tr><td class=\"confluenceTd\"><p>Work-loop poll</p></td><td class=\"confluenceTd\"><p>~1\u20132 Hz/robot</p></td><td class=\"confluenceTd\"><p>~1\u20132 Hz/robot</p></td></tr><tr><td class=\"confluenceTd\"><p>Perceived-load writes</p></td><td class=\"confluenceTd\"><p>sporadic, per robot at a station</p></td><td class=\"confluenceTd\"><p>per robot; bounded by stations in view</p></td></tr></tbody></table></div><p>Per-robot \u2248 12\u201314 current-state upserts/sec plus sporadic perceived-load writes (each robot writes only loads <em>it</em> perceives \u2014 there is no single world-model fan-out bottleneck, \u00a76). Pilot (8 robots) \u2248 ~110/sec \u2014 trivial for one Postgres. Design (1,000 robots) \u2248 ~13k/sec, <strong>contention-free</strong> (each robot upserts only its own rows), partitioned by fleet; a single primary per region handles it.</p><p>Decisions that hold this: relaxed-fact writes don't contend (PK = subject); the strong core shards by token so independent fires don't contend; <strong>HF facts and both audit logs never enter the OLTP path \u2014 pose/telemetry history and Cedar decisions go to the OLAP/ClickHouse path</strong>; markings are bounded by sink-place reaping so the hot table doesn't grow with completed work; global reads go to a read replica; the map snapshot materializes at ~1 Hz; the per-instance guard cache absorbs eligibility reads off the hot store. Rate-limit <code>/work</code> per principal, coalesce fact writes latest-wins within a window, keep lease TTLs short.</p><p><strong>Latency (measured, office):</strong> robot\u2192local LAN \u2248 3 ms; robot\u2192local WiFi \u2248 25 ms; robot\u2192cloud London \u2248 33 ms; robot\u2192cloud US \u2248 88 ms. WiFi dominates; a UK-region cloud adds ~8 ms, so the work loop tolerates WAN \u2014 on-prem is an <em>availability</em> decision (Outpost spec / Appendix F), not a latency one. JSON serialization on this path is immaterial next to WiFi.</p><hr/><h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-AppendixE\u2014ExternalIntegration:SAP/WMSandSynaOS\">Appendix E \u2014 External Integration: SAP/WMS and SynaOS</h1><p>Integrations attach at the <strong>System-3 boundary as adapters</strong> \u2014 Switchboard is the seam, and robots never talk to SAP or SynaOS directly. Each adapter is a capability-bounded principal (Appendix B); adapters may <strong>not</strong> deviate (\u00a710). There are two, deliberately distinct.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-E.1SAP/WMS\u2014thebusinesstasksource(HMND-18)\">E.1 SAP / WMS \u2014 the business task source (HMND-18)</h2><p>SAP/WMS is where orders originate. The adapter is a System-3 principal authorized only to inject <code>work</code> and read status \u2014 the same shape as <code>mock-wms</code> in the <code>martur_fompak</code> stack. A SAP order becomes a <code>work</code> token via a source transition (claimed instantaneously, no lease), with the SAP order number on the subject's <code>external_ref</code>; fulfilment status is reported back from the marking and the OLAP event history. Robots fulfil the work without any knowledge of SAP.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-E.2SynaOS/AGVcoexistence\u2014azoned-authoritycontinuum(HMND-17)\">E.2 SynaOS / AGV coexistence \u2014 a zoned-authority continuum (HMND-17)</h2><p>Our robots share floor with Schaeffler's KUKA AGVs under SynaOS. The SoW commits us to <em>integrate</em>; SynaOS wants deep integration; the right engineering posture is a <strong>continuum</strong>, and <strong>authority is zoned, not global</strong>: SynaOS is the traffic authority <strong>only in the regions it owns</strong> (its transit aisles), and is <em>not</em> authoritative over our work cells. A <code>place</code>/<code>zone</code> therefore carries an <strong>authority-owner</strong> attribute, and a single mechanism spans the whole continuum \u2014 the only thing that changes between tiers is how much of the map SynaOS owns and how hard we work to align the two maps.</p><p><strong>The continuum (pilot targets the floor + a slice of mid):</strong></p><ul><li><p><strong>Floor \u2014 heuristic coexistence (pilot scope).</strong> Treat AGVs/AMRs as <strong>dynamic obstacles</strong>: announce presence, pull over, avoid. This is the same behavior we need for <em>all</em> dynamic obstacles (humans, manual trains), not just KUKA AGVs, and it is viable given the low AMR density at the pilot sites. The only Switchboard-side state this needs is <strong>node/zone occupancy facts</strong> \u2014 a robot broadcasts which zones it occupies so peers (ours and, where bridged, SynaOS) avoid deadlocks. This is the answer to the v0 open question &quot;does AWx need AWy's state to break deadlocks&quot;: yes, via occupancy facts served at the edge. <em>(This matches the 2026-06-05 pilot decision: heuristic coexistence, &quot;no full VDA 5050 integration,&quot; node-occupancy broadcasting, SynaOS mock against the LIF format.)</em></p></li><li><p><strong>Mid \u2014 &quot;virtual fleet&quot; state broadcast.</strong> A VDA5050 adapter presents our robots to SynaOS as a virtual fleet: SynaOS <em>sees</em> state updates synthesized from our replicated facts (pose, power, <code>carried_by</code>, marking progress), so it knows what our robots are doing \u2014 but the integration is intentionally incomplete: we broadcast discrete state, we do not yet coordinate over map locations.</p></li><li><p><strong>Ceiling \u2014 zoned base/horizon coordination (future / Schweinfurt / MSA scale).</strong> Align the two very different maps (SynaOS LIF nodes/edges \u2194 our spatial + mindmap + 3D maps), represent SynaOS nodes as <strong>places</strong> (semantic anchors, perception-refined), and in <strong>SynaOS-owned zones</strong> request and obey base/horizon as <strong>lease</strong> tokens (an execution reservation), with edge traversal evaluated by conformance (&quot;close enough&quot;), not exact match. In our work cells, SynaOS holds no authority and base/horizon don't apply. This is the hard tier and is explicitly post-pilot.</p></li></ul><p>The mapping onto this doc's model, where it applies:</p><ul><li><p><strong>VDA node (LIF)</strong> \u2192 a <strong>place</strong> with <code>authority_owner = synaos</code> in SynaOS-owned regions.</p></li><li><p><strong>VDA order</strong> \u2192 a <strong>work</strong> token via a source transition.</p></li><li><p><strong>VDA action</strong> (e.g. <code>pick</code>) \u2192 an <strong>internal workflow</strong>; the adapter reports a clean action result and hides internal transitions.</p></li><li><p><strong>VDA base/horizon</strong> \u2192 <strong>lease</strong> tokens <em>only inside SynaOS-owned zones</em>.</p></li><li><p><strong>VDA state/telemetry</strong> \u2192 <strong>synthesized from replicated facts</strong> + marking progress.</p></li></ul><p>Two boundaries to hold regardless of tier: VDA navigation gets the robot roughly there at AMR tolerances \u2014 <strong>task-level cm precision is local manipulation refinement, never grasp from the map</strong>; and customer-specific shims (SynaOS) sit on top of any VDA5050 core, expected to vary per site. This is distinct from Safe Coexistence (HMND-19), the runtime AGV/AMR coexistence <em>behaviour</em>; E.2 is the <em>protocol/authority</em> by which the customer fleet and ours coordinate.</p><hr/><h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-AppendixF\u2014AuthorityPlacement(deferstotheOutpostspec)\">Appendix F \u2014 Authority Placement (defers to the Outpost spec)</h1><p>This model <strong>accommodates</strong> either authority placement; it does <strong>not</strong> own the placement decision, node topology, or HA tiers \u2014 those belong to the <strong>HMND Outpost &amp; Site Authority</strong> spec, which is canonical for them. HA/node-count is an infrastructure axis orthogonal to this state model.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-F.1Whatthisspecneedsfromplacement\">F.1 What this spec needs from placement</h2><p>Only one thing: <em>where the writer of operational truth lives.</em> Two cases, and the state model behaves identically in coordination terms under both:</p><ul><li><p><strong>Cloud-authoritative.</strong> Robots reach the cloud coordinator over the (locked-down, proxied) site WAN. Acceptable where the WAN is reliable and ~33 ms (UK region) is fine. <strong>Phase 1 of the Schaeffler pilot leans here.</strong></p></li><li><p><strong>Site-authoritative.</strong> A local Switchboard runs at the site and is authoritative for that fleet's live coordination; the cloud observes via async, one-directional sync. Survives WAN loss. <strong>Phase 2 shifts here to hit availability KPIs.</strong></p></li></ul><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-F.2Authoritybydataclass(consistentwithOutpost&#39;sruntime/durablesplit)\">F.2 Authority by data class (consistent with Outpost's runtime/durable split)</h2><ul><li><p><strong>Registry / config</strong> (definitions, maps, fleet membership, groups) \u2014 <strong>cloud-authoritative</strong>, pushed down; the site reads a cached copy.</p></li><li><p><strong>Live coordination state</strong> (markings, leases, facts) \u2014 <strong>local-fast</strong>; site-authoritative when a site authority is present (markings may be local-fast even under cloud authority, per the Outpost Tier-1 contract). Streamed <strong>up</strong> to the cloud read-only.</p></li></ul><p>One authority per data class means sync is one-directional per class with no merge conflicts \u2014 an event/log stream, not two-master reconciliation. Epoch and version travel with the records so the observer can order and dedupe.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-F.3Identityunderpartition\">F.3 Identity under partition</h2><p>For a site authority to enroll robots and mint fleet certs during a WAN outage, Backbone issues it an <strong>intermediate CA</strong>, granted <strong>only</strong> for airgap/in-factory/offline operation (the Outpost spec's &quot;certificate pi\u00f1ata&quot; warning applies \u2014 the default is <em>not</em> to hand every site a long-lived intermediate). The default is cloud-mints, edge-validates. Enrollment and the work loop keep functioning offline; revocation/rotation reconcile on reconnect.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-F.4Resolved/remaining\">F.4 Resolved / remaining</h2><ul><li><p><strong>Fleet/site cardinality</strong> \u2014 resolved (\u00a74): <strong>one site per fleet deployment, multiple maps allowed</strong>.</p></li><li><p><strong>Fleet SVID minting</strong> \u2014 resolved by the Outpost spec: cloud mints by default, edge validates; delegated local intermediate only for offline modes.</p></li><li><p><strong>Cross-robot deadlock info</strong> \u2014 resolved (\u00a7E.2 floor): <strong>node/zone occupancy facts</strong>, served at the edge.</p></li><li><p><strong>Sync transport and lag budget</strong> \u2014 owned by the Outpost spec.</p></li><li><p><strong>Map places: replica vs reference</strong> \u2014 replicate-on-version-load (uniform query, chosen in A.1).</p></li></ul><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-F.5Site\u2194CloudSyncIsanApplication-LayerProtocol(Phase-2designsketch)\">F.5 Site\u2194Cloud Sync Is an Application-Layer Protocol (Phase-2 design sketch)</h2><p><strong>Decision.</strong> Sync across the site\u2194cloud boundary happens at the <strong>application layer</strong>, over the same authenticated HTTP surface everything else uses \u2014 never DB-layer replication. Two rules: <strong>DB replication (read replicas, HA) is permitted only inside a trust-and-version domain; anything crossing the site\u2194cloud boundary \u2014 different trust, different versions, different authority \u2014 goes through the application protocol.</strong> Rationale: the sync contract is per data class with a direction (F.2), which WAL-level replication cannot express; the site authority becomes just another principal (SVID at the edge, Cedar-capped to its own fleet, RLS, both audit logs) so the sync channel inherits the entire four-tier security model instead of needing a parallel one for a database connection; a versioned JSON surface tolerates version skew across N customer sites where synchronized upgrades are impossible; outbound-only HTTPS from the site matches the same NAT/firewall posture as the robots; and authority transfer (Phase 2 cutover) becomes an epoch-scoped recorded event rather than a database failover. The work loop is the template: <strong>a site authority syncs to the cloud the way a robot syncs to Switchboard</strong> \u2014 the same idempotency, epoch, and latest-wins machinery, one level up.</p><p><strong>Markings sync by replay.</strong> The event log is the transport. The cloud never stores authoritative markings for a site-authoritative fleet; it holds a read-model derived by folding events \u2014 G.6's oracle (&quot;the event log replays to the same marking&quot;) promoted from an invariant to the mechanism, and kept honest as a property test (<code>replay(log) == marking</code>) run against every store. Four conditions make the fold sound:</p><ol start=\"1\"><li><p><strong>Replay is a mechanical fold, never re-execution.</strong> Events record <em>what happened</em>, with a payload sufficient to apply blind \u2014 replay never re-evaluates guards, consults facts, or needs the workflow definition. All commit-time decisions are baked into the event at write time; migrations, resets, and interventions are events carrying their inputs (the place mapping, the seed).</p></li><li><p><strong>Reaping is an event, not a clock.</strong> Sink-place reaping must appear in the log (a <code>__reap__</code> event) so an observer neither re-implements TTL with its own clock nor fails to prune. No clocks in anything that must replay deterministically.</p></li><li><p><strong>Gap detection needs a per-instance monotonic sequence.</strong> Time-ordered UUIDv7 event ids order the stream but cannot prove completeness. A per-instance <code>seq</code> makes the cursor protocol self-verifying: the observer sees 41 then 43 and requests backfill.</p></li><li><p><strong>Bootstrap is snapshot + suffix.</strong> Periodic marking checkpoints (snapshot + the cursor it corresponds to) let a new or lagging observer join without genesis replay, and bound site-side log retention \u2014 the OLAP path remains the forever-record.</p></li></ol><p><strong>Facts sync as an LWW map.</strong> The fact replica is merged with <code>merge(a, b) = max_by(epoch, observed_at, writer)</code> \u2014 a join-semilattice (commutative, associative, idempotent), i.e. a state-based CRDT without importing one. The design already supplies what makes LWW safe: write authority is single-writer per <code>(subject, key)</code> (two writers contending is a definition smell, \u00a7B.6), <code>observed_at</code> is enforced monotonic per <code>(subject, epoch)</code>, and epoch dominates across reconnects \u2014 so &quot;last&quot; never depends on synchronized wall clocks. TTL/epoch make tombstone GC unnecessary: an old entry is inert, not dangerous. <strong>Do not adopt a generic CRDT library</strong> (vector clocks, OR-sets); the domain-specific causality is smaller, already implemented, and easier to audit.</p><p><strong>Leases and claims never sync as writable state.</strong> They are meaningful only inside the single strong authority. The cloud observes a site's leases read-only \u2014 effectively more TTL-governed facts. The moment a lease looks writable on both sides of a partition, the one-authority-per-class design has been silently abandoned.</p><p><strong>Protocol summary.</strong> <em>Up:</em> the event stream (per-instance seq + cursor; the same stream feeds the webhook outbox and the OLAP export \u2014 sync is a third consumer of the J.3/J.4 outbox-and-cursor machinery, not a new subsystem) plus coalesced fact deltas merged LWW. <em>Down:</em> immutable config versions, pulled. <em>Bootstrap/recovery:</em> snapshot + cursor, then suffix replay. <em>Partition behavior:</em> the cloud twin goes TTL-stale and says so \u2014 a partitioned site degrades in the operator view exactly like a robot that went dark; on reconnect, replay the gap and merge \u2014 nothing that syncs is multi-master, so there is no reconciliation logic.</p><p><strong>Work items implied</strong> (all small, all site-side): the per-instance event <code>seq</code> column; reap-as-event; marking checkpoint snapshots; the replay-equivalence property test. Transport choice and lag budget remain the Outpost spec's (F.4); this section fixes the <em>mechanism</em>.</p><hr/><h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-AppendixG\u2014Use-CasesandEnd-to-EndTests\">Appendix G \u2014 Use-Cases and End-to-End Tests</h1><p>Scenarios double as the use-case catalogue and the integration-test suite, drawn from real pilot/demo contexts: <strong>Symphony 2</strong> two-robot tote handling (east/west, aw7/aw12), <strong>RoboStore</strong>/<strong>ring picking</strong> demos, the <code>martur_fompak</code> stack with <code>mock-wms</code>, the <strong>June Schaeffler navigation workshop</strong>, and recurring deployment/troubleshooting threads. Each is preconditions \u2192 steps \u2192 oracle and asserts a model property.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.1Robotsoftwareupdateandrejoin\">G.1 Robot software update and rejoin</h2><p><strong>Pre:</strong> <code>r12</code> <code>working</code>, holding a <code>NavigateToStack</code> lease, carrying <code>load:tote_3</code>. <strong>Steps:</strong> take r12 offline past TTLs; bring it back (epoch 42\u219243), re-localize, re-assign. <strong>Oracle:</strong> during downtime r12's pose leaves <code>fact_fresh</code>; the lease expires and work returns to the pool; r12's marking is unchanged; <code>tote_3</code>'s relative pose resolves <code>unknown</code>. On return, epoch-42 facts are not fresh even within TTL; r12 is ineligible until <code>localization.current(epoch=43)</code> is fresh and above threshold (written by reverb); then it resumes. No phantom participation.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.2Bumpthemapversion\">G.2 Bump the map version</h2><p><strong>Pre:</strong> deployment on <code>herzo@v17</code>; <code>r7</code>, <code>r12</code> localized. <strong>Steps:</strong> record <code>herzo@v18</code>; point <code>active_map</code> at v18; robots re-pull and re-localize. <strong>Oracle:</strong> v17 place facts invalidate by map epoch and v18 places replicate in; a pose with <code>map_id=v17</code> is rejected for a v18 guard (frame identity, fail closed); each robot is ineligible until it re-asserts <code>localization.current(map_id=v18)</code>; workflow places re-resolve against v18; no cross-version pose comparison succeeds. (No <code>tag_set_version</code> needed \u2014 map version + epoch suffice.)</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.3Reassignarobottoadifferentworkflow(distinctmap,samesite)\">G.3 Reassign a robot to a different workflow (distinct map, same site)</h2><p><strong>Pre:</strong> <code>r12</code> working <code>A</code> on <code>M1</code>; <code>r7</code> working <code>B</code> on <code>M2</code>; both maps in <code>site:herzo</code>. <strong>Steps:</strong> operator records a new <strong>assignment</strong> r12\u2192B; r12 polls, de-registers from A, pulls <code>M2</code>+B, re-localizes, runs B. <strong>Oracle:</strong> r12's A-markings release (or quarantine if mid-task) and its A lease frees; r12's <strong>fleet-scoped resource facts survive the switch</strong> (not workflow-owned) \u2014 proving the replica/projection split; r12 is ineligible in B until localized on <code>M2</code>; <code>r7</code> unaffected; the fleet lens shows both robots continuously. <em>(This is the single-workflow regression, now supported.)</em></p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.4Migrateaninstanceacrossadefinitionversion\">G.4 Migrate an instance across a definition version</h2><p><strong>Pre:</strong> instance <code>i1</code> on <code>empty_stacks</code> <strong>v3</strong>, tokens in <code>P1,P2,P3</code>; agent publishes <strong>v4</strong> renaming <code>P2\u2192P2'</code>, removing <code>P3</code>. <strong>Steps:</strong> <code>PUT</code> v4 (validated vs map places); agent supplies <code>{P1\u2192P1, P2\u2192P2'}</code>; <code>POST /migrate</code> (drain). <strong>Oracle:</strong> drains in-flight leases, then quiesces; tokens move <code>P1\u2192P1</code>, <code>P2\u2192P2'</code>; the <code>P3</code> token \u2192 <code>__quarantine__</code>; <code>definition_version=4</code>; a <code>__migrate__</code> event records the mapping; facts untouched; eligibility recomputes against v4. Forced migration uses <code>release\u2192reacquire</code> and quarantines the interrupted token.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.5Multi-robotreservationandcorridorlock\">G.5 Multi-robot reservation and corridor lock</h2><p><strong>Pre:</strong> two robots, two stacks, central table with N slots, hall locks. <strong>Steps:</strong> both concurrently reserve totes/slots and attempt the same hall. <strong>Oracle:</strong> no tote/slot reserved twice (<strong>lease serializes dispatch</strong> \u2014 even though pose facts are relaxed); the second hall claimant is <strong>not offered</strong> the lock while held; when one robot drops (G.1) its reservations release by TTL; total delivered never exceeds available totes/slots.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.6SAP/WMSorderinjectionandfulfilment\">G.6 SAP/WMS order injection and fulfilment</h2><p><strong>Pre:</strong> running instance, idle robots; a WMS principal authorized only for <code>NewOrder</code>. <strong>Steps:</strong> WMS injects <code>NewOrder</code> \u00d73 (instant, no lease), each with a SAP order number on <code>external_ref</code>. <strong>Oracle:</strong> three <code>work:order</code> tokens via source transitions; the WMS principal cannot fire any other transition <strong>and cannot deviate</strong>; orders fulfilled by eligible robots; status maps back by <code>external_ref</code>; the event log replays to the same marking; fulfilled tokens reach a <strong>sink</strong> and reap, history retained in OLAP.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.7SynaOScoexistence(zonedauthority)\">G.7 SynaOS coexistence (zoned authority)</h2><p><strong>Pre:</strong> the SynaOS adapter registered as a System-3 principal; LIF aligned to <code>herzo@v17</code>; <code>r7</code> localized. <strong>Steps (pilot floor):</strong> <code>r7</code> traverses a SynaOS-owned aisle while a KUKA AGV approaches; <code>r7</code> broadcasts zone occupancy and pulls over. <strong>Oracle:</strong> the occupancy fact is visible to peers; <code>r7</code> treats the AGV as a dynamic obstacle and yields; <strong>inside the SynaOS-owned zone SynaOS is the traffic authority</strong>; once <code>r7</code> enters its <strong>work cell, SynaOS holds no authority</strong>; no VDA semantics leak into the robot stack; the adapter cannot deviate. <em>(Ceiling-tier base/horizon\u2192lease is exercised only in a future test once map alignment exists.)</em></p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.8Operatorplotsthefloorwhilearobotisdelocalized\">G.8 Operator plots the floor while a robot is delocalized</h2><p><strong>Pre:</strong> <code>r7</code> localized and moving; <code>r12</code> enrolled but stuck <code>localizing</code>. <strong>Steps:</strong> operator opens the map lens for <code>herzo@v17</code>. <strong>Oracle:</strong> the map returns <code>r7</code> at a fresh world pose plus static places; <code>r12</code> does <strong>not</strong> appear as a located pose \u2014 it shows enrolled/idle in the fleet lens; a load carried by <code>r7</code> resolves through its carrier (relative mode); nothing plots a stale or wrong-map pose.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.9ReconnectwithinTTLmustnotresurrectstaletruth(reverb-cacheacceptancetest)\">G.9 Reconnect within TTL must not resurrect stale truth (reverb-cache acceptance test)</h2><p><strong>Pre:</strong> <code>r12</code> working; pose TTL 2 s; <strong>reverb localization cache removed or epoch-aware</strong> (\u00a711 precondition). <strong>Steps:</strong> r12 blips for 1.5 s (inside TTL) and returns with an epoch bump. <strong>Oracle:</strong> even within its TTL window the prior pose is non-fresh because of the epoch bump; r12 re-asserts at the new epoch before any guard trusts its pose; <strong>no on-disk cache republishes the stale pose</strong>; no flicker. <em>(This test fails against today's reverb until the cache precondition is met \u2014 that is the point.)</em></p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.10IdempotentworkloopunderflakyWiFi\">G.10 Idempotent work loop under flaky WiFi</h2><p><strong>Pre:</strong> <code>r12</code> working; a <code>CompletePick</code> claim in flight. <strong>Steps:</strong> r12 sends the claim; the response is lost; r12 retries the identical claim. <strong>Oracle:</strong> the transition fires exactly once (idempotent by <code>claim_id</code>); fact upserts are latest-wins; a refreshed lease is extended, not duplicated; the event log shows one <code>CompletePick</code>.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.11Carriedtote:pick,place,andadrop\">G.11 Carried tote: pick, place, and a drop</h2><p><strong>Pre:</strong> <code>load:tote_3</code> absolute-located on <code>table_a</code>; <code>r7</code> localized and approaching. <strong>Steps:</strong> <code>r7</code> fires <code>pick</code> (consume absolute token, produce relative/carried, assert <code>carried_by=r7</code>), navigates, fires <code>place</code> on <code>table_b</code>. Then a second run where <code>r7</code> drops the tote mid-transit. <strong>Oracle (place):</strong> while carried, the tote's pose derives from r7's pose and is in <code>relative</code> mode; on <code>place</code> the pose <strong>collapses to a frozen absolute snapshot</strong> at r7's location and stops re-deriving; the tote is <strong>one subject</strong> throughout. <strong>Oracle (drop):</strong> a <code>carried \u2192 dropped</code> transition records last-known position and raises an operator flag \u2014 not silent staleness.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-G.12Recordeddeviation(illegaltransitionacceptedandloud)\">G.12 Recorded deviation (illegal transition accepted and loud)</h2><p><strong>Pre:</strong> <code>r12</code> working; the net expects <code>Pick</code> before <code>Place</code>. <strong>Steps:</strong> r12 (knowing reality) claims <code>Place</code> from a state the net considers illegal. <strong>Oracle:</strong> Switchboard <strong>accepts and records</strong> the claim with <code>conformant=false</code>, moves the token (possibly to <code>__illegal__</code>), and raises a flag \u2014 it does <strong>not</strong> reject reality; conformance metrics over the event log reflect the deviation; a <code>wms-adapter</code> attempting the same <code>Deviate</code> is <strong>denied</strong> (capability-gated); exclusivity (any lease involved) was still serialized.</p><hr/><h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-AppendixH\u2014MVPImplementationandEntryPoints\">Appendix H \u2014 MVP Implementation and Entry Points</h1><p>Single Rust service (Tokio, <strong>axum</strong>) over one Postgres (<code>sqlx</code>) in k3s/EKS, <strong>Cedar</strong> for route authorization, and an in-memory standalone mode for rapid local testing. HTTP/JSON throughout, hot path included.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-H.1Entrypoints\u2014authnattheALB\">H.1 Entry points \u2014 authn at the ALB</h2><ul><li><p><strong>Robots \u2014 mTLS.</strong> ALB terminates mTLS and forwards the SPIFFE id (fleet SVID); the service parses it into a <strong>Robot</strong> principal + fleet + label. Robots reach only enrollment, deployment/assignment poll, and the work loop; outbound-only (zero inbound \u2014 suits site NAT/firewalls).</p></li><li><p><strong>Humans \u2014 OIDC (Cognito).</strong> ALB validates the session and forwards signed claims including <strong>static group memberships</strong>; the service builds a <strong>User</strong> principal with its groups and scope. (Customer-SSO federation deferred, B.7.)</p></li><li><p><strong>Adapters / System-3 \u2014 service-account token.</strong> SAP and SynaOS adapters present a token and become a capability-bounded <strong>Service</strong> principal; they cannot deviate.</p></li></ul><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-H.2Requestpipeline\">H.2 Request pipeline</h2><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"8999ca15-5d4a-48f7-9ea8-1cc7fb18e1f3\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">ALB (mTLS | OIDC | token)  \u2500\u2500headers\u2500\u2500\u25b6  axum middleware\n   1. authenticate at ALB \u2192 identity headers\n   2. middleware builds Principal (Robot | User+static groups | Service)\n   3. set Postgres session app.fleet GUC                       (RLS isolation)\n   4. Cedar authorize(principal, action, resource, context)    (capability; includes Deviate/Intervene)\n   5. handler runs; strong commit in one txn; RLS backstop      (integrity)\n   6. emit Cedar decision + domain event, correlated by trace_id, to the OLAP path  (audit)</pre>\n</div></div><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-H.3MVPscope\">H.3 MVP scope</h2><p>A.1 schema only (no PostGIS, no typed snapshots); one Postgres primary (no sharding, no replica); fleet-as-RLS; <strong>cloud-authoritative footprint</strong> (Phase 1; site authority deferred to Outpost for Phase 2); app-side UUIDv7; static Cognito groups (no federation); sink-place reaping; the three actions + idempotent <code>/work</code>. The same binary is <code>k8s</code>-deployable for the cloud single-pane-of-glass and a future site authority.</p><hr/><h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-AppendixI\u2014WorkflowDefinitionsinStarlark\">Appendix I \u2014 Workflow Definitions in Starlark</h1><p>Definitions are authored as <strong>Starlark</strong> and compiled to the canonical Petri-net IR the runtime executes. Starlark (a hermetic Python subset) gives loops, conditionals, and reusable macros without a Turing-complete escape hatch, evaluates deterministically, and is far easier and more familiar for an authoring agent than soupy YAML. The runtime never sees Starlark \u2014 only the evaluated IR.</p><p><strong>Pipeline.</strong> <code>source (Starlark) \u2192 parse \u2192 evaluate \u2192 normalize \u2192 hash \u2192 validate \u2192 store</code>. The published artifact is the normalized net plus its <code>canonical_hash</code> (A.1 <code>workflow.definition</code> + <code>canonical_hash</code>); the source is retained (<code>source_starlark</code>) for editing/provenance but never executed. <code>PUT /v1/workflows/$id?from=$ver</code> carries the source; the server evaluates, <strong>validates that referenced places resolve in the target map version</strong> (soft reference, \u00a79), and rejects on a stale <code>from</code>.</p><p><strong>Existing YAML.</strong> The <code>symphony2_*.yaml</code> corpus is migrated by <strong>conversion tooling</strong> to Starlark/IR. YAML is not maintained as a perpetual first-class authoring input; it is one possible serialization of the same net, useful for one-time conversion.</p><p><strong>Evaluation constraints.</strong> Frozen globals; no clocks, randomness, or I/O; bounded execution-step and allocation budget; deterministic collection ordering. <code>load()</code> is disabled or restricted to a controlled module path for shared macros (open question below).</p><p><strong>Builtins (DSL sketch).</strong></p><ul><li><p><code>place(name, capacity=, sink=, sink_ttl=)</code> \u2014 a Petri place; <code>capacity</code> enforced at commit; <code>sink</code>/<code>sink_ttl</code> drive marking reaping (\u00a712).</p></li><li><p><code>transition(name, consume=[...], produce=[...], guard=, executor=)</code> \u2014 bound to the executor that fires it (\u00a7B.6).</p></li><li><p><code>role(name, capabilities=[...], subject_binding=)</code> \u2014 a capability bundle; <code>capabilities</code> may include <code>Deviate</code> for executors permitted to record non-conforming transitions (\u00a710).</p></li><li><p><code>executor(name, role=)</code> \u2014 a named actor bound to a role.</p></li><li><p>guard helpers (e.g. <code>near(subject, tag)</code>) \u2014 evaluate at author-time into a guard AST, not free-text, so the validator can reason about them.</p></li></ul><p><strong>Example.</strong></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"b015b923-728c-4152-8a38-3db821042b69\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\"># symphony2.star \u2014 authored by the workflow agent, evaluated to the IR\nWORKCELLS = [&quot;table_a&quot;, &quot;table_b&quot;]\n\nrobots_idle = place(&quot;RobotsIdle&quot;, capacity = len(WORKCELLS))\ncarrying    = place(&quot;Carrying&quot;, capacity = 1)\ndone        = place(&quot;Done&quot;, sink = True, sink_ttl = &quot;10m&quot;)   # tokens here reap\nrole(&quot;mobile&quot;, capabilities = [&quot;*&quot;, &quot;Deviate&quot;], subject_binding = &quot;self&quot;)\nrobot_exec = executor(&quot;robot-exec&quot;, role = &quot;mobile&quot;)\n\ndef empty_stack(cell):\n    src = place(&quot;tote_stack@%s&quot; % cell, capacity = 1)\n    dst = place(&quot;conveyor@%s&quot; % cell, capacity = 1)\n    transition(&quot;pick_%s&quot; % cell,                       # absolute -&gt; relative (carried)\n        consume = [robots_idle, src], produce = [carrying],\n        guard = near(subject = &quot;robot&quot;, tag = &quot;tote_stack@%s&quot; % cell),\n        executor = robot_exec)\n    transition(&quot;place_%s&quot; % cell,                      # relative -&gt; absolute snapshot\n        consume = [carrying], produce = [robots_idle, dst, done],\n        executor = robot_exec)\n\nfor cell in WORKCELLS:\n    empty_stack(cell)</pre>\n</div></div><p><strong>Determinism.</strong> Identical source \u21d2 identical <code>canonical_hash</code>. This lets canonical traces act as regression tests and makes the (deferred) snapshot/patch authoring model reproducible.</p><p><strong>Open questions.</strong></p><ul><li><p>Shared-macro distribution: allow <code>load()</code> of a vetted module path, or inline per definition?</p></li><li><p>Guards: author-time AST (preferred) vs runtime strings \u2014 settle before the validator is built.</p></li><li><p>Evaluation budget defaults and host interpreter (<code>starlark-go</code> / <code>starlark-rust</code> / a Python-native dialect).</p></li><li><p>Operator-facing SOP/visualization: parallel projection (Studio) or co-located docstrings? <em>(Studio workflow editing \u2014 including the authoring-agent tag round-trip, HECO-3376 \u2014 is a separate forthcoming spec.)</em></p></li></ul><hr/><h1 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-AppendixJ\u2014AmendmentsfromtheRustMVPImplementation\">Appendix J \u2014 Amendments from the Rust MVP Implementation</h1><p>The Rust implementation has added several concrete surfaces beyond the abstract state-model spec above. These are accepted MVP amendments unless later replaced by a narrower production design.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-J.1LocalRuntimeTopology\">J.1 Local Runtime Topology</h2><p>The local runtime has two supported shapes:</p><ul><li><p><strong>standalone binary</strong> is the fast local path: one Switchboard process using the in-memory store, with no container runtime or Postgres dependency.</p></li><li><p><strong>k3s/k3d</strong> is the runtime-infra simulation path: ephemeral Postgres via memory-backed <code>emptyDir</code>, a scalable Switchboard <code>Deployment</code>, a ClusterIP service, and Traefik ingress. Kubernetes <code>Ingress</code> does not itself mutate request headers, so the local k3s stack uses Traefik <code>Middleware</code> resources to overwrite the same trusted identity headers that production edge auth provides.</p></li></ul><p>The local trusted-header contract is: <code>x-switchboard-principal-kind</code>, <code>x-switchboard-user-sub</code>, <code>x-switchboard-groups</code>, <code>x-switchboard-fleet</code>, <code>x-switchboard-service</code>, and <code>x-switchboard-robot-id</code>. Direct insecure development access additionally requires <code>x-switchboard-dev-token</code> or <code>Authorization: Bearer &lt;dev-token&gt;</code> when no edge principal header is present.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-J.2EmbeddedMapServer\">J.2 Embedded Map Server</h2><p>The MVP embeds a map-server surface in the Switchboard binary instead of running a separate map service. It stores YAML/PGM map bundles in <code>site_map*</code> tables, maintains an active-map selector per fleet, extracts map tags into durable place subjects, publishes selected tags as <code>keypoint.pose</code> facts, and records map mutations in <code>map_audit_log</code>. This is broader than Appendix A's compact <code>map</code> metadata row: the compact workflow map catalog still exists, but map bundles and tag publication are owned by the embedded map-server module.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-J.3WebhookOutbox\">J.3 Webhook Outbox</h2><p>The implementation includes a durable webhook outbox over workflow events. Webhook subscriptions store projection, event-kind filters, retry bounds, retention windows, timeout, pending backlog limit, and optional signing secret. Deliveries are claimed with database locks, retried with bounded attempts, marked <code>delivered</code> or <code>failed</code>, and subscriptions can pause when backlog bounds are exceeded. Payloads are redacted before delivery; outbound hosts are checked against an allowlist so local/test deployments can opt into explicit receiver hosts.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-J.4AuditandAnalyticsExportSources\">J.4 Audit and Analytics Export Sources</h2><p>The MVP records Cedar authorization decisions in a fleet-scoped <code>authz_audit_log</code> before protected operations proceed. The analytics export stub intentionally treats exactly three OLTP sources as exportable: workflow <code>events</code>, <code>authz_audit_log</code>, and <code>map_audit_log</code>. High-frequency fact updates are deliberately excluded from this business/audit export path.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-J.5CatalogandAPIHardening\">J.5 Catalog and API Hardening</h2><p>The implementation adds practical catalog hardening that the simplified schema omitted: UUID text validation for externally visible IDs, soft-delete metadata, case-insensitive uniqueness for human names, bounded pagination/filter structs on list endpoints, fleet-scoped uniqueness, a <code>commercial_model</code> on fleets, and a <code>region</code> on sites.</p><p>The HTTP surface also includes concrete MVP routes beyond Appendix C's sketch: OpenAPI/Redoc (<code>/openapi.json</code>, <code>/docs</code>), map bundle CRUD and active-map selection, webhook CRUD/delivery inspection, instance event filtering, work-item injection/removal, marking move/reset/retire intervention routes, and the locatables map lens backed by both projected facts and embedded map-server places.</p><h2 id=\"Spec:SwitchboardStateModel&amp;FleetRegistry-J.6Store-PortDecisions\">J.6 Store-Port Decisions</h2><p>This amendment records the concrete model used by the Rust MVP. Where it disagrees with the earlier sketch above, this section is the source of truth until the spec is rewritten top-to-bottom.</p><ul><li><p><strong>One data model.</strong> Switchboard has one native schema and one runtime model. Prototype compatibility is an API translation layer over that model, not a second schema, compatibility database, or schema mode.</p></li><li><p><strong>Fleets are the commercial boundary.</strong> The earlier tenant split is folded into fleets for now. Federation, customer IdP ownership, and cross-customer tenancy can be reintroduced when there is a real commercial or regulatory requirement.</p></li><li><p><strong>Sites are stable operating locations.</strong> Sites remain fleet-scoped and keep a <code>region</code> field as coarse deployment/jurisdiction metadata. Whether this becomes richer jurisdiction policy is deferred.</p></li><li><p><strong>Site maps are definitions plus versions.</strong> A <code>site_map</code> is the named, site-scoped logical map. A <code>site_map_version</code> is the pinned map artifact used by workflows and instances. Names are unique within a site, not globally. Inline bundles stay in the version row for the pilot; S3/LanceDB-backed map assets are a later storage seam.</p></li><li><p><strong>Workflow definitions are source-only metadata plus versions.</strong> A <code>workflow_definition</code> is the named workflow attached to a fleet/site/site-map lineage and records the latest version. A <code>workflow_definition_version</code> stores the authored source, source format, version number, and canonical source hash. The compiled IR is recomputed on load and may be cached in RAM; it is not persisted in the catalog table.</p></li><li><p><strong>Legacy YAML is first-class for the transition.</strong> New authoring is still expected to move toward Starlark, but old Coordinator YAML is accepted as a stored workflow source format and compiled into the same IR. This keeps the existing workflow corpus testable while Studio and the authoring agent move.</p></li><li><p><strong>Runtime instances are separate from definitions.</strong> A <code>workflow_instance</code> pins the exact definition version it started from, may record <code>migrated_from</code>, and owns runtime markings, leases, events, and facts. Publishing a new definition version does not implicitly mutate live runtime state.</p></li><li><p><strong>Robots are physical assets; executors claim work.</strong> Robots are enrolled in a fleet and deployed to at most one site. Executors are instance-scoped work claimants of kind <code>robot</code> or <code>service</code>; robot executors reference a deployed robot, while service executors do not need physical-site lifecycle. Assignment is to workflow instances, not definitions.</p></li><li><p><strong>Markings carry stable entity identity directly.</strong> The separate generic subject/entity table is dropped. <code>entity_id</code> on a marking is the stable UUID that threads token lifecycles across create/destroy transitions.</p></li><li><p><strong>Facts have two scopes.</strong> <code>workflow_facts</code> are instance-scoped facts used by the workflow itself. <code>executor_facts</code> are executor-scoped observations and heartbeats. Both use <code>created_at</code>, <code>created_by</code>, <code>updated_at</code>, and <code>version</code> naming; per-key write authority and stronger frame/epoch modeling are deferred until they are needed.</p></li><li><p><strong>Place metadata belongs to the workflow IR.</strong> Runtime rows reference places by IDs/names resolved from the compiled workflow and map context. Extra metadata that describes a place belongs in the workflow/map source, not in a parallel mutable runtime table.</p></li><li><p><code>/v1</code><strong> is the compatibility API.</strong> The old Coordinator/prototype-compatible paths are served at <code>/v1</code>, including old colon-style prototype subpaths where necessary. They translate to the native model and are marked deprecated.</p></li><li><p><code>/v2</code><strong> is reserved for the native API.</strong> The native route shape should avoid colon actions and should be designed after the store-port proves the model against Studio, reverb, sockpuppet, and the workflow authoring agent.</p></li><li><p><strong>Local tools do not require HTTP.</strong> <code>switchboardctl</code> is the local compiler, validator, diff, snapshot, simulator, and trace runner for Starlark and legacy YAML. Python callers use <code>LocalSwitchboardTools</code>, which shells out to the configured <code>switchboardctl</code> binary and avoids the service API entirely for validation and simulation workflows.</p></li></ul><p>Deferred items are intentionally explicit: fact epochs and frame identity; tag-relative pose semantics; S3/LanceDB map assets; fleet-by-site sharing and multi-fleet sites; customer tenants and IdP federation; the <code>/v2</code> resource design; richer workflow syntax such as subnets, entrypoint constraints, actionless transitions, and tag reservations; per-fact-key write authority; and PostGIS or gRPC promotion if measured bottlenecks justify them.</p>"
        },
        {
          "id": "1501626408",
          "title": "Spec: Kubernetes Simulation Service",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1501626408",
          "last_modified": "2026-06-17T15:26:02.385Z",
          "created_at": "2026-01-13T12:49:15.679Z",
          "body_html": "<p local-id=\"a068edad574c\"><strong>Summary</strong>: Managed K8S service for simulation fleets with optional display,  <br/>workflow execution, and developer access, replacing direct remote-workstation  <br/>and Helm workflows with a service-owned control plane.</p><p local-id=\"eafd6479cab1\"><strong>Owner</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:7690fba0-4f39-48f4-b0f3-91cb29c9f23f\" href=\"https://sklvc.atlassian.net/wiki/people/712020:7690fba0-4f39-48f4-b0f3-91cb29c9f23f?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"2065563701\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Tony Kinsley</a></p><p local-id=\"12c10f80f5ff\"><strong>Date</strong>: <time datetime=\"2026-06-15\" class=\"date-past\">15 Jun 2026</time></p><p local-id=\"a182fd911bbf\"><strong>Approvers</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a> <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:7df6d5c9-5e81-453f-8af7-45995ec2cdfc\" href=\"https://sklvc.atlassian.net/wiki/people/712020:7df6d5c9-5e81-453f-8af7-45995ec2cdfc?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"168525834\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Dmitriy Shingarey</a></p><p local-id=\"8f27f2916a88\"><strong>Informed</strong>:</p><p local-id=\"c1d9db90bdb3\"><strong>Related</strong>:</p><ul local-id=\"b7d1b765a9ab\"><li local-id=\"01ac1ada3ba2\"><p local-id=\"e02554c7ad71\">Source spec: <a href=\"/wiki/spaces/ROBOT/pages/1501626408/Spec+Kubernetes+Simulation+Service\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1501626408</a></p></li><li local-id=\"ed619c8900bd\"><p local-id=\"da532f0a85c4\">Fleet Control Plane: <a href=\"/wiki/spaces/ROBOT/pages/1170341889/Spec+HMND+Fleet+Control+Plane\" data-linked-resource-id=\"1170341889\" data-linked-resource-version=\"16\" data-linked-resource-type=\"page\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1170341889</a></p></li><li local-id=\"150f953a28eb\"><p local-id=\"1d17a5cc126f\">Core Control Plane: <a href=\"/wiki/spaces/ROBOT/pages/1151303693/Spec+HMND+Core+Control+Plane\" data-linked-resource-id=\"1151303693\" data-linked-resource-version=\"8\" data-linked-resource-type=\"page\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1151303693</a></p></li><li local-id=\"85a29718d92c\"><p local-id=\"e033bdcb5a27\">Nexus Sandbox Capability:  <br/><a href=\"/wiki/spaces/ROBOT/pages/1963851838/Spec+Nexus+Cloud+Control+Plane+Sandbox+Capability\" data-linked-resource-id=\"1963851838\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1963851838</a></p></li><li local-id=\"215f9eba5e47\"><p local-id=\"9cc2d8b64de6\">API and CLI: <a href=\"/wiki/spaces/ROBOT/pages/2099871761/Spec+Simulation+Service+API+and+CLI+Compatibility\" data-linked-resource-id=\"2099871761\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2099871761</a></p></li><li local-id=\"70401e805114\"><p local-id=\"4c0014d8398e\">Runtime: <a href=\"/wiki/spaces/ROBOT/pages/2099806230/Spec+Simulation+Runtime+on+EKS\" data-linked-resource-id=\"2099806230\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2099806230</a></p></li><li local-id=\"58a9cbc98069\"><p local-id=\"578a2e7c51e0\">Catalog: <a href=\"/wiki/spaces/ROBOT/pages/2099904528/Spec+Simulation+Catalog\" data-linked-resource-id=\"2099904528\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2099904528</a></p></li><li local-id=\"c69a1cc8843a\"><p local-id=\"b7bc851a9ec5\">Workflow runs: <a href=\"/wiki/spaces/ROBOT/pages/2099871787/Spec+Simulation+Workflow+Runs\" data-linked-resource-id=\"2099871787\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2099871787</a></p></li></ul><h2 local-id=\"70fa5fa243f5\" id=\"Spec:KubernetesSimulationService-ProblemStatement\">Problem Statement</h2><p local-id=\"28f6d6aabd48\">HMND needs a scalable way for engineers to test robot applications without  <br/>depending on direct access to physical robots. The company will never have  <br/>enough hardware for every developer, every integration branch, and every  <br/>automated test lane to use real robots on demand. A managed virtual fleet lets  <br/>us make more tests automatic, repeatable, and deterministic while shortening  <br/>the developer loop from &quot;find hardware and reproduce state&quot; to &quot;launch the  <br/>scenario and inspect the result.&quot;</p><p local-id=\"582130146ca3\">The current simulation workflow is also constrained by developer machines.  <br/>Most engineers work on macOS laptops, while realistic simulation requires an  <br/>NVIDIA platform and a Linux graphics/runtime stack. Setting up a host that can  <br/>run Isaac Sim is itself a project: GPU drivers, CUDA/runtime compatibility,  <br/>Isaac Sim dependencies, remote display, and Wayland/X11 behavior all become  <br/>part of the developer experience. The simulator should be a managed service,  <br/>not a workstation setup exercise.</p><p local-id=\"fd163c35da83\">Single-machine simulation is insufficient for the systems we need to validate.  <br/>Fleet orchestration, robot coordination, Switchboard behavior, policy serving,  <br/>Reverb integration, and cloud control-plane interactions all need tests that  <br/>can operate fleets of virtual robots. Those fleets should be able to run  <br/>against real hosted cloud systems for demos, canaries, product review, and  <br/>feedback, while also supporting isolated test environments for development and  <br/>CI.</p><p local-id=\"2a73eda5b842\">The service needs to support two primary usage modes:</p><ul local-id=\"35cb13d7ce0c\"><li local-id=\"b9a6188c7bb5\"><p local-id=\"d7af46bfb13a\">User-operated simulation, where a person launches a complete virtual system  <br/>built from prebuilt components and interacts through the same product  <br/>surfaces used elsewhere: CLIs, web pages, teleop, logs, and observability.</p></li><li local-id=\"549fff8628a7\"><p local-id=\"40fd766f5dbe\">Developer-targeted simulation, where any component in the virtual system can  <br/>be replaced with a development version, such as a local Switchboard server,  <br/>policy engine, Reverb instance, robot application, or scenario runner.</p></li></ul><h2 local-id=\"a54f16bf622d\" id=\"Spec:KubernetesSimulationService-CurrentState\">Current State</h2><p local-id=\"aac5b93f04bf\">The current simulation stack already has useful K8S building blocks:  <br/>Kubernetes, Helm, ECR-hosted images, Karpenter GPU pools, and <code>sim_cli</code>  <br/>integration. Those pieces prove that GPU-backed interactive simulation can run  <br/>in shared infrastructure, but the user-facing abstraction is still a  <br/>developer-operated pod workflow.</p><p local-id=\"1fb00027c4c9\">On <code>main</code>, <code>hmnd_training/infra/helm/simulation</code> deploys an interactive  <br/><code>hmnd-sim</code> Kubernetes Deployment. <code>sim_cli</code> wraps this chart and provides  <br/>per-user Helm releases, image tag selection, Karpenter GPU profile overrides,  <br/>DCV or VNC display mode, workspace persistence, logs, shell access, scene  <br/>config injection, and pod readiness reporting.</p><p local-id=\"1931bfc9b6af\">The current model has several service-level gaps:</p><ul local-id=\"0bfc3fe46db3\"><li local-id=\"fc90668ba843\"><p local-id=\"0ef779d09cf3\">the user's local process owns authentication, Helm execution, and Kubernetes  <br/>state interpretation;</p></li><li local-id=\"d2601cc48909\"><p local-id=\"dc8bc1043ce1\">authentication depends on local <code>awscli</code> and <code>kubectl</code> setup;</p></li><li local-id=\"0a9a459bf9b9\"><p local-id=\"38300338a4d1\">each simulator instance is a separate deployment, which makes shared  <br/>components across instances difficult;</p></li><li local-id=\"5608b9dbbb91\"><p local-id=\"6fa58027f78f\">TTL, idle detection, and cleanup are not central service behavior;</p></li><li local-id=\"fafd154b3fca\"><p local-id=\"783916bfacf3\">cloud simulation cannot schedule the existing E2E orchestration, assemble  <br/>sim/fleet/robot/policy components, seed Switchboard workflows, drive  <br/>localization/WBC/Reverb initialization, track workflow progress, or return a  <br/>structured pass/fail result.</p></li></ul><p local-id=\"eda2abe6873c\">Detailed E2E workflow behavior is covered in  <br/><a href=\"/wiki/spaces/ROBOT/pages/2099871787/Spec+Simulation+Workflow+Runs\" data-linked-resource-id=\"2099871787\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Simulation Workflow Runs</a>.</p><h2 local-id=\"7d1258e9164a\" id=\"Spec:KubernetesSimulationService-Goals\">Goals</h2><ul local-id=\"d93285a2ac08\"><li local-id=\"f1599dc3e38e\"><p local-id=\"731ac8c528cd\">Provide a service-owned API, CLI, and web UI for launching and operating  <br/>simulator fleets on k8s.</p></li><li local-id=\"5d69e109a693\"><p local-id=\"72303c86829f\">Authenticate developers through a Cognito pool with Google SSO.</p></li><li local-id=\"f7ee95c8c606\"><p local-id=\"6d3829ce4ad0\">Avoid requiring normal users to run Helm or <code>kubectl</code> for deployment,  <br/>lifecycle, and happy-path access.</p></li><li local-id=\"d4fd24e1d360\"><p local-id=\"73589a890d3c\">Preserve current developer workflows from <code>sim_cli</code>, including scene setup,  <br/>GPU selection, display access, logs, shell/debug access, robot bringup, and  <br/>controller launch.</p></li><li local-id=\"4a49a2aa6c43\"><p local-id=\"39d534cce1a1\">Support workflow execution for E2E and canary simulation runs.</p></li><li local-id=\"f29a9fbbfcfb\"><p local-id=\"1667b1221859\">Optimize the developer loop by keeping components small and schedulable  <br/>together, so iterating on one component does not require rebuilding and  <br/>uploading the full simulator image.</p></li><li local-id=\"743669a705fc\"><p local-id=\"6eb04a38030b\">Keep fleet and instance state Kubernetes-native for v1.</p></li></ul><h2 local-id=\"261c46fa7871\" id=\"Spec:KubernetesSimulationService-Non-Goals\">Non-Goals</h2><ul local-id=\"11eb9ee4113a\"><li local-id=\"e13ce4e83bc0\"><p local-id=\"ed0a2b272322\">Replacing every <code>kubectl</code> workflow. The service should still provide  <br/>generated <code>kubectl logs</code>, <code>kubectl exec</code>, and <code>kubectl port-forward</code>  <br/>commands for diagnostics and development.</p></li><li local-id=\"91f93bfb5a83\"><p local-id=\"5d3ff594d2ed\">Supporting multi-instance fleets in Phase 1. The API should be designed for  <br/>multi-instance fleets, but the first implementation should enforce  <br/><code>SimFleet.size == 1</code>.</p></li><li local-id=\"7aa5acd2d7f4\"><p local-id=\"b51782f57915\">Making display a required part of every run. Display is a capability that can  <br/>be enabled for visual debugging and user-operated simulation, not a fleet  <br/>type.</p></li><li local-id=\"f92bda36eafa\"><p local-id=\"6f0607900c29\">Introducing an external database for authoritative fleet state in v1.</p></li></ul><h2 local-id=\"5b545121ab0b\" id=\"Spec:KubernetesSimulationService-DesignOverview\">Design Overview</h2><p local-id=\"1e49ade4cd5d\">The backend should be implemented as a single binary process with two logical  <br/>responsibilities: a user-facing Simulator Service API and a Kubernetes-facing  <br/>Simulator Operator. Splitting these names in the spec is about ownership and  <br/>interfaces inside the service, not about requiring two separately deployed  <br/>services.</p><p local-id=\"c8af35398ed6\">The Simulator Service API is the product and workflow layer. Users interact  <br/>with it through a web UI and CLI backed by a well-defined API. It authenticates  <br/>developers, walks users through scene setup and configuration, exposes catalog  <br/>inputs that users can choose from, records fleets, instances, and runs, and  <br/>returns connection details for active simulations. Its job is to turn &quot;I want  <br/>this simulation&quot; into validated desired state.</p><p local-id=\"8f6df07e1132\">The Simulator Operator is the scheduling and reconciliation layer. It consumes  <br/>validated desired state from the Simulator Service API and turns it into K8S  <br/>workloads. The operator schedules simulator fleets, places workloads on GPU  <br/>nodes, wires companion containers or services, watches runtime health, reports  <br/>status, and cleans up resources.</p><p local-id=\"0a16cbf2a17f\">The operator will be a Kubernetes &quot;operator&quot; for simulation workloads.  <br/>&quot;Operator&quot; is intentionally in quotes: the exact implementation is TBD. We may  <br/>introduce Custom Resource Definitions such as <code>SimFleet</code> and <code>SimInstance</code>, or  <br/>we may implement the same reconciliation model inside the backend controller  <br/>without exposing custom Kubernetes resource types. In either case, the  <br/>user-facing service API should remain stable while the operator implementation  <br/>evolves inside the same backend binary.</p><p local-id=\"4d405c04bc1b\">The service should avoid storing authoritative fleet or instance state outside  <br/>Kubernetes for v1. If we introduce CRDs, <code>SimFleet</code> and <code>SimInstance</code>  <br/>resources should hold desired state and status. If we do not introduce CRDs,  <br/>the backend should use Kubernetes labels, annotations, and ConfigMaps to  <br/>maintain the same state. The expected scale is low enough that Kubernetes API  <br/>performance should not be a limiting factor any time soon.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"2dac5dfd-a845-4be2-ac73-bc05ee89f134\" data-local-id=\"dcb116e2b5ec\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">---\nconfig:\n  theme: base\n  themeVariables:\n    darkMode: true\n    background: &quot;#0f172a&quot;\n    mainBkg: &quot;#111827&quot;\n    primaryColor: &quot;#111827&quot;\n    primaryBorderColor: &quot;#64748b&quot;\n    primaryTextColor: &quot;#e5e7eb&quot;\n    lineColor: &quot;#94a3b8&quot;\n    textColor: &quot;#e5e7eb&quot;\n    clusterBkg: &quot;#111827&quot;\n    clusterBorder: &quot;#64748b&quot;\n    clusterTextColor: &quot;#e5e7eb&quot;\n    edgeLabelBackground: &quot;#111827&quot;\n  layout: elk\n  flowchart:\n    htmlLabels: false\n---\nflowchart TB\n    user[&quot;User CLI / Web UI / Agent&quot;]\n\n    subgraph backend [Single simulator backend process]\n        subgraph service [Simulator Service API]\n            api[&quot;API server&quot;]\n            auth[&quot;Cognito + Google SSO&quot;]\n            setup[&quot;Scene and configuration setup&quot;]\n            catalog[&quot;Simulation catalog&quot;]\n            records[&quot;Fleet, instance, and run views&quot;]\n            access[&quot;Connection details and access tokens&quot;]\n        end\n\n        subgraph operator [Simulator Operator]\n            desired[&quot;Validated SimFleet / SimInstance desired state&quot;]\n            reconcile[&quot;Reconcile desired state&quot;]\n            schedule[&quot;Schedule simulator fleet workloads&quot;]\n            watch[&quot;Watch pod/job state and runtime health&quot;]\n            cleanup[&quot;TTL, idle, and artifact cleanup&quot;]\n            credentials[&quot;Short-lived access credentials&quot;]\n        end\n    end\n\n    subgraph kube_state [Kubernetes-native state]\n        kstate[&quot;CRDs or labels/annotations + ConfigMaps&quot;]\n    end\n\n    subgraph k8s [k8s GPU cluster]\n        subgraph instance [Configurable SimInstance pod]\n            sim[&quot;sim: Isaac Sim + GPU&quot;]\n            robot[&quot;robot: hmnd_robot bringup&quot;]\n            coordinator[&quot;coordinator: workflow API&quot;]\n            map_service[&quot;map-service: fleet map API&quot;]\n            robot_map[&quot;robot-map: robot map state&quot;]\n            warehouse_agent[&quot;warehouse-agent: task executor&quot;]\n            policy[&quot;policy: selected policy service&quot;]\n            runner[&quot;runner: readiness, workflow, result collection&quot;]\n            display[&quot;Optional display / debug sidecars&quot;]\n            exported[&quot;Artifacts/logs exported on completion&quot;]\n        end\n    end\n\n    user --&gt; api\n    api --&gt; auth\n    api --&gt; setup\n    api --&gt; catalog\n    api --&gt; records\n    api --&gt; access\n    access --&gt; credentials\n    api --&gt; kstate\n    kstate --&gt; desired\n    kstate --&gt; records\n    desired --&gt; reconcile\n    reconcile --&gt; schedule\n    reconcile --&gt; watch\n    reconcile --&gt; cleanup\n    schedule --&gt; instance\n    watch --&gt; kstate\n    instance --&gt; records\n    runner --&gt; exported\n    cleanup --&gt; kstate\n\n    sim --&gt; robot\n    robot --&gt; coordinator\n    coordinator --&gt; map_service\n    coordinator --&gt; robot_map\n    coordinator --&gt; warehouse_agent\n    robot --&gt; policy\n    runner --&gt; sim\n    runner --&gt; robot\n    runner --&gt; coordinator\n    runner --&gt; policy\n\n    classDef actorNode fill:#7c2d12,stroke:#fdba74,color:#fff7ed\n    classDef serviceNode fill:#1e3a8a,stroke:#93c5fd,color:#eff6ff\n    classDef operatorNode fill:#14532d,stroke:#86efac,color:#f0fdf4\n    classDef stateNode fill:#713f12,stroke:#fde68a,color:#fef9c3\n    classDef workloadNode fill:#581c87,stroke:#d8b4fe,color:#faf5ff\n\n    class user actorNode\n    class api,auth,setup,catalog,records,access serviceNode\n    class desired,reconcile,schedule,watch,cleanup,credentials operatorNode\n    class kstate stateNode\n    class sim,robot,coordinator,map_service,robot_map,warehouse_agent,policy,runner,display,exported workloadNode\n\n    style backend fill:#0f172a,stroke:#64748b,stroke-width:2px\n    style service fill:#0f1f3d,stroke:#60a5fa,stroke-width:1px\n    style operator fill:#0f2a1a,stroke:#4ade80,stroke-width:1px\n    style kube_state fill:#261b09,stroke:#facc15,stroke-width:2px\n    style k8s fill:#1f1235,stroke:#c084fc,stroke-width:2px\n    style instance fill:#2e1065,stroke:#d8b4fe,stroke-width:1px</pre>\n</div></div><p local-id=\"ac9c8fb5d183\" /><div>We don't have a way to export this macro.</div><h2 local-id=\"513d2d902e08\" id=\"Spec:KubernetesSimulationService-ManagedStateModel\">Managed State Model</h2><p local-id=\"94cdfca5f4ad\">The service should expose two managed states: <code>SimFleet</code> and <code>SimInstance</code>.  <br/>These are product concepts first. They may become Kubernetes CRDs, or they may  <br/>be represented through native Kubernetes objects, labels, annotations, and  <br/>ConfigMaps.</p><h3 local-id=\"881d35e0d0bc\" id=\"Spec:KubernetesSimulationService-SimFleet\">SimFleet</h3><p local-id=\"fb21a0f20775\">A <code>SimFleet</code> is the user-visible unit for a virtual system. It describes the  <br/>desired scene, selected catalog inputs, fleet size, shared services, display  <br/>configuration, workflow execution, access capabilities, lifecycle policy, and  <br/>developer overrides.</p><p local-id=\"133ecdb9e6c3\">The service should model those capabilities directly rather than introducing a  <br/>separate <code>runtime_profile</code> state field. The CLI and UI can still offer  <br/>templates such as &quot;interactive debug&quot;, &quot;E2E workflow&quot;, or &quot;canary&quot;, but those  <br/>templates should expand into explicit <code>SimFleet</code> configuration before the  <br/>operator reconciles Kubernetes resources.</p><p local-id=\"4d787167b208\">A <code>SimFleet</code> records:</p><ul local-id=\"e85594aa0295\"><li local-id=\"e5208d3245e0\"><p local-id=\"4096c020d54c\"><code>id</code> / name</p></li><li local-id=\"2c008bd3a827\"><p local-id=\"c4ea358e6578\"><code>owner</code></p></li><li local-id=\"5609d2baae34\"><p local-id=\"b26dc04fc94d\"><code>state</code>: <code>queued</code>, <code>starting</code>, <code>running</code>, <code>stopping</code>, <code>stopped</code>, <code>failed</code>,  <br/><code>expired</code></p></li><li local-id=\"231b8f9efe3a\"><p local-id=\"ffd225e9994d\"><code>size</code>: desired number of simulator instances</p></li><li local-id=\"27035e1d405f\"><p local-id=\"b0b2ff73e59f\"><code>scene</code>: scene/world configuration</p></li><li local-id=\"1dbccd479fd7\"><p local-id=\"55f01cf9f12b\"><code>catalog_inputs</code>: selected simulator, robot, policy, fleet, and scenario  <br/>catalog entries</p></li><li local-id=\"5789e684dc23\"><p local-id=\"b238ba308aab\"><code>gpu_profile</code>: for example <code>g6_l4</code> or <code>g7e_rtx6000</code></p></li><li local-id=\"add10dc9c4cf\"><p local-id=\"391450664e03\"><code>display</code>: enabled flag, backend such as DCV or WebRTC, resolution, and  <br/>access policy</p></li><li local-id=\"4ff9c916f30e\"><p local-id=\"c9e0b98d2d7f\"><code>workflow</code>: optional scenario, autostart flag, inputs, timeout, and  <br/>completion criteria</p></li><li local-id=\"67ee7944f8ec\"><p local-id=\"68cb7ed4f3fd\"><code>access</code>: logs, exec, port-forward, Foxglove, Sockpuppet, Reverb/app, IDE  <br/>attach, and local development connectivity options</p></li><li local-id=\"5a6d01712df3\"><p local-id=\"5aed8a11713e\"><code>shared_services</code>: Switchboard, policy, Reverb, map services, or external  <br/>endpoints used by the fleet</p></li><li local-id=\"64c1e6e837be\"><p local-id=\"6e88186265b6\"><code>networking</code>: local-development connectivity mode and exposed access points</p></li><li local-id=\"29c4ce5211aa\"><p local-id=\"5610662eb42d\"><code>lifecycle</code>: TTL, idle timeout, hard timeout, cleanup policy</p></li><li local-id=\"2f17d3685690\"><p local-id=\"ecf1d5483a82\"><code>status</code>: aggregate instance readiness, workflow progress, and conditions</p></li><li local-id=\"dfc4a61178eb\"><p local-id=\"5f30bdb5ecbb\"><code>failure_reason</code></p></li></ul><p local-id=\"4cc478e3dd67\"><strong>Phase 1 restriction:</strong> MVP fleets support exactly one simulator. This lets  <br/>the operator schedule shared services in the same pod as the simulator while  <br/>the service contract is still maturing. The restriction should be lifted in a  <br/>later phase by integrating with the  <br/><a href=\"/wiki/spaces/ROBOT/pages/1963851838/Spec+Nexus+Cloud+Control+Plane+Sandbox+Capability\" data-linked-resource-id=\"1963851838\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">Nexus/Sandbox</a>  <br/>model for shared services used by all <code>SimInstance</code> pods in a fleet.</p><h3 local-id=\"00e3ae41a3ab\" id=\"Spec:KubernetesSimulationService-SimInstance\">SimInstance</h3><p local-id=\"8fdd4b86dd35\">A <code>SimInstance</code> is one simulator pod in a <code>SimFleet</code>. Each pod should contain  <br/>the containers required to operate that simulated robot. At minimum, that means  <br/>an Isaac Sim container and an <code>hmnd_robot</code> container. Depending on the selected  <br/>fleet configuration, the pod may also include display/viewer, policy, runner,  <br/>artifact-export, or debugging sidecars.</p><p local-id=\"d794cf521dca\">A <code>SimInstance</code> records:</p><ul local-id=\"c2fb2098402e\"><li local-id=\"262166d608e9\"><p local-id=\"68a228dbbd1e\"><code>id</code> / ordinal</p></li><li local-id=\"1b6f990718c6\"><p local-id=\"016263df3cb4\"><code>fleet_id</code></p></li><li local-id=\"faccd3a55c32\"><p local-id=\"577caca8e77e\"><code>pod_name</code></p></li><li local-id=\"b0b309009fc2\"><p local-id=\"495cba0b3b65\"><code>node</code></p></li><li local-id=\"7118fef4b86f\"><p local-id=\"2cededf56d74\"><code>state</code>: pod phase plus normalized service state</p></li><li local-id=\"ca2eb32a3899\"><p local-id=\"584f64b9ab19\"><code>containers</code>: Isaac Sim, <code>hmnd_robot</code>, and selected companion containers</p></li><li local-id=\"c0b72bc1e4d3\"><p local-id=\"061c0a4c0f77\"><code>image_refs</code>: image repository, tag, digest, and artifact channel</p></li><li local-id=\"b6a5ca3ad054\"><p local-id=\"339cb9648c2f\"><code>robot</code>: robot ID, ROS domain, bringup config, <code>pc_type</code>, and map config</p></li><li local-id=\"74967feeeaf8\"><p local-id=\"8fe6ad7bd57c\"><code>access</code>: display, Foxglove, Sockpuppet, Reverb/app, shell, logs, and IDE  <br/>attach endpoints or commands</p></li><li local-id=\"dccae512ec6e\"><p local-id=\"36bed81ce936\"><code>runtime</code>: tmux/debug handle, port-forward status, and local connect state</p></li><li local-id=\"61c1b650cdc6\"><p local-id=\"1165a7f81158\"><code>health</code>: simulator readiness, robot bringup readiness, fleet registration,  <br/>workflow progress, and last Kubernetes event</p></li><li local-id=\"42ccea5e9e25\"><p local-id=\"d898b3db1782\"><code>artifacts</code>: logs, reports, screenshots, recordings, and run metadata</p></li><li local-id=\"3832b44ded6c\"><p local-id=\"c89a901dfffd\"><code>failure_reason</code></p></li></ul><h2 local-id=\"288d47ab59d8\" id=\"Spec:KubernetesSimulationService-High-LevelRuntimeModel\">High-Level Runtime Model</h2><p local-id=\"d42c3db0e126\">The service should have one <code>SimFleet</code> runtime model. Interactive debugging,  <br/>E2E workflow execution, and canary/demo fleets should be represented as  <br/>different combinations of explicit configuration fields, not as separate  <br/>managed resource categories.</p><p local-id=\"010696c1ab80\">The v1 runtime should use a split <code>SimInstance</code> pod model with separate  <br/>containers for major components instead of treating the current monolithic  <br/>interactive pod as the long-term abstraction:</p><ul local-id=\"beed00d439e4\"><li local-id=\"5e904b16c7a3\"><p local-id=\"dfa6b593f330\"><code>sim</code> owns Isaac Sim and the GPU.</p></li><li local-id=\"2c90c7a24964\"><p local-id=\"eb64f2213f18\"><code>robot</code> owns robot bringup.</p></li><li local-id=\"457e8edd3394\"><p local-id=\"4cd853abdea6\">fleet services run as separate containers or service dependencies.</p></li><li local-id=\"0aac6a4bc816\"><p local-id=\"e444b8218b58\"><code>policy</code> is either an internal endpoint or a sidecar selected by the fleet.</p></li><li local-id=\"1f0f4a861d4d\"><p local-id=\"e0db57732c12\"><code>display.enabled</code> adds a display/viewer sidecar and browser access endpoint.</p></li><li local-id=\"a92be0cc1b33\"><p local-id=\"f4d84f2eb26b\"><code>workflow.autostart</code> adds or activates a runner that owns readiness,  <br/>scenario start, progress checks, result collection, and shutdown.</p></li><li local-id=\"6b0950bc8383\"><p local-id=\"bf135af258bf\"><code>access</code> controls which debug and developer connectivity surfaces are  <br/>exposed through the API and CLI.</p></li></ul><p local-id=\"70a4234ade1a\">Display should not be required for workflow execution. Automated E2E runs  <br/>should default to <code>display.enabled=false</code> so they do not pay the CPU, memory,  <br/>startup, and operational cost of the display sidecar unless a developer  <br/>explicitly requests visual debugging.</p><p local-id=\"7b53063b6990\">Runtime details are covered in  <br/><a href=\"/wiki/spaces/ROBOT/pages/2099806230/Spec+Simulation+Runtime+on+EKS\" data-linked-resource-id=\"2099806230\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Simulation Runtime on </a>k8s.  <br/>API and CLI compatibility details are covered in  <br/><a href=\"/wiki/spaces/ROBOT/pages/2099871761/Spec+Simulation+Service+API+and+CLI+Compatibility\" data-linked-resource-id=\"2099871761\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Simulation Service API and CLI Compatibility</a>.</p><h2 local-id=\"db79e9604a0a\" id=\"Spec:KubernetesSimulationService-PhasedDeliveryPlan\">Phased Delivery Plan</h2><h3 local-id=\"194a711bc66d\" id=\"Spec:KubernetesSimulationService-Phase1:ServiceShellAroundExistingInteractiveChart\">Phase 1: Service Shell Around Existing Interactive Chart</h3><ul local-id=\"9a9cfa54f167\"><li local-id=\"74364399f5a8\"><p local-id=\"fff2e2ad7ead\">Add the single backend binary with Simulator Service API and Simulator  <br/>Operator responsibilities.</p></li><li local-id=\"ae804333f817\"><p local-id=\"fd936678c929\">Add Kubernetes-backed <code>SimFleet</code> and <code>SimInstance</code> state.</p></li><li local-id=\"e3d9c072fc09\"><p local-id=\"0023d3070532\">Enforce <code>SimFleet.size == 1</code>.</p></li><li local-id=\"e3e5bf5cb4b7\"><p local-id=\"c1b348c4c94c\">Dispatch the current Helm chart from the operator instead of from <code>sim_cli</code>.</p></li><li local-id=\"4935419ac955\"><p local-id=\"3db52c96c87d\">Preserve current GPU profile behavior and display access.</p></li><li local-id=\"6bfd3308eff8\"><p local-id=\"9bd7ff7bc91c\">Add TTL cleanup, list/get/terminate, and normalized failure reporting.</p></li><li local-id=\"37053a957bfe\"><p local-id=\"7aae86ce7f7e\">Update CLI to call the service for create/list/get/terminate/connect.</p></li></ul><h3 local-id=\"254901f0cdb4\" id=\"Spec:KubernetesSimulationService-Phase2:E2EWorkflowExecutionOnk8s\">Phase 2: E2E Workflow Execution On k8s</h3><ul local-id=\"828c3e8dcd72\"><li local-id=\"d8dfeecde2aa\"><p local-id=\"6d7fe69e247e\">Define and implement a configurable split <code>SimInstance</code> pod shape on k8s.</p></li><li local-id=\"f8753c828701\"><p local-id=\"7bb733e657c6\">Start with <code>app_regression</code> as the first supported scenario.</p></li><li local-id=\"704a2300052c\"><p local-id=\"5e15fa39d1fe\">Use a real reachable policy service or an explicitly requested test policy  <br/>sidecar.</p></li><li local-id=\"3604604e5049\"><p local-id=\"ea025a2529b8\">Default workflow runs to <code>display.enabled=false</code>, with explicit visual debug  <br/>opt-in.</p></li><li local-id=\"39e762a127a6\"><p local-id=\"87934cbc3175\">Persist runner reports and per-container logs as fleet artifacts.</p></li></ul><h3 local-id=\"c6ac83f69bea\" id=\"Spec:KubernetesSimulationService-Phase3:ScenarioAndSimulationCatalog\">Phase 3: Scenario And Simulation Catalog</h3><ul local-id=\"366037137c14\"><li local-id=\"a0952c31191c\"><p local-id=\"446d904a72d0\">Add scenario registry and runtime image compatibility metadata.</p></li><li local-id=\"afcdbd9a6498\"><p local-id=\"88c6de5762b2\">Add UI/API support for scene setup and catalog selection.</p></li><li local-id=\"b912bd2ea845\"><p local-id=\"c8b31610fc05\">Add scenario input validation and explicit artifact outputs.</p></li><li local-id=\"0d03cdce8310\"><p local-id=\"1816e4a52500\">Support promoted images and release channels instead of ad hoc image tags.</p></li><li local-id=\"361199497e11\"><p local-id=\"fd9ddbcf23b6\">Add richer run history and search.</p></li></ul><h3 local-id=\"6fc2d62304e7\" id=\"Spec:KubernetesSimulationService-Phase4:BroaderSchedulingAndRuntimeRefinement\">Phase 4: Broader Scheduling And Runtime Refinement</h3><ul local-id=\"77a807602207\"><li local-id=\"f913c2ce864a\"><p local-id=\"fcc36de531a7\">Add queueing and capacity-aware scheduling.</p></li><li local-id=\"938402ef8971\"><p local-id=\"e7214a8a9706\">Add better spot/on-demand fallback policy if cost pressure requires it.</p></li><li local-id=\"ddf78aa2c57b\"><p local-id=\"c7fdb37fcbf6\">Revisit one-Pod workflow runtime versus separate Kubernetes services.</p></li><li local-id=\"fc77080a0c86\"><p local-id=\"c243da47f4ab\">Evaluate whether WebRTC or another browser display path should augment or  <br/>replace DCV on k8s.</p></li></ul><h2 local-id=\"85c443f6003d\" id=\"Spec:KubernetesSimulationService-AcceptanceCriteria\">Acceptance Criteria</h2><p local-id=\"8fa805d77cde\">Version 1 is ready when:</p><ul local-id=\"3939b88c343a\"><li local-id=\"c45db9e3ff18\"><p local-id=\"3725ef725507\">A user can create a display-enabled fleet without running Helm or <code>kubectl</code>  <br/>for deployment.</p></li><li local-id=\"f9558fd1f5de\"><p local-id=\"27fe26ce3258\">A user can choose a scene, configuration, and catalog inputs through the  <br/>service API.</p></li><li local-id=\"9615d438a717\"><p local-id=\"0f058f5f1386\">When display is enabled, the service returns a browser display URL and log  <br/>access for each instance.</p></li><li local-id=\"73134da81c59\"><p local-id=\"1b837c961e45\">When display is disabled, the operator does not schedule display-only  <br/>sidecars.</p></li><li local-id=\"83aca6e91830\"><p local-id=\"aaf2604f1b8d\">Each instance schedules on the selected GPU profile or fails with an  <br/>actionable admission error.</p></li><li local-id=\"31a5767c388c\"><p local-id=\"d938983d45fc\">The user can terminate the fleet and the service cleans up all Kubernetes  <br/>resources.</p></li><li local-id=\"0d2b862f245c\"><p local-id=\"0c842844dc60\">TTL and idle cleanup work without manual intervention.</p></li><li local-id=\"a0bc4ea1bbae\"><p local-id=\"bfe0f0cb4ce4\">A user can launch an <code>app_regression</code> workflow through the service API.</p></li><li local-id=\"7efa107da38f\"><p local-id=\"64027406c9ec\">The workflow run reports pass/fail, current step, final task counts, and  <br/>links to logs/artifacts.</p></li><li local-id=\"43a61c686897\"><p local-id=\"18a9b36f6b49\">Failures surface the real blocker, such as policy unreachable, sim not ready,  <br/>robot bringup failed, localization failed, or workflow timeout.</p></li><li local-id=\"c4b6aabcc220\"><p local-id=\"f86b98d5796b\">The CLI no longer requires normal users to manage kubeconfig, Helm releases,  <br/>or direct pod names for happy-path deployment and lifecycle usage.</p></li><li local-id=\"9b53249a68b5\"><p local-id=\"439ddd4efdc1\">Engineers can still use service-generated <code>kubectl logs</code>, <code>kubectl exec</code>,  <br/>and <code>kubectl port-forward</code> commands for diagnostics and development  <br/>connectivity.</p></li></ul>"
        },
        {
          "id": "2105475136",
          "title": "Fleet Software: Requirements \u2192 Services Mapping",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2105475136",
          "last_modified": "2026-06-17T10:45:34.534Z",
          "created_at": "2026-06-16T16:56:00.017Z",
          "body_html": "<p><strong>Audience:</strong> Systems &amp; Product<br/><strong>Purpose:</strong> Show how the FMS requirement set (the 129 FMS functional requirements + 30 new user stories) maps onto the fleet software architecture we are actually building, and where we are on each.<br/><strong>Status:</strong> Draft for review \u2014 Cody Griffin<br/><strong>Related:</strong> Switchboard State Model &amp; Fleet Registry \u00b7 Switchboard Coordinator \u00b7 HMND Outpost &amp; Site Authority \u00b7 Spec: Insight \u00b7 The Problem With Central Planning</p><hr/><h2 id=\"FleetSoftware:Requirements\u2192ServicesMapping-Howtoreadthisdocument\">How to read this document</h2><p>Software doesn't march down the requirements list line-by-line, which makes it hard to tell whether what's been asked for is being built. This document is the bridge: <strong>every requirement has a home</strong> \u2014 an owning service, a one-line <em>how</em>, and a status \u2014 including the ones deliberately deferred or owned outside fleet software.</p><p>Three things explain why the build order differs from the requirement order:</p><ul><li><p><strong>Substrate first, product second.</strong> Many requirements (dashboards, lists, maps, reports) are products <em>on top of</em> a shared coordination/identity/state substrate. Build that once (Switchboard, Backbone, Outpost) and the surfaces come fast and reliable; build them first and you re-plumb the foundation repeatedly.</p></li><li><p><strong>Same intent, different mechanism.</strong> Where a requirement assumes a central scheduler, we coordinate decentrally \u2014 robots self-select advertised work, strong consistency prevents conflicts \u2014 and optimize <em>advisorily</em>, off the critical path. That meets the throughput intent while keeping graceful degradation; full central scheduling stays an optional layer. (See &quot;The Problem With Central Planning.&quot;)</p></li><li><p><strong>Status, not just ownership.</strong> Each row carries a maturity, so you can see the pilot path versus scale-out.</p></li></ul><h3 id=\"FleetSoftware:Requirements\u2192ServicesMapping-Servicelegend\">Service legend</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Code</p></th><th class=\"confluenceTh\"><p>Service</p></th><th class=\"confluenceTh\"><p>Owns</p></th><th class=\"confluenceTh\"><p>Source of truth</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>SB</strong></p></td><td class=\"confluenceTd\"><p><strong>Switchboard</strong></p></td><td class=\"confluenceTd\"><p>Fleet/site/map/workflow registry, coordination state (markings, leases), the replicated fact model, the three actions (enroll/deploy/assign), query lenses, authz projection, System-3 adapters</p></td><td class=\"confluenceTd\"><p>Coordination state; replicates everything else</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>CO</strong></p></td><td class=\"confluenceTd\"><p><strong>Coordinator</strong></p></td><td class=\"confluenceTd\"><p>Workflow/Petri-net execution semantics (the engine under Switchboard)</p></td><td class=\"confluenceTd\"><p>Workflow execution model</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>BB</strong></p></td><td class=\"confluenceTd\"><p><strong>Backbone</strong></p></td><td class=\"confluenceTd\"><p>Global device identity, attestation, certificate lifecycle, <strong>global asset registry</strong>, OS-level device ops (SSH/reboot/OTA/rollback), capability distribution, IAM/Cognito pool</p></td><td class=\"confluenceTd\"><p>Device identity &amp; global asset truth</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>OP</strong></p></td><td class=\"confluenceTd\"><p><strong>Outpost</strong></p></td><td class=\"confluenceTd\"><p>Authority placement (cloud vs site), HA tiers, provisioning state machine, network/power qualification, sync, local service stack, PKI placement</p></td><td class=\"confluenceTd\"><p>Authority placement &amp; site infra</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>RV</strong></p></td><td class=\"confluenceTd\"><p><strong>Reverb</strong></p></td><td class=\"confluenceTd\"><p>On-robot System-2 agent: edge work-selection, perception, localization, manipulation, local safety/coexistence behavior</p></td><td class=\"confluenceTd\"><p>Reality at the edge</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>ST</strong></p></td><td class=\"confluenceTd\"><p><strong>Studio</strong></p></td><td class=\"confluenceTd\"><p>Cloud workflow authoring/editing/inference, simulation &amp; what-if, authoring-agent + eval harness</p></td><td class=\"confluenceTd\"><p>Workflow definitions (authoring)</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>MAP</strong></p></td><td class=\"confluenceTd\"><p><strong>Map / Semantic</strong></p></td><td class=\"confluenceTd\"><p>Map ingest, versioning, 3D/semantic assets, spatial pipeline</p></td><td class=\"confluenceTd\"><p>Static spatial truth</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>OPT</strong></p></td><td class=\"confluenceTd\"><p><strong>Optimization Agent</strong> <em>(advisory)</em></p></td><td class=\"confluenceTd\"><p>Goal\u2192priority translation; reprioritizes/affinity-tags advertised work to bias selection. Off the critical path</p></td><td class=\"confluenceTd\"><p>Nothing authoritative (advisory)</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>INS</strong></p></td><td class=\"confluenceTd\"><p><strong>Insight</strong></p></td><td class=\"confluenceTd\"><p>Derived-truth plane (read-only): KPIs/SLAs, dashboards, alerting, incident detection, benchmarking, explainability, learning corpus. Four stores \u2014 Mimir/Tempo/Loki (system health) + ClickHouse (work events); spans <strong>fleet</strong> scope (from Switchboard) and <strong>device</strong> scope (from Backbone). See <em>Spec: Insight</em>.</p></td><td class=\"confluenceTd\"><p>Nothing authoritative (derived)</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>FC</strong></p></td><td class=\"confluenceTd\"><p><strong>Fleet Console / Fleet API</strong></p></td><td class=\"confluenceTd\"><p>The unified experience layer (single pane of glass): composes the substrate into facility/customer/global views; NL tasking + intent confirmation; role-scoped access</p></td><td class=\"confluenceTd\"><p>Nothing authoritative (composition)</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>N/A</strong></p></td><td class=\"confluenceTd\"><p>\u2014</p></td><td class=\"confluenceTd\"><p>Not fleet software (hardware handling, manufacturing QA)</p></td><td class=\"confluenceTd\"><p>\u2014</p></td></tr></tbody></table></div><h3 id=\"FleetSoftware:Requirements\u2192ServicesMapping-Statuslegend\">Status legend</h3><ul><li><p><strong>Built</strong> \u2014 substrate exists in the current implementation or an approved spec.</p></li><li><p><strong>Next</strong> \u2014 on the pilot path (Schaeffler EOY 2026).</p></li><li><p><strong>Later</strong> \u2014 post-pilot / scale-out.</p></li><li><p><strong>Deferred</strong> \u2014 designed-for but deliberately parked (with a reason).</p></li><li><p><strong>Out</strong> \u2014 outside fleet-software scope.</p></li></ul><hr/><h2 id=\"FleetSoftware:Requirements\u2192ServicesMapping-Thedecentralization&amp;optimizationnote(readthisbeforetheschedulingrows)\">The decentralization &amp; optimization note (read this before the scheduling rows)</h2><p>The requirements include a Scheduling Engine, Workload Balancing, Multi-Robot Coordination &quot;optimising material flow,&quot; and autonomous charging coordination. Here is how we satisfy the <em>intent</em> of all of them:</p><ul><li><p><strong>Conflict-free coordination</strong> is guaranteed by Switchboard today: leases serialize dispatch, so two robots are never handed the same exclusive work. This is strong and non-negotiable.</p></li><li><p><strong>Work selection</strong> is decentralized: work is <em>advertised</em>, and robots (via Reverb) self-select based on their own state (charge, distance, health) and peer awareness. Better-suited robots respond more eagerly; the first valid claim wins. No central brain decides every move.</p></li><li><p><strong>Optimization</strong> is real but advisory: the <strong>Optimization Agent</strong> translates facility goals (&quot;1,000 units/day,&quot; &quot;expedite this order&quot;) into priorities and affinities on the advertised work. It tunes the <em>bias</em>, not the <em>mechanism</em>. If it degrades, the fleet falls back to making steady progress rather than stalling.</p></li></ul><p>This is a deliberate reliability trade chosen for humanoids in unstructured spaces. The throughput target is met; the fragility of central planning is avoided by default. Where a requirement says &quot;scheduling engine,&quot; the default is goal-driven prioritization over a decentralized, self-balancing fleet \u2014 with full central scheduling available as an <strong>optional layer</strong> for deployments that deliberately choose optimality over availability.</p><hr/><h2 id=\"FleetSoftware:Requirements\u2192ServicesMapping-Traceabilitymatrix\u2014FMSFunctionalRequirements(129)\">Traceability matrix \u2014 FMS Functional Requirements (129)</h2><p><em>Requirement text is quoted verbatim from the source export (the bold lead is a short label for scanning). Rows ordered by maturity: Built \u2192 Next \u2192 Later \u2192 Mixed \u2192 Deferred \u2192 Out.</em></p><h3 id=\"FleetSoftware:Requirements\u2192ServicesMapping-\u00a71FacilityFleetManagement\">\u00a71 Facility Fleet Management</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>ID</p></th><th class=\"confluenceTh\"><p>Requirement</p></th><th class=\"confluenceTh\"><p>Service(s)</p></th><th class=\"confluenceTh\"><p>How it's delivered</p></th><th class=\"confluenceTh\"><p>Status</p></th></tr><tr><td class=\"confluenceTd\"><p>3239</p></td><td class=\"confluenceTd\"><p><strong>Facility fleet orchestration (6+ robots)</strong> \u2014 The Fleet Management System shall orchestrate the facility (local) fleet, optimising material flow, and maximising local fleet utilisation. (6+ robots per deployment)</p></td><td class=\"confluenceTd\"><p>SB \u00b7 RV \u00b7 OPT</p></td><td class=\"confluenceTd\"><p>Coordination substrate + edge selection + advisory prioritization</p></td><td class=\"confluenceTd\"><p>Built (coord) / Next (opt)</p></td></tr><tr><td class=\"confluenceTd\"><p>3308</p></td><td class=\"confluenceTd\"><p><strong>Fleet &amp; robot monitoring</strong> \u2014 The Fleet Management System will have monitoring and alerting capabilities for errors impacting robot performance. For example, network degradation, battery, task performance, etc.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 INS</p></td><td class=\"confluenceTd\"><p>Facts/lenses provide data; Insight computes alerts</p></td><td class=\"confluenceTd\"><p>Built (data) / Next (alerting)</p></td></tr><tr><td class=\"confluenceTd\"><p>3303</p></td><td class=\"confluenceTd\"><p><strong>Workflow simulation &amp; what-if</strong> \u2014 The Fleet Management System should allow users to test scenarios before implementation.</p></td><td class=\"confluenceTd\"><p>ST</p></td><td class=\"confluenceTd\"><p>Symbolic simulator exists in Studio</p></td><td class=\"confluenceTd\"><p>Built</p></td></tr><tr><td class=\"confluenceTd\"><p>3298</p></td><td class=\"confluenceTd\"><p><strong>Event replay</strong> \u2014 The Fleet Management System shall allow users to replay robot operations (map + actions + sensor context) for debugging and training.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 INS</p></td><td class=\"confluenceTd\"><p>Append-only event log is the spine; replay UI in Insight</p></td><td class=\"confluenceTd\"><p>Built (log) / Later (UI)</p></td></tr><tr><td class=\"confluenceTd\"><p>3292</p></td><td class=\"confluenceTd\"><p><strong>Integration with enterprise systems</strong> \u2014 The Fleet Management System shall integrate with customer systems (e.g. WMS, MES) for task ingestion and reporting.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 OP</p></td><td class=\"confluenceTd\"><p>SAP/WMS adapter at System-3 boundary; Factory Integration Gateway</p></td><td class=\"confluenceTd\"><p>Built / Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3257</p></td><td class=\"confluenceTd\"><p><strong>Workflow execution</strong> \u2014 The Fleet Management System shall execute defined workflows with metrics and validation.</p></td><td class=\"confluenceTd\"><p>CO \u00b7 SB \u00b7 INS</p></td><td class=\"confluenceTd\"><p>Execution engine + markings/leases + conformance metric</p></td><td class=\"confluenceTd\"><p>Built</p></td></tr><tr><td class=\"confluenceTd\"><p>3252</p></td><td class=\"confluenceTd\"><p><strong>Intervention</strong> \u2014 The Fleet Management System shall enable operators to intervene via teleoperation or control overrides in a safe way.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 RV \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Transactional release\u2192reacquire + marking intervention; teleop transport</p></td><td class=\"confluenceTd\"><p>Built (coord) / Next (teleop)</p></td></tr><tr><td class=\"confluenceTd\"><p>3249</p></td><td class=\"confluenceTd\"><p><strong>Robot swap management</strong> \u2014 The Fleet Management System shall support swapping robots in and out of tasks dynamically.</p></td><td class=\"confluenceTd\"><p>SB</p></td><td class=\"confluenceTd\"><p>Assignment + release\u2192reacquire</p></td><td class=\"confluenceTd\"><p>Built</p></td></tr><tr><td class=\"confluenceTd\"><p>3248</p></td><td class=\"confluenceTd\"><p><strong>Multi-robot coordination</strong> \u2014 The Fleet Management System shall coordinate multiple robots executing tasks simultaneously.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 RV</p></td><td class=\"confluenceTd\"><p>Leases serialize dispatch + edge selection</p></td><td class=\"confluenceTd\"><p>Built</p></td></tr><tr><td class=\"confluenceTd\"><p>3247</p></td><td class=\"confluenceTd\"><p><strong>Dynamic repurposing</strong> \u2014 The Fleet Management System shall enable reassignment of robots across tasks and use cases.</p></td><td class=\"confluenceTd\"><p>SB</p></td><td class=\"confluenceTd\"><p>Reassign via assignment join</p></td><td class=\"confluenceTd\"><p>Built</p></td></tr><tr><td class=\"confluenceTd\"><p>3245</p></td><td class=\"confluenceTd\"><p><strong>Task assignment</strong> \u2014 The Fleet Management System shall allow operators to assign tasks to robots via the Fleet UI.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Assignment / InjectWork action; Console UI</p></td><td class=\"confluenceTd\"><p>Built</p></td></tr><tr><td class=\"confluenceTd\"><p>3243</p></td><td class=\"confluenceTd\"><p><strong>Robot onboarding</strong> \u2014 The Fleet Management System shall onboard robots into the facility fleet with readiness validation.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 OP \u00b7 BB</p></td><td class=\"confluenceTd\"><p>Enroll + localization gate; provisioning state machine; device identity</p></td><td class=\"confluenceTd\"><p>Built / Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3242</p></td><td class=\"confluenceTd\"><p><strong>POI &amp; zone definition</strong> \u2014 The Fleet Management System shall allow definition of points of interest, workstations, safety, maintenance and storage zones.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 MAP \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Zones/POIs as map-owned places; authoring UI</p></td><td class=\"confluenceTd\"><p>Built (model) / Next (UI)</p></td></tr><tr><td class=\"confluenceTd\"><p>3241</p></td><td class=\"confluenceTd\"><p><strong>2D facility map</strong> \u2014 The Fleet Management System shall provide an interactive 2D map of the facility for context showing real-time robot locations, health and allow drill-down to individual robots.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Map lens (operator map view); Console render</p></td><td class=\"confluenceTd\"><p>Built (data) / Next (UI)</p></td></tr><tr><td class=\"confluenceTd\"><p>321</p></td><td class=\"confluenceTd\"><p><strong>Robot list</strong> \u2014 The Fleet Management System shall offer a searchable and filterable robot list view for fleet overview.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Fleet lens; Console list view</p></td><td class=\"confluenceTd\"><p>Built (data) / Next (UI)</p></td></tr><tr><td class=\"confluenceTd\"><p>274</p></td><td class=\"confluenceTd\"><p><strong>Robot status</strong> \u2014 The Fleet Management System shall report the operational status such as Running, Idle, Need Intervention.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Lifecycle state + resource fact; Console</p></td><td class=\"confluenceTd\"><p>Built</p></td></tr><tr><td class=\"confluenceTd\"><p>273</p></td><td class=\"confluenceTd\"><p><strong>Robot ID / name</strong> \u2014 The Fleet Management System shall report a unique identifier or label for each robot.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 BB</p></td><td class=\"confluenceTd\"><p>Subject id + label (SB); device identity (BB)</p></td><td class=\"confluenceTd\"><p>Built</p></td></tr><tr><td class=\"confluenceTd\"><p>3307</p></td><td class=\"confluenceTd\"><p><strong>Workflow editor</strong> \u2014 The Fleet Management System shall provide the ability to edit workflows intuitively through the interface.</p></td><td class=\"confluenceTd\"><p>ST</p></td><td class=\"confluenceTd\"><p>Cloud authoring/editing (authoring agent prototype exists)</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3300</p></td><td class=\"confluenceTd\"><p><strong>Local worker interaction</strong> \u2014 The Fleet Management System shall enable workers to interact with robots locally whilst updating the FMS. For example, a local worker might want to &quot;send home&quot; or &quot;swap out&quot; a robot and this is reflected in the UI.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 RV \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Operator-override facts + assignment change; reflected in Console</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3299</p></td><td class=\"confluenceTd\"><p><strong>Natural language tasking</strong> \u2014 The Fleet Management System shall allow users to assign tasks using natural language via the FMS interface.</p></td><td class=\"confluenceTd\"><p>FC \u00b7 ST</p></td><td class=\"confluenceTd\"><p>NL front-end \u2192 assignment/work; authoring agent exists</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3291</p></td><td class=\"confluenceTd\"><p><strong>Integration with 3rd-party FMS</strong> \u2014 The Fleet Management System shall have the API to integrate with third party fleet management applications for visibility, and control. For example; our robots can be visualised in 3rd party fleet management application like NAiSE.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 OP</p></td><td class=\"confluenceTd\"><p>VDA5050 virtual-fleet state broadcast</p></td><td class=\"confluenceTd\"><p>Next (floor) / Later (full)</p></td></tr><tr><td class=\"confluenceTd\"><p>3261</p></td><td class=\"confluenceTd\"><p><strong>VDA5050 protocol support</strong> \u2014 The Fleet Management System shall implement the VDA5050 communication standard for message exchange between the Fleet Management System and robots, including all mandatory message types and data structures.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 OP</p></td><td class=\"confluenceTd\"><p>Zoned-authority continuum; pilot does floor tier</p></td><td class=\"confluenceTd\"><p>Next (floor) / Deferred (full set)</p></td></tr><tr><td class=\"confluenceTd\"><p>3255</p></td><td class=\"confluenceTd\"><p><strong>Charging coordination (manual)</strong> \u2014 The Fleet Management System shall enable the ability to manually instigate a battery swap between a user selected robot and a user selected swap station.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Manual swap as work injection + lease; triggered in Console</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3253</p></td><td class=\"confluenceTd\"><p><strong>Safety controls</strong> \u2014 The Fleet Management System shall implement and visualise safety features including stop, slow zones, stop conditions and go home for individual robots and fleet.</p></td><td class=\"confluenceTd\"><p>RV \u00b7 SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Zones as places + Console visualisation; <strong>enforcement is robot-side</strong></p></td><td class=\"confluenceTd\"><p>Next (viz) / RV (behavior)</p></td></tr><tr><td class=\"confluenceTd\"><p>3240</p></td><td class=\"confluenceTd\"><p><strong>3D facility map</strong> \u2014 The Fleet Management System shall provide an interactive 3D map of the facility for context.</p></td><td class=\"confluenceTd\"><p>MAP \u00b7 SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>3D/semantic assets + locatables; Console render</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>346</p></td><td class=\"confluenceTd\"><p><strong>Fleet dashboard</strong> \u2014 The Fleet Management System shall include relevant user dashboards.</p></td><td class=\"confluenceTd\"><p>INS \u00b7 FC</p></td><td class=\"confluenceTd\"><p>KPI data + Console dashboards</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3713</p></td><td class=\"confluenceTd\"><p><strong>Remote robot control</strong> \u2014 The Fleet Management System support remote control of an individual robot including bring-up, move to work location, start/stop task, etc.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 RV \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Commands as polled operator <em>intent</em> over the work loop (preserves zero-inbound)</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3498</p></td><td class=\"confluenceTd\"><p><strong>Environment change action</strong> \u2014 The Fleet Management System shall suggest actions for unforeseen environmental changes. For example, suggesting rerouting options to be confirmed.</p></td><td class=\"confluenceTd\"><p>RV \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Robot reroutes locally; suggestion surfaced for confirmation</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3493</p></td><td class=\"confluenceTd\"><p><strong>Fleet/facility goal setting</strong> \u2014 The Fleet Management System will have goal setting ability to set operational performance based goals. For example, the facility needs to achieve 1000 orders or units per day.</p></td><td class=\"confluenceTd\"><p>FC \u00b7 OPT</p></td><td class=\"confluenceTd\"><p>Goals set in Console; translated to advertised-work priorities</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3306</p></td><td class=\"confluenceTd\"><p><strong>Environment change detection</strong> \u2014 The Fleet Management System shall detect and present to the user changes in the environment.</p></td><td class=\"confluenceTd\"><p>RV \u00b7 MAP</p></td><td class=\"confluenceTd\"><p>Perception + map-delta detection</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3302</p></td><td class=\"confluenceTd\"><p><strong>Facility digital twin</strong> \u2014 The Fleet Management System maintain a digital twin of each facility for simulation and planning.</p></td><td class=\"confluenceTd\"><p>ST \u00b7 MAP \u00b7 SB</p></td><td class=\"confluenceTd\"><p>Twin from spatial assets + simulation instances</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3301</p></td><td class=\"confluenceTd\"><p><strong>Intent confirmation</strong> \u2014 The Fleet Management System shall confirm and validate user intent (with confidence levels) before executing commands.</p></td><td class=\"confluenceTd\"><p>FC</p></td><td class=\"confluenceTd\"><p>NL intent rendered for confirmation before commit</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3297</p></td><td class=\"confluenceTd\"><p><strong>Remote diagnostic</strong> \u2014 The Fleet Management System shall automatically identify and present root causes for task failures, robot failures or performance degradation (with dynamic upgrade and confirm).</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>Root-cause over event/telemetry streams</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3296</p></td><td class=\"confluenceTd\"><p><strong>Decision explainability</strong> \u2014 The Fleet Management System shall explain why a robot made a decision (e.g. path, failure, task choice) in a human-readable format.</p></td><td class=\"confluenceTd\"><p>INS \u00b7 RV</p></td><td class=\"confluenceTd\"><p>Event+authz logs correlated by trace_id; agent rationale</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3295</p></td><td class=\"confluenceTd\"><p><strong>Customised report management</strong> \u2014 The Fleet Management System shall allow users to create, edit, and store reports that include images, annotations, timestamps, and metadata for traceability and audit purposes.</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>Reporting product over the event store</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3294</p></td><td class=\"confluenceTd\"><p><strong>Image capture &amp; association</strong> \u2014 The Fleet Management System shall enable live and time-based image capture from robot sensors or external devices and associate images with robots, tasks, locations, or events within the system.</p></td><td class=\"confluenceTd\"><p>RV \u00b7 INS</p></td><td class=\"confluenceTd\"><p>Robot capture; associate to subject/task/event</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3260</p></td><td class=\"confluenceTd\"><p><strong>Fleet operational reporting</strong> \u2014 The Fleet Management System provide reporting on task status, productivity and utilisation at robot and fleet level.</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>Productivity/utilisation reporting over the event store</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3258</p></td><td class=\"confluenceTd\"><p><strong>Workflow optimisation</strong> \u2014 The Fleet Management System shall provide feedback and suggestions to optimise workflows.</p></td><td class=\"confluenceTd\"><p>ST \u00b7 OPT</p></td><td class=\"confluenceTd\"><p>Inference proposes improvements; advisory</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3256</p></td><td class=\"confluenceTd\"><p><strong>Charging coordination (auto)</strong> \u2014 The Fleet Management System shall coordinate charging across robots and swap stations to maximise uptime and operational flows.</p></td><td class=\"confluenceTd\"><p>OPT \u00b7 RV \u00b7 SB</p></td><td class=\"confluenceTd\"><p>Swap station as place + lease + power facts; advisory coordination</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3246</p></td><td class=\"confluenceTd\"><p><strong>Scheduling engine</strong> \u2014 The Fleet Management System shall schedule and balance workloads across robots with constraints, prioritising operational value to the high level operation goal.</p></td><td class=\"confluenceTd\"><p>OPT \u00b7 RV</p></td><td class=\"confluenceTd\"><p>Advisory prioritization + decentralized selection (central scheduling = optional layer)</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>153</p></td><td class=\"confluenceTd\"><p><strong>Robot goal setting</strong> \u2014 The Fleet Management System will have goal setting ability to be able to set operational performance based goals.</p></td><td class=\"confluenceTd\"><p>FC \u00b7 OPT</p></td><td class=\"confluenceTd\"><p>Goals in Console \u2192 priorities</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>278</p></td><td class=\"confluenceTd\"><p><strong>System logs</strong> \u2014 The Fleet Management System shall collect and report system logs, messages, and historical status.</p></td><td class=\"confluenceTd\"><p>BB \u00b7 INS</p></td><td class=\"confluenceTd\"><p>Device logs collected by Backbone; surfaced in Insight</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>277</p></td><td class=\"confluenceTd\"><p><strong>Robot adv. states</strong> \u2014 The Fleet Management System shall report CPU usage, memory usage, current, data usage, and uptime.</p></td><td class=\"confluenceTd\"><p>BB \u00b7 INS</p></td><td class=\"confluenceTd\"><p>Device-scope telemetry (Backbone) surfaced via Insight</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>129</p></td><td class=\"confluenceTd\"><p><strong>Individual robot monitoring &amp; control</strong> \u2014 The Fleet Management System shall support remote control and reporting of the individual robot.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 BB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Operational state via SB; device telemetry via BB; Console</p></td><td class=\"confluenceTd\"><p>Mixed</p></td></tr><tr><td class=\"confluenceTd\"><p>599</p></td><td class=\"confluenceTd\"><p><strong>Sub-fleet &amp; group operations</strong> \u2014 The Fleet Management System shall enable grouping of robots and execution of group operations like updates, reboots, and dispatch commands.</p></td><td class=\"confluenceTd\"><p>BB \u00b7 SB</p></td><td class=\"confluenceTd\"><p><strong>Split concept:</strong> OTA/OS cohorts \u2192 Backbone; tasking affinity \u2192 Switchboard</p></td><td class=\"confluenceTd\"><p>Deferred (needs spec)</p></td></tr><tr><td class=\"confluenceTd\"><p>322</p></td><td class=\"confluenceTd\"><p><strong>Mass actions</strong> \u2014 The Fleet Management System shall support bulk actions on multiple robots, such as updates, reboots, and task assignments.</p></td><td class=\"confluenceTd\"><p>BB \u00b7 SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>OS bulk ops \u2192 Backbone; bulk tasking \u2192 affinity</p></td><td class=\"confluenceTd\"><p>Deferred / Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3305</p></td><td class=\"confluenceTd\"><p><strong>Infrastructure interaction</strong> \u2014 The Fleet Management System shall enable robots to interact with facility infrastructure (doors, elevators, conveyors). <em>(REMOVE)</em></p></td><td class=\"confluenceTd\"><p>N/A</p></td><td class=\"confluenceTd\"><p>Marked REMOVE in source</p></td><td class=\"confluenceTd\"><p>Out</p></td></tr></tbody></table></div><h3 id=\"FleetSoftware:Requirements\u2192ServicesMapping-\u00a72CustomerFleetManagement(1,000+robots\u2014analytics&amp;multi-site)\">\u00a72 Customer Fleet Management (1,000+ robots \u2014 analytics &amp; multi-site)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>ID</p></th><th class=\"confluenceTh\"><p>Requirement</p></th><th class=\"confluenceTh\"><p>Service(s)</p></th><th class=\"confluenceTh\"><p>How it's delivered</p></th><th class=\"confluenceTh\"><p>Status</p></th></tr><tr><td class=\"confluenceTd\"><p>3285</p></td><td class=\"confluenceTd\"><p><strong>Customer-level policy configuration</strong> \u2014 The Fleet Management System shall allow configuration of policies, thresholds, and workflows at the customer level - applicable across a single customer network of sites.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 BB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Tenant-scoped groups/policies in registry/authz; Console UI</p></td><td class=\"confluenceTd\"><p>Next (registry) / Later (UI)</p></td></tr><tr><td class=\"confluenceTd\"><p>3238</p></td><td class=\"confluenceTd\"><p><strong>Customer fleet monitoring &amp; growth</strong> \u2014 The Fleet Management System shall monitor and alert on performance, reliability, utilisation, ROI and provide features that grow and adapt the fleet to new facilities and operations based on customer fleet data (1000+ robot per customer).</p></td><td class=\"confluenceTd\"><p>INS \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Customer-level analytics + dashboard</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3304</p></td><td class=\"confluenceTd\"><p><strong>Cross-facility learning transfer</strong> \u2014 The Fleet Management System shall transfer learnings from one customer facility to others where applicable.</p></td><td class=\"confluenceTd\"><p>INS \u00b7 ST</p></td><td class=\"confluenceTd\"><p>Fleet-wide data pipeline feeds learning/authoring</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3290</p></td><td class=\"confluenceTd\"><p><strong>Fleet growth forecasting</strong> \u2014 The Fleet Management System shall forecast required fleet size based on workload and performance trends, and proactively recommend fleet expansion.</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>Forecasting over utilisation/throughput trends</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3289</p></td><td class=\"confluenceTd\"><p><strong>Performance recommendations</strong> \u2014 The Fleet Management System shall provide recommendations to improve utilisation and performance.</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>Recommendation product over the event store</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3287</p></td><td class=\"confluenceTd\"><p><strong>SLA tracking</strong> \u2014 The Fleet Management System shall track and report performance against defined SLAs.</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>SLA computation/reporting</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3286</p></td><td class=\"confluenceTd\"><p><strong>Stakeholder reporting</strong> \u2014 The Fleet Management System shall generate reports for operational, and business stakeholders. For example: inspection reports for operations, financial reports for business stakeholders.</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>Operational/financial report generation</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3284</p></td><td class=\"confluenceTd\"><p><strong>Site-level alerting</strong> \u2014 The Fleet Management System shall notify users of failures, anomalies, and performance degradation at the site level i.e. this site isn't achieving its UPD target.</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>Per-site KPI/target alerting</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3282</p></td><td class=\"confluenceTd\"><p><strong>Aggregated task performance</strong> \u2014 The Fleet Management System shall measure aggregated task-level performance including cycle time, success rate, and throughput across all sites (operated by the customer).</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>Cycle time / success / throughput across sites</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3280</p></td><td class=\"confluenceTd\"><p><strong>Reliability monitoring (MTBF)</strong> \u2014 The Fleet Management System shall track reliability metrics including uptime, failure rates, and MTBF.</p></td><td class=\"confluenceTd\"><p>INS \u00b7 BB</p></td><td class=\"confluenceTd\"><p>Device-scope reliability metrics (joins fleet at availability)</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3279</p></td><td class=\"confluenceTd\"><p><strong>ROI reporting</strong> \u2014 The Fleet Management System shall calculate and present ROI metrics including throughput, cost savings, and productivity gains.</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>ROI/productivity metrics</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3278</p></td><td class=\"confluenceTd\"><p><strong>Utilisation tracking</strong> \u2014 The Fleet Management System shall track robot utilisation including active time, idle time, and task allocation.</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>Active/idle/allocation tracking</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3277</p></td><td class=\"confluenceTd\"><p><strong>Customer fleet dashboard</strong> \u2014 The Fleet Management System shall provide a unified dashboard showing fleet performance, utilisation, and status across all customer facilities.</p></td><td class=\"confluenceTd\"><p>FC \u00b7 INS</p></td><td class=\"confluenceTd\"><p>Unified cross-facility dashboard</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr></tbody></table></div><h3 id=\"FleetSoftware:Requirements\u2192ServicesMapping-\u00a73GlobalFleetManagement(185krobotsby2030\u2014lifecycle,observability,rollout)\">\u00a73 Global Fleet Management (185k robots by 2030 \u2014 lifecycle, observability, rollout)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>ID</p></th><th class=\"confluenceTh\"><p>Requirement</p></th><th class=\"confluenceTh\"><p>Service(s)</p></th><th class=\"confluenceTh\"><p>How it's delivered</p></th><th class=\"confluenceTh\"><p>Status</p></th></tr><tr><td class=\"confluenceTd\"><p>3313</p></td><td class=\"confluenceTd\"><p><strong>Multi-tenant isolation</strong> \u2014 The Fleet Management System shall isolate customer data, fleets, and operations securely with customers having visibility and control (through UI) of what data is sharable.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 OP \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Fleet-as-RLS + tenant boundary; segregation; sharability-control UI</p></td><td class=\"confluenceTd\"><p>Built (isolation) / Later (UI)</p></td></tr><tr><td class=\"confluenceTd\"><p>3271</p></td><td class=\"confluenceTd\"><p><strong>Identity &amp; access control</strong> \u2014 The Fleet Management System shall enforce secure identity, authentication, and access control across all robots and operators.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 BB \u00b7 OP</p></td><td class=\"confluenceTd\"><p>Cedar authz (SB) + Cognito/device identity (BB) + PKI placement (OP)</p></td><td class=\"confluenceTd\"><p>Built / Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3269</p></td><td class=\"confluenceTd\"><p><strong>Fleet lifecycle management</strong> \u2014 The Fleet Management System shall manage the full fleet lifecycle including onboarding, operation, maintenance, and decommissioning.</p></td><td class=\"confluenceTd\"><p>BB \u00b7 SB \u00b7 OP</p></td><td class=\"confluenceTd\"><p>Enroll/deploy/assign (SB) within full device lifecycle (BB) + provisioning (OP)</p></td><td class=\"confluenceTd\"><p>Built (enroll) / Later (full)</p></td></tr><tr><td class=\"confluenceTd\"><p>3319</p></td><td class=\"confluenceTd\"><p><strong>Commercial model differentiation (CapEx vs. RAAS)</strong> \u2014 The Fleet Management System shall have the ability to differentiate between different commercial models (RAAS or CapEx), with different monitoring, alerting, and escalation paths.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 INS \u00b7 FC</p></td><td class=\"confluenceTd\"><p><code>commercial_model</code> on fleet \u2192 differentiated monitoring/escalation</p></td><td class=\"confluenceTd\"><p>Next (model) / Later (paths)</p></td></tr><tr><td class=\"confluenceTd\"><p>3273</p></td><td class=\"confluenceTd\"><p><strong>Data pipeline for learning</strong> \u2014 The Fleet Management System shall collect and structure fleet-wide data for training, simulation, and continuous improvement.</p></td><td class=\"confluenceTd\"><p>INS \u00b7 ST</p></td><td class=\"confluenceTd\"><p>Event log \u2192 analytical/archive tiers; structured for training</p></td><td class=\"confluenceTd\"><p>Next (log ships) / Later (full)</p></td></tr><tr><td class=\"confluenceTd\"><p>3272</p></td><td class=\"confluenceTd\"><p><strong>Fleet segmentation</strong> \u2014 The Fleet Management System shall segment robots by customer, region, facility and commercial model while maintaining centralized control.</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>tenant/fleet/site + <strong>region on site, commercial model on fleet</strong></p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3262</p></td><td class=\"confluenceTd\"><p><strong>Global asset registry</strong> \u2014 The Fleet Management System shall maintain a global registry of all robots including identity, configuration, ownership, and lifecycle state.</p></td><td class=\"confluenceTd\"><p>BB</p></td><td class=\"confluenceTd\"><p><strong>Backbone owns it</strong>; Switchboard references it (per-deployment fleet registry)</p></td><td class=\"confluenceTd\"><p>Next (BB) / Built (SB ref)</p></td></tr><tr><td class=\"confluenceTd\"><p>3236</p></td><td class=\"confluenceTd\"><p><strong>E2E asset lifecycle &amp; global observability</strong> \u2014 The Fleet Management System shall have end-to-end asset lifecycle management, global observability &amp; health, upgrades &amp; rollout ability for a large distributed fleet operating across multiple different customer facilities (185,000 robots in operation by 2030).</p></td><td class=\"confluenceTd\"><p>BB \u00b7 INS \u00b7 OP</p></td><td class=\"confluenceTd\"><p>Lifecycle/asset (BB) + observability (INS) + rollout substrate (OP)</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3312</p></td><td class=\"confluenceTd\"><p><strong>Spare parts prediction &amp; tracking</strong> \u2014 The Fleet Management System shall predict and recommend spare parts inventory based on usage patterns.</p></td><td class=\"confluenceTd\"><p>INS \u00b7 BB</p></td><td class=\"confluenceTd\"><p>Device-scope usage-pattern prediction</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3311</p></td><td class=\"confluenceTd\"><p><strong>Remote diagnostics</strong> \u2014 The Fleet Management System shall allow remote diagnosis of robot issues without onsite intervention.</p></td><td class=\"confluenceTd\"><p>INS \u00b7 BB</p></td><td class=\"confluenceTd\"><p>Remote diagnosis without onsite intervention</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3310</p></td><td class=\"confluenceTd\"><p><strong>Guided maintenance workflows</strong> \u2014 The Fleet Management System shall guide technicians through maintenance procedures step-by-step.</p></td><td class=\"confluenceTd\"><p>BB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Step-by-step maintenance procedures</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3276</p></td><td class=\"confluenceTd\"><p><strong>Fleet expansion management</strong> \u2014 The Fleet Management System shall support rapid scaling from pilot to large-scale deployments without degradation in performance.</p></td><td class=\"confluenceTd\"><p>OP \u00b7 SB</p></td><td class=\"confluenceTd\"><p>Placement/scale tiers + Switchboard sharding path</p></td><td class=\"confluenceTd\"><p>Later (designed-for)</p></td></tr><tr><td class=\"confluenceTd\"><p>3275</p></td><td class=\"confluenceTd\"><p><strong>Global map &amp; knowledge sharing</strong> \u2014 The Fleet Management System shall enable sharing of maps, workflows, and learnings across facilities and customers.</p></td><td class=\"confluenceTd\"><p>MAP \u00b7 ST \u00b7 BB</p></td><td class=\"confluenceTd\"><p>Map/workflow/learning sharing across sites</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3274</p></td><td class=\"confluenceTd\"><p><strong>Capability distribution</strong> \u2014 The Fleet Management System shall distribute new robot capabilities (skills/workflows) across the fleet (if permitted by customer).</p></td><td class=\"confluenceTd\"><p>BB \u00b7 ST</p></td><td class=\"confluenceTd\"><p>Capability rollout (customer-permitted)</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3270</p></td><td class=\"confluenceTd\"><p><strong>Incident management</strong> \u2014 The Fleet Management System shall detect, log, and manage incidents across all robots and fleets.</p></td><td class=\"confluenceTd\"><p>INS \u00b7 SB</p></td><td class=\"confluenceTd\"><p>Exception events (SB) \u2192 detect/log/manage (INS)</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3268</p></td><td class=\"confluenceTd\"><p><strong>Predictive maintenance</strong> \u2014 The Fleet Management System shall predict maintenance needs using fleet-wide data and trigger proactive servicing.</p></td><td class=\"confluenceTd\"><p>INS \u00b7 BB</p></td><td class=\"confluenceTd\"><p>Device-scope fleet-wide predictive servicing</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3267</p></td><td class=\"confluenceTd\"><p><strong>Controlled software rollback</strong> \u2014 The Fleet Management System shall support controlled rollback of software, policies, and configurations across the fleet (sample to full fleet).</p></td><td class=\"confluenceTd\"><p>BB</p></td><td class=\"confluenceTd\"><p>Sample\u2192full rollback</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3266</p></td><td class=\"confluenceTd\"><p><strong>Fleet-wide software deployment</strong> \u2014 The Fleet Management System shall deploy software updates, policies, and capabilities across the global fleet (sample to full fleet).</p></td><td class=\"confluenceTd\"><p>BB</p></td><td class=\"confluenceTd\"><p>Sample\u2192full OTA</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3265</p></td><td class=\"confluenceTd\"><p><strong>Global performance benchmarking</strong> \u2014 The Fleet Management System shall aggregate telemetry data (performance, utilisation, and faults) across all robots for centralized analysis, and shall use this data to benchmark robot and fleet performance across sites, customers, and use cases.</p></td><td class=\"confluenceTd\"><p>INS</p></td><td class=\"confluenceTd\"><p>Cross-site/customer benchmarking</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3263</p></td><td class=\"confluenceTd\"><p><strong>Fleet-wide health monitoring</strong> \u2014 The Fleet Management System shall continuously monitor health, diagnostics, and status of all robots across the global fleet.</p></td><td class=\"confluenceTd\"><p>INS \u00b7 BB</p></td><td class=\"confluenceTd\"><p>Device-scope health/diagnostics across fleet</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr></tbody></table></div><hr/><h2 id=\"FleetSoftware:Requirements\u2192ServicesMapping-Traceabilitymatrix\u2014NewUserStories(30)\">Traceability matrix \u2014 New User Stories (30)</h2><p>Most user stories restate an FMS functional requirement at a higher level. The use-case text below is the verbatim user story; the bold lead is a short label. Mapped to FMS equivalent + service + status; rows ordered by maturity, as above. Physical-handling and QA stories are flagged as outside fleet software.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>ID</p></th><th class=\"confluenceTh\"><p>Use case</p></th><th class=\"confluenceTh\"><p>FMS equiv.</p></th><th class=\"confluenceTh\"><p>Service(s)</p></th><th class=\"confluenceTh\"><p>Status</p></th></tr><tr><td class=\"confluenceTd\"><p>3740</p></td><td class=\"confluenceTd\"><p><strong>Workflow Execution &amp; Editing</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to execute defined workflows with real-time metrics and validation, and edit those workflows intuitively through the FMS interface, so that operations can be adapted quickly without engineering intervention.</p></td><td class=\"confluenceTd\"><p>3257 \u00b7 3307</p></td><td class=\"confluenceTd\"><p>CO \u00b7 SB \u00b7 ST</p></td><td class=\"confluenceTd\"><p>Built / Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3739</p></td><td class=\"confluenceTd\"><p><strong>Dynamic Repurposing &amp; Robot Swap</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to dynamically reassign robots across tasks and use cases, and swap robots in and out of active tasks, so that I can respond to changing operational demands without interrupting workflows.</p></td><td class=\"confluenceTd\"><p>3247 \u00b7 3249</p></td><td class=\"confluenceTd\"><p>SB</p></td><td class=\"confluenceTd\"><p>Built</p></td></tr><tr><td class=\"confluenceTd\"><p>3738</p></td><td class=\"confluenceTd\"><p><strong>Multi-Robot Coordination</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want the FMS to coordinate multiple robots executing tasks simultaneously, optimising material flow and maximising fleet utilisation across deployments of 6 or more robots, so that throughput targets are met without conflicts.</p></td><td class=\"confluenceTd\"><p>3248</p></td><td class=\"confluenceTd\"><p>SB \u00b7 RV \u00b7 OPT</p></td><td class=\"confluenceTd\"><p>Built (coord) / Later (opt)</p></td></tr><tr><td class=\"confluenceTd\"><p>3735</p></td><td class=\"confluenceTd\"><p><strong>Task Assignment</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to assign tasks to specific robots via the FMS interface so that I can direct the fleet to the right work at the right time.</p></td><td class=\"confluenceTd\"><p>3245</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Built</p></td></tr><tr><td class=\"confluenceTd\"><p>3726</p></td><td class=\"confluenceTd\"><p><strong>2D Facility Map</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want an interactive 2D map of the facility so that I can see real-time robot locations and health, and drill down into individual robots directly from the map.</p></td><td class=\"confluenceTd\"><p>3241</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Built / Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3725</p></td><td class=\"confluenceTd\"><p><strong>Robot List View</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want a searchable and filterable list of all robots in the fleet so that I can quickly locate, inspect, and act on individual robots.</p></td><td class=\"confluenceTd\"><p>321</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Built / Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3723</p></td><td class=\"confluenceTd\"><p><strong>Robot Onboarding Validation</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to onboard a robot into the facility fleet with automated readiness validation so that only robots in a verified operational state are admitted to active service.</p></td><td class=\"confluenceTd\"><p>3243</p></td><td class=\"confluenceTd\"><p>SB \u00b7 OP \u00b7 BB</p></td><td class=\"confluenceTd\"><p>Built / Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3722</p></td><td class=\"confluenceTd\"><p><strong>POI &amp; Zone Definition</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to define points of interest, workstations, safety zones, maintenance zones, and storage zones on the facility map so that robots can navigate purposefully and operators can enforce spatial rules across the fleet.</p></td><td class=\"confluenceTd\"><p>3242</p></td><td class=\"confluenceTd\"><p>SB \u00b7 MAP \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Built / Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3719</p></td><td class=\"confluenceTd\"><p><strong>Network Setup &amp; Fleet Onboarding</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to connect the robot to the customer network and register it in the fleet management system so that it can be monitored, assigned tasks, and operated as part of the fleet.</p></td><td class=\"confluenceTd\"><p>\u2014</p></td><td class=\"confluenceTd\"><p>OP \u00b7 SB \u00b7 BB</p></td><td class=\"confluenceTd\"><p>Built / Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3784</p></td><td class=\"confluenceTd\"><p><strong>Fleet Segmentation</strong> \u2014 As a Global Fleet Operations Manager, I want to segment robots by customer, region, facility, and commercial model while maintaining centralised control so that each customer's fleet is managed independently without sacrificing global visibility.</p></td><td class=\"confluenceTd\"><p>3272</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3741</p></td><td class=\"confluenceTd\"><p><strong>Safety Controls</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to define and visualise safety features including stop zones, slow zones, stop conditions, and go-home commands for individual robots and the fleet so that I can enforce safe operating boundaries at all times. <em>(maybe this should just be visualisation)</em></p></td><td class=\"confluenceTd\"><p>3253</p></td><td class=\"confluenceTd\"><p>RV \u00b7 SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Next (viz) / RV (behavior)</p></td></tr><tr><td class=\"confluenceTd\"><p>3736</p></td><td class=\"confluenceTd\"><p><strong>Natural Language Tasking &amp; Intent Confirmation</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to assign tasks to robots using natural language via the FMS interface, with the system confirming and validating my intent (including confidence levels) before executing, so that I can direct the fleet intuitively without risking unintended actions.</p></td><td class=\"confluenceTd\"><p>3299 \u00b7 3301</p></td><td class=\"confluenceTd\"><p>FC \u00b7 ST</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3733</p></td><td class=\"confluenceTd\"><p><strong>Charging Coordination (Manual)</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to manually trigger a battery swap between a specific robot and a specific swap station so that I can intervene in charging schedules when operational priorities require it.</p></td><td class=\"confluenceTd\"><p>3255</p></td><td class=\"confluenceTd\"><p>SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3727</p></td><td class=\"confluenceTd\"><p><strong>3D Facility Map</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want an interactive 3D view of the facility so that I can gain richer spatial context for robot positions, routes, and zone layouts.</p></td><td class=\"confluenceTd\"><p>3240</p></td><td class=\"confluenceTd\"><p>MAP \u00b7 SB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3724</p></td><td class=\"confluenceTd\"><p><strong>Fleet Dashboard</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want a real-time fleet dashboard so that I can monitor the operational status, health, and performance of all robots at a glance and receive alerts for issues impacting robot performance.</p></td><td class=\"confluenceTd\"><p>346</p></td><td class=\"confluenceTd\"><p>INS \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3721</p></td><td class=\"confluenceTd\"><p><strong>Local Mapping</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to instruct the robot to autonomously map its local environment so that it can navigate, manage tasks, and be orchestrated within the fleet.</p></td><td class=\"confluenceTd\"><p>\u2014</p></td><td class=\"confluenceTd\"><p>MAP \u00b7 RV</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3720</p></td><td class=\"confluenceTd\"><p><strong>Global Mapping</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to upload a facility layout into the FMS so that robots have a global reference map available before on-site deployment.</p></td><td class=\"confluenceTd\"><p>\u2014</p></td><td class=\"confluenceTd\"><p>MAP \u00b7 SB</p></td><td class=\"confluenceTd\"><p>Next</p></td></tr><tr><td class=\"confluenceTd\"><p>3737</p></td><td class=\"confluenceTd\"><p><strong>Scheduling Engine &amp; Workload Balancing</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want the FMS to automatically schedule and balance workloads across all robots respecting constraints and prioritising tasks by operational value so that the fleet consistently works towards facility-level goals.</p></td><td class=\"confluenceTd\"><p>3246</p></td><td class=\"confluenceTd\"><p>OPT \u00b7 RV</p></td><td class=\"confluenceTd\"><p>Later (decentralized)</p></td></tr><tr><td class=\"confluenceTd\"><p>3734</p></td><td class=\"confluenceTd\"><p><strong>New Task Onboarding</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to onboard a new task into the robot's system within 2 hours so that the robot can learn and execute it consistently in its operational environment.</p></td><td class=\"confluenceTd\"><p>\u2014</p></td><td class=\"confluenceTd\"><p>ST \u00b7 RV</p></td><td class=\"confluenceTd\"><p>Later (policy training partly Out)</p></td></tr><tr><td class=\"confluenceTd\"><p>3732</p></td><td class=\"confluenceTd\"><p><strong>Charging &amp; Battery Swap (Autonomous)</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want the FMS to autonomously coordinate charging and battery swaps across all robots and swap stations so that operational uptime is maximised and battery health is maintained.</p></td><td class=\"confluenceTd\"><p>3256</p></td><td class=\"confluenceTd\"><p>OPT \u00b7 RV \u00b7 SB</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3730</p></td><td class=\"confluenceTd\"><p><strong>Environment Change Detection &amp; Response</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want the FMS to automatically detect changes in the environment and surface suggested responses (e.g. rerouting options) for my confirmation so that I can keep the fleet operating safely when conditions change unexpectedly.</p></td><td class=\"confluenceTd\"><p>3306 \u00b7 3498</p></td><td class=\"confluenceTd\"><p>RV \u00b7 MAP \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3729</p></td><td class=\"confluenceTd\"><p><strong>Facility Digital Twin</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want the FMS to maintain a live digital twin of the facility so that I can use it for simulation, planning, and what-if analysis without impacting live operations.</p></td><td class=\"confluenceTd\"><p>3302</p></td><td class=\"confluenceTd\"><p>ST \u00b7 MAP \u00b7 SB</p></td><td class=\"confluenceTd\"><p>Later</p></td></tr><tr><td class=\"confluenceTd\"><p>3728</p></td><td class=\"confluenceTd\"><p><strong>Individual Robot Monitoring &amp; Control</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to view detailed status and telemetry for any individual robot including unique ID, operational state (Running / Idle / Needs Intervention), CPU usage, memory, current draw, data usage, uptime, and system logs and issue remote control commands (bring-up, move to work location, start/stop task) so that I can monitor and manage each robot precisely.</p></td><td class=\"confluenceTd\"><p>129 / 3713 / 277 / 278 / 274</p></td><td class=\"confluenceTd\"><p>SB \u00b7 BB \u00b7 FC</p></td><td class=\"confluenceTd\"><p>Mixed</p></td></tr><tr><td class=\"confluenceTd\"><p>3731</p></td><td class=\"confluenceTd\"><p><strong>Sub-Fleet &amp; Group Operations</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to group robots into sub-fleets and execute bulk operations such as software updates, reboots, and dispatch commands across all robots in a group simultaneously so that I can manage large fleets efficiently.</p></td><td class=\"confluenceTd\"><p>599</p></td><td class=\"confluenceTd\"><p>BB \u00b7 SB</p></td><td class=\"confluenceTd\"><p>Deferred</p></td></tr><tr><td class=\"confluenceTd\"><p>3718</p></td><td class=\"confluenceTd\"><p><strong>Power-Down</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to follow a defined power-down sequence so that I can prevent data corruption, avoid system damage, and leave the robot in a safe, stable state.</p></td><td class=\"confluenceTd\"><p>\u2014</p></td><td class=\"confluenceTd\"><p>N/A</p></td><td class=\"confluenceTd\"><p>Out (hardware procedure)</p></td></tr><tr><td class=\"confluenceTd\"><p>3717</p></td><td class=\"confluenceTd\"><p><strong>Power-Up</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to follow a defined power-up sequence so that the robot starts safely and correctly without risking damage or malfunction.</p></td><td class=\"confluenceTd\"><p>\u2014</p></td><td class=\"confluenceTd\"><p>N/A</p></td><td class=\"confluenceTd\"><p>Out (hardware procedure)</p></td></tr><tr><td class=\"confluenceTd\"><p>3716</p></td><td class=\"confluenceTd\"><p><strong>Unpackaging</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to unpackage the robot carefully so that I can confirm it arrived safely and avoid causing damage during unpacking.</p></td><td class=\"confluenceTd\"><p>\u2014</p></td><td class=\"confluenceTd\"><p>N/A</p></td><td class=\"confluenceTd\"><p>Out (physical handling)</p></td></tr><tr><td class=\"confluenceTd\"><p>3715</p></td><td class=\"confluenceTd\"><p><strong>Packaging</strong> \u2014 As a Deployment Engineer/Fleet Manager, I want to package the robot for transport or storage so that it is protected from damage and can be safely handled during transit or warehousing.</p></td><td class=\"confluenceTd\"><p>\u2014</p></td><td class=\"confluenceTd\"><p>N/A</p></td><td class=\"confluenceTd\"><p>Out (physical handling)</p></td></tr><tr><td class=\"confluenceTd\"><p>3714</p></td><td class=\"confluenceTd\"><p><strong>End of Line Testing</strong> \u2014 As a QA Technician, I want to perform end-of-line testing on each robot before shipment so that I can certify it meets quality, performance, and safety standards.</p></td><td class=\"confluenceTd\"><p>\u2014</p></td><td class=\"confluenceTd\"><p>N/A</p></td><td class=\"confluenceTd\"><p>Out (manufacturing QA)</p></td></tr></tbody></table></div><hr/><h2 id=\"FleetSoftware:Requirements\u2192ServicesMapping-Coveragesummary\">Coverage summary</h2><p><strong>By owning service (primary or shared):</strong></p><ul><li><p><strong>Switchboard (SB)</strong> \u2014 the coordination/identity/state substrate underpins ~30 requirements; it is the <em>first</em> dependency for assignment, isolation, the map/list lenses, intervention, and integration.</p></li><li><p><strong>Backbone (BB)</strong> \u2014 owns global asset registry, device identity, OS-level ops, and OTA/rollout; primary or shared on ~18 requirements (mostly \u00a73 lifecycle/rollout).</p></li><li><p><strong>Insight (INS)</strong> \u2014 the derived-truth plane (Grafana/Loki/Tempo/Mimir + ClickHouse) is primary on the large majority of \u00a72 and the analytics half of \u00a73 (~30 requirements). Spans <strong>fleet</strong> scope (work KPIs, from Switchboard) and <strong>device</strong> scope (health/MTBF, from Backbone) \u2014 the two meet at availability. Derived-only; see <em>Spec: Insight</em>.</p></li><li><p><strong>Fleet Console (FC)</strong> \u2014 the experience layer is shared on most &quot;view,&quot; &quot;dashboard,&quot; &quot;list,&quot; and &quot;tasking&quot; requirements; composition-only.</p></li><li><p><strong>Outpost (OP)</strong> \u2014 owns the entire deployment/identity/network/provisioning cluster (onboarding, multi-tenant segregation, HA, offline).</p></li><li><p><strong>Studio (ST)</strong>, <strong>Reverb (RV)</strong>, <strong>Map (MAP)</strong>, <strong>Coordinator (CO)</strong>, <strong>Optimization Agent (OPT)</strong> \u2014 own the authoring, edge-execution, spatial, workflow-execution, and prioritization concerns respectively.</p></li></ul><p><strong>By status:</strong></p><ul><li><p><strong>Built / Next (pilot path):</strong> identity &amp; isolation, the three actions + lifecycle, coordination &amp; leases, assignment/repurposing/swap, intervention, map &amp; list lenses, WMS integration, SynaOS coexistence floor, workflow execution + simulation, manual charging, remote-control-as-intent, zone/POI definition, network onboarding.</p></li><li><p><strong>Later (post-pilot/scale):</strong> the analytics/BI surface (\u00a72 and analytics \u00a73), autonomous charging, digital twin, predictive maintenance, global rollout/rollback, cross-facility learning, full reporting.</p></li><li><p><strong>Deferred (designed-for, parked):</strong> customer-IdP federation, the full VDA5050 mandatory message set, sub-fleet/group operations.</p></li><li><p><strong>Out (not fleet software):</strong> packaging/unpackaging, power-up/down sequences, EOL testing, removed infrastructure-interaction requirement.</p></li></ul><hr/><h2 id=\"FleetSoftware:Requirements\u2192ServicesMapping-Honestgaps&amp;decisions(theshortlist)\">Honest gaps &amp; decisions (the short list)</h2><p>These are the places where the requirement and the architecture need a conscious decision rather than a clean mapping. Calling them out builds the trust this document is for.</p><ol start=\"1\"><li><p><strong>Sub-fleet / group operations (599, 3731, 322)</strong> mixes two planes: device-management cohorts (OTA, reboot, SSH \u2014 Backbone) and tasking groups (coordinated dispatch \u2014 Switchboard, expressible as affinity on advertised work). It needs a small spec change to split cleanly; we are not adding a monolithic &quot;sub-fleet&quot; object.</p></li><li><p><strong>Scheduling requirements (3737, 3246):</strong> the system is designed for decentralized coordination via Petri nets <em>by default</em> \u2014 and already works this way: robots self-select advertised work, with strong consistency preventing conflicts. That posture prioritizes availability and continuous progress. <strong>Central scheduling is then an optional layer on top:</strong> a deployment that wants more optimality can switch it on, explicitly accepting reduced availability/progress as the trade. So we satisfy the <em>intent</em> (throughput, balance, goals) decentrally, and offer central planning as an opt-in for sites willing to pay the fragility cost \u2014 rather than baking central planning in as the only mode. These requirements may be worth rewording so they don't presuppose it.</p></li><li><p><strong>Remote control (3713)</strong> rides the existing outbound poll channel as recorded operator intent \u2014 fine for tasking commands. <strong>Safety stops (e-stop, go-home in 3253/3741) do not</strong> ride this path \u2014 and the issue isn't poll-vs-push latency, it's that safety cannot depend on the facility network <em>at all</em>. Relying on customer WiFi for a remote stop is unacceptable regardless of channel. Safety belongs to a local, hardware-backed interlock at the edge; any remote stop is best-effort supervision layered on top, never the primary mechanism.</p></li><li><p><strong>Global asset registry (3262)</strong> lives in Backbone, not Switchboard. The unified registry experience the requirement implies is delivered by the Fleet Console composing Backbone (asset) + Switchboard (fleet) \u2014 built &quot;on top, after the fact.&quot;</p></li><li><p><strong>Full VDA5050 (3261)</strong> is a continuum: the pilot delivers heuristic coexistence + occupancy broadcast (floor tier); the full mandatory message set is post-pilot.</p></li><li><p><strong>Metrics readiness (Insight).</strong> The SoW makes the KPI pipeline an acceptance gate (Annex D SAT-09) and ties Availability/OEE to service credits. Most KPIs are event-derived, not raw gauges, so the work between &quot;we have Grafana&quot; and &quot;we pass SAT&quot; is instrumentation: cause-classified downtime, the SoW error taxonomy, autonomy-vs-intervention tagging, station tagging, battery/swap events, network telemetry. See <em>Spec: Insight</em>.</p></li></ol><hr/><p><em>This mapping is a living artifact. Service boundaries (notably Optimization Agent vs Coordinator, and how much of Device-Ops is Backbone vs a distinct plane) are still being refined; the requirement attributions will track those decisions.</em></p>"
        },
        {
          "id": "1672577044",
          "title": "Spec: Insight - Fleet Observability",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1672577044",
          "last_modified": "2026-06-16T17:46:12.816Z",
          "created_at": "2026-02-25T10:37:37.970Z",
          "body_html": "<p local-id=\"e0f804bf29b9\"><strong>Summary</strong>: Insight is the derived-truth plane for fleet software \u2014 the read-only analytics &amp; observability layer that turns the streams every other system emits into what humans and contracts need to <em>see and judge</em>. It spans two scopes (fleet/work and device/hardware) over four stores (Mimir, Tempo, Loki, ClickHouse). It owns no source of truth and never feeds coordination.</p><p local-id=\"a0405106e60d\"><strong>Owner</strong>: Cody Griffin</p><p local-id=\"71d976df2af0\"><strong>Date</strong>: 2026-06-16</p><p local-id=\"1fd271f1abda\"><strong>Status</strong>: Draft v1 \u2014 supersedes the former <em>Core Events (ClickHouse)</em> spec, which becomes Insight's analytical tier.</p><p local-id=\"d554c7008fc7\"><strong>Related</strong>: Observability Stack (Grafana/Loki/Tempo/Mimir) \u00b7 Spec: Switchboard State Model &amp; Fleet Registry \u00b7 Spec: HMND Outpost &amp; Site Authority \u00b7 Fleet Software: Requirements \u2192 Services Mapping \u00b7 Schaeffler Deployment Pilot SoW (Annex D SATs, Annex E KPIs)</p><blockquote local-id=\"451f732b6eb7\"><p local-id=\"0f53f3e0a013\"><strong>Naming note.</strong> &quot;Insight&quot; is a working name for the derived plane; it unifies the existing <em>Observability Stack</em> and <em>Core Events</em> pages under one identity. Alternatives: fold under &quot;Core&quot; (matches the existing &quot;Core observability / Core Events&quot; framing) or &quot;Observability&quot; (undersells the \u00a72/\u00a73 analytics + learning mission). Cheap to rename while it lives in one place.</p></blockquote><h2 local-id=\"6be5b3779d8f\" id=\"Spec:Insight-FleetObservability-1.ProblemStatement\">1. Problem Statement</h2><p local-id=\"2444bd8de34f\">We have the pieces of an observability stack (Grafana/Loki/Tempo/Mimir) and a speculative event store (ClickHouse), but no plane that says what they are <em>for</em>, where their boundaries sit, and how they produce the things the business and the pilot contract actually depend on \u2014 KPIs, SLAs, dashboards, incidents, audit, and (later) the learning corpus. This spec defines that plane. It subsumes the former <em>Core Events (ClickHouse)</em> spec, which becomes Insight's analytical tier (\u00a77, \u00a710).</p><p local-id=\"568ef499f659\">Two pressures make this urgent rather than academic:</p><ul local-id=\"1fb9411496ca\"><li local-id=\"817ca2e05342\"><p local-id=\"fdf578bb1a7a\">The Schaeffler SoW ties service credits and termination to <strong>Fleet Availability</strong> and <strong>OEE</strong>, and <strong>Annex D SAT-09 makes the KPI pipeline itself an acceptance gate</strong> \u2014 at commissioning we must demonstrate correct logging and calculation of KPIs and produce a 24-hour KPI report. The derivation layer has to be real and <em>validated</em> before go-live.</p></li><li local-id=\"56b167e47d4d\"><p local-id=\"d179f1e2e77f\">Most contractual KPIs are <strong>event-derived</strong> (success rate, OEE, UPH, intervention rate, error taxonomy), not raw gauges \u2014 so &quot;we have Grafana&quot; is not the same as &quot;we can compute and defend the numbers.&quot;</p></li></ul><h2 local-id=\"d5a26784535d\" id=\"Spec:Insight-FleetObservability-2.WhatInsightis\u2014thederived-truthinvariant\">2. What Insight is \u2014 the derived-truth invariant</h2><p local-id=\"2f025dd4eff3\"><strong>Switchboard coordinates; Insight observes.</strong> Insight owns no source of truth: it consumes the Switchboard event log, robot/device telemetry, traces, and Cedar authz decisions, and computes dashboards, KPIs/SLAs, alerts, incidents, benchmarking, explainability, and reports. Everything it holds is derived and can always be rebuilt by replaying its sources.</p><p local-id=\"17393be91913\">The hard rule: <strong>Insight never closes the loop.</strong> A dashboard number must never become a dispatch input \u2014 that would re-introduce the central-planning fragility the architecture rejects. Goal\u2192work bias is the Optimization Agent's job, and even that reads facts, not dashboards. Insight writes reports and alerts; it never writes operational state.</p><h2 local-id=\"5432f08b1cbc\" id=\"Spec:Insight-FleetObservability-3.Scope:fleetvsdevice(weneedboth,andtheyaredifferent)\">3. Scope: fleet vs device (we need both, and they are different)</h2><p local-id=\"526673d8a134\">Insight has two source scopes with different owners, identities, tenancy, and consumers. Conflating them is the main way this plane goes wrong.</p><p local-id=\"e71bb8e6366c\"><strong>Fleet scope (work).</strong> Sourced from the Switchboard event log. Answers <em>&quot;what is this fleet producing, and is it meeting the contract?&quot;</em> \u2014 UPH, OEE, task/mission success, intervention rate, task-readiness, the Annex E KPIs. Tenant/fleet-isolated (RLS): a customer sees only their own fleet. Bound to the deployment; relevant for the contract window and audit.</p><p local-id=\"5e1014020bb8\"><strong>Device scope (hardware).</strong> Sourced from device/robot telemetry, rooted in Backbone (device identity is global and long-lived). Answers <em>&quot;what is this chassis doing, and how healthy is it?&quot;</em> \u2014 CPU/mem/thermal/current, uptime, MTBF, faults/diagnostics, component wear, predictive maintenance, spares. Primarily HMND-facing: HMND monitors its whole device fleet's reliability across all customers; a customer sees only the health of devices currently assigned to it. Follows the asset across deployments and customers.</p><div class=\"table-wrap\"><table data-table-width=\"760\" data-layout=\"default\" data-local-id=\"aad609636aac\" class=\"confluenceTable\"><tbody><tr data-local-id=\"f3b4f5e04391\"><th data-local-id=\"ecea0300897a\" class=\"confluenceTh\"><p local-id=\"4eaf4952ddb4\" /></th><th data-local-id=\"50928d07d5de\" class=\"confluenceTh\"><p local-id=\"500846acc306\">Fleet scope</p></th><th data-local-id=\"bc1517007ca9\" class=\"confluenceTh\"><p local-id=\"2ba79ad50960\">Device scope</p></th></tr><tr data-local-id=\"a16f708e194c\"><td data-local-id=\"a7796ce91ec1\" class=\"confluenceTd\"><p local-id=\"d95be0823b80\">Question</p></td><td data-local-id=\"fa2ba16aad8d\" class=\"confluenceTd\"><p local-id=\"434ba77adc59\">What is the fleet producing?</p></td><td data-local-id=\"b2db4791bc69\" class=\"confluenceTd\"><p local-id=\"29abf01cd519\">How healthy is the chassis?</p></td></tr><tr data-local-id=\"9a0df42d1b98\"><td data-local-id=\"7f613807ce1b\" class=\"confluenceTd\"><p local-id=\"82807f651c5d\">Source</p></td><td data-local-id=\"8f70af37764f\" class=\"confluenceTd\"><p local-id=\"b5b0dc4a1d0e\">Switchboard event log</p></td><td data-local-id=\"bf2dc72f6410\" class=\"confluenceTd\"><p local-id=\"8c95261d7c0c\">Device telemetry (Backbone-rooted)</p></td></tr><tr data-local-id=\"220732db1761\"><td data-local-id=\"62e9cbaa73fb\" class=\"confluenceTd\"><p local-id=\"8b30d65cd7e8\">Identity</p></td><td data-local-id=\"6645e4f50139\" class=\"confluenceTd\"><p local-id=\"724c40a0c893\">fleet (rotates per deployment)</p></td><td data-local-id=\"ad30a7fe6402\" class=\"confluenceTd\"><p local-id=\"fd3efadf9e27\">device (durable, global)</p></td></tr><tr data-local-id=\"1ad489db4977\"><td data-local-id=\"7ad3dbe134f0\" class=\"confluenceTd\"><p local-id=\"28926b3d2a20\">Tenancy</p></td><td data-local-id=\"479c2aa1f2b7\" class=\"confluenceTd\"><p local-id=\"fe58adc75e25\">tenant-isolated (RLS)</p></td><td data-local-id=\"17d3d24d133a\" class=\"confluenceTd\"><p local-id=\"c958c06d161b\">HMND-global; customer sees assigned devices only</p></td></tr><tr data-local-id=\"44b1d23d780f\"><td data-local-id=\"5a3c1eafc085\" class=\"confluenceTd\"><p local-id=\"2258d1f8e448\">Consumers</p></td><td data-local-id=\"946c7033df34\" class=\"confluenceTd\"><p local-id=\"d1f426790697\">customer dashboards, SoW KPIs (\u00a71/\u00a72)</p></td><td data-local-id=\"d510dbb5a09f\" class=\"confluenceTd\"><p local-id=\"29ad54c8c8a3\">HMND reliability, maintenance, asset mgmt (\u00a73)</p></td></tr></tbody></table></div><p local-id=\"12f9d66ac837\"><strong>Where the two scopes meet \u2014 availability.</strong> A device fault (device scope) causes fleet downtime (fleet scope). The SoW's Fleet Availability definition <em>excludes</em> non-Supplier causes (network, materials, operator, charging), so to defend the availability number you must attribute each downtime interval to a cause \u2014 and that attribution <strong>is</strong> the join between the two scopes, made through the robot subject (<code>device_ref</code> \u2192 Backbone device id) at the point in time the fault occurred. Availability and MTBF are therefore the canonical place fleet and device meet, and the most contractually load-bearing place in the whole plane. This is the concrete reason we need both: you cannot defend the fleet KPI without the device signal.</p><h2 local-id=\"fe0fe8b6dd46\" id=\"Spec:Insight-FleetObservability-4.Thefourstores\u2014systemvswork\">4. The four stores \u2014 system vs work</h2><p local-id=\"1f899326fc84\">The clean line the existing specs draw: <strong>metrics/logs/traces describe the </strong><em><strong>system</strong></em><strong>; events describe the </strong><em><strong>work</strong></em><strong>.</strong></p><ul local-id=\"f9b5cfda786c\"><li local-id=\"d710e0a2c647\"><p local-id=\"394bd45fddcc\"><strong>Mimir (metrics)</strong> \u2014 low-cardinality system health: availability/uptime, latency p50/p95, comm quality, battery levels, device-telemetry rollups. Real-time, cheap.</p></li><li local-id=\"7710863d79fe\"><p local-id=\"077a2d698394\"><strong>Tempo (traces)</strong> \u2014 per-task lifecycle: the live view, response-time (assign\u2192action) spans, and the drill-down (&quot;show me the trace for this failed pick&quot;). Generates span-metrics into Mimir. Fine at pilot scale; do not tail-sample task traces or success-rate denominators and UPH counts skew.</p></li><li local-id=\"23721382fb09\"><p local-id=\"1370b63fc679\"><strong>Loki (logs)</strong> \u2014 operational logs, audit/RBAC, incident text, safety-event records.</p></li><li local-id=\"e647a8a82a29\"><p local-id=\"da74200c012b\"><strong>ClickHouse (events)</strong> \u2014 high-cardinality, ad-hoc SQL event store. The home for the Switchboard event log and the right engine for the work-outcome KPIs: UPH per station per bearing-range, success rate by error class, OEE quality by good/total over monthly windows. Exactly what Mimir is bad at (cardinality explosion) and what ClickHouse is for.</p></li></ul><p local-id=\"85cc7250ba0f\">All four surface through one Grafana pane. Infra for Mimir/Loki/Tempo/Grafana is specced in <em>Observability Stack</em>; ClickHouse runs in the same footprint (same-host bootstrap, EBS hot / S3 cold), detailed in \u00a710.</p><h2 local-id=\"cf671e92aa89\" id=\"Spec:Insight-FleetObservability-5.TheSwitchboardevent-logseam\">5. The Switchboard event-log seam</h2><p local-id=\"b081eeb40018\">The seam between Switchboard and Insight is the append-only event log. Switchboard events ship (via Vector) into the ClickHouse <code>events</code> table; Switchboard dimensions (<code>instance_id</code>, <code>transition</code>, <code>conformant</code>, <code>subject_id</code>, <code>station</code>, <code>error_class</code>, autonomy flag, cause-of-downtime) live in <code>attrs</code> and are promoted to columns when they get hot. That is the same <strong>arbitrary \u2192 registered \u2192 promoted</strong> evolution the Switchboard fact table uses (A.2) and the same model ClickHouse uses for <code>attrs</code> \u2192 column \u2014 one doctrine across the stack, so the pipeline scales without a schema rewrite.</p><p local-id=\"4ac51d485af2\"><code>trace_id</code> is the universal join: one id correlates a ClickHouse event \u2194 a Tempo trace \u2194 Loki logs \u2194 the Cedar authz decision. That correlation <strong>is</strong> explainability and replay.</p><h2 local-id=\"a720020031a1\" id=\"Spec:Insight-FleetObservability-6.KPIderivation(Schaefflerpilot)\">6. KPI derivation (Schaeffler pilot)</h2><ul local-id=\"09bda491f5c2\"><li local-id=\"0dc10343ea79\"><p local-id=\"a69c6edd7e47\"><strong>Work-outcome KPIs</strong> (success rate, OEE quality, UPH, intervention rate, error taxonomy) \u2014 ClickHouse SQL over the event log. High-cardinality, monthly windows.</p></li><li local-id=\"4efbf187e5e4\"><p local-id=\"ec8825425b41\"><strong>System-health KPIs</strong> (Fleet Availability, uptime, latency, comm quality, battery) \u2014 Mimir time-series; availability needs <strong>cause-classified downtime events</strong> (a ClickHouse event with cause in <code>attrs</code>, plus a Mimir uptime series).</p></li><li local-id=\"dd923e56330d\"><p local-id=\"bd98e4a39191\"><strong>Response time</strong> (assign\u2192action) \u2014 Tempo span \u2192 Mimir.</p></li><li local-id=\"11ba61941628\"><p local-id=\"325063f468b7\"><strong>The 24-hour SAT-09 report and the monthly contractual numbers</strong> read from materialized ClickHouse aggregates + Mimir series \u2014 not raw-trace scans. Traces are the per-task substrate and the dispute drill-down, not the monthly aggregation engine.</p></li></ul><p local-id=\"6d133294ef4a\"><strong>Instrumentation that must exist for the above (gaps today):</strong> cause-classified downtime, the SoW error taxonomy on pick/place outcomes, autonomy-vs-intervention tagging per task, station tagging on completions, battery/swap events, and a robot-side network exporter. Transport (Tempo/events) is not instrumentation \u2014 Reverb/Switchboard must emit these attributes regardless of sink.</p><h2 local-id=\"e23203aba476\" id=\"Spec:Insight-FleetObservability-7.Retentionhorizons\">7. Retention horizons</h2><p local-id=\"4650813f8ab4\">Three horizons; the former ClickHouse spec covers only the middle:</p><ul local-id=\"b88781fccdbd\"><li local-id=\"f44f48544890\"><p local-id=\"437f1f49340c\"><strong>Live</strong> (Grafana stack) \u2014 days\u2013weeks; real-time ops and alerting.</p></li><li local-id=\"a12113bcfbb0\"><p local-id=\"d0f4a77429a5\"><strong>Analytical</strong> (ClickHouse) \u2014 1 day hot \u2192 S3 cold, <strong>180-day delete as currently specced</strong>. Covers the full pilot and the May\u2013Nov tracking window, but is <em>not</em> the forever-record.</p></li><li local-id=\"880bbb0dde9e\"><p local-id=\"1bb836edf069\"><strong>Archive / learning</strong> (lakehouse / Parquet on S3) \u2014 forever; audit, cross-facility learning, training corpus (\u00a73 reqs 3273/3304). Currently out of scope; needed when the forever/learning mission lands. Note the tension against Switchboard's &quot;event log is forever-history&quot; doctrine \u2014 the analytical TTL must be reconciled with that, or archival must catch what ClickHouse drops.</p></li></ul><h2 local-id=\"3db6c5cceb22\" id=\"Spec:Insight-FleetObservability-8.Boundarieswithneighbours\">8. Boundaries with neighbours</h2><ul local-id=\"c76710b748bf\"><li local-id=\"f142403698c8\"><p local-id=\"aaf8f3f59d67\"><strong>Switchboard</strong> \u2014 source and seam; Insight is read-only on it.</p></li><li local-id=\"a9ecda74d003\"><p local-id=\"4e4bc61704be\"><strong>Backbone</strong> \u2014 owns device identity and the device-telemetry feed; Insight ingests it for the device scope and the global asset/health view.</p></li><li local-id=\"9ac7d7f76525\"><p local-id=\"628dee8809de\"><strong>Console / Fleet API</strong> \u2014 presentation vs computation. At pilot scale Grafana <em>is</em> the ops console; at scale the Console composes Insight's outputs into the customer/global product. Overlap resolves with growth.</p></li><li local-id=\"7ff0c0546108\"><p local-id=\"f27b682c9511\"><strong>Optimization Agent</strong> \u2014 may read Insight aggregates (utilisation, congestion) to set bias, but the loop stays advisory and off the critical path.</p></li><li local-id=\"6ba0fceaae67\"><p local-id=\"d851848a0f21\"><strong>Outpost</strong> \u2014 already names cloud as &quot;a mirror and analytics plane&quot;; Insight is structurally the cloud-side sink of the upward sync, and must be stale-aware (Outpost's shadow-vs-live warning). Under site authority, telemetry/events are emitted locally and streamed up.</p></li></ul><h2 local-id=\"120071d4f6fc\" id=\"Spec:Insight-FleetObservability-9.Scale&amp;multi-tenancy\">9. Scale &amp; multi-tenancy</h2><p local-id=\"402a8420ea66\">Pilot is single-tenant (one customer, one site) and the current single-node footprint is fine. Scale (\u00a72/\u00a73 of the requirements) forces the multi-tenant authz the Core Events spec deferred \u2014 and the <strong>fleet-vs-device split is exactly what forces it</strong>: fleet analytics must be tenant-partitioned (a customer sees only their fleet), while device health is HMND-global with customer-scoped views (a customer sees only its assigned devices). Per Outpost's data-segregation rule, cloud analytics may be multi-tenant internally while the control plane preserves tenant boundaries. Cross-customer benchmarking and the learning pipeline live here and are HMND-internal by construction.</p><h2 local-id=\"0c3dbd1318d8\" id=\"Spec:Insight-FleetObservability-10.Analyticaltier\u2014ClickHouseevents(inheritedfromCoreEvents)\">10. Analytical tier \u2014 ClickHouse events (inherited from Core Events)</h2><p local-id=\"36c0757d214c\">ClickHouse adds the high-cardinality, SQL-queryable event store to the observability footprint (hot on EBS, cold on S3), exposed to Grafana. It <strong>complements</strong> Loki/Tempo/Mimir; it does not replace them.</p><p local-id=\"840449db244c\"><strong>Topology (initial).</strong> Same EC2 host as Grafana/Loki/Tempo/Mimir for bootstrap (share <code>/var/lib/observability</code> EBS); move to a dedicated instance only if resource contention appears. Same ALB/Nginx front-door pattern and S3 bucket.</p><p local-id=\"9e7bd47f1919\"><strong>Storage.</strong> MergeTree with a <code>hot_cold</code> policy \u2014 hot on local EBS, cold on S3 via a ClickHouse S3 disk. Inserts land hot; TTL moves merged parts to S3.</p><p local-id=\"b4313c1e47e0\"><strong>Ingestion.</strong> Robots and Core services emit events; Vector forwards over HTTP with <code>async_insert=1</code>, <code>wait_for_async_insert=0</code>, minimal client batching (0.5\u20132s or N events) to keep events visible fast while coalescing server-side.</p><p local-id=\"f1cb43f89015\"><strong>Event contract.</strong> Required: <code>ts</code>, <code>robot_id</code>, <code>robot_type</code>, <code>event_name</code>, <code>severity</code>, <code>attrs</code>. Recommended: <code>trace_id</code>, <code>span_id</code>, <code>workflow_id</code>, <code>task_id</code>, <code>schema_ver</code>. Design principle: low-cardinality fields become columns; high-cardinality/unknown fields live in <code>attrs</code>. The contract carries <strong>both scopes</strong> \u2014 device events are <code>robot_id</code>-keyed; work/fleet events add <code>workflow_id</code>/<code>task_id</code>/<code>instance_id</code>/<code>subject_id</code>/<code>station</code>/<code>error_class</code>/<code>cause</code> (in <code>attrs</code>, promoted to columns when hot).</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"e983fddc-e6f3-47a4-9824-fe501e9a6a82\" data-local-id=\"055cb52936f7\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: sql; gutter: false; theme: Confluence\" data-theme=\"Confluence\">CREATE TABLE events\n(\n  ts           DateTime64(3, 'UTC'),\n  ingest_ts    DateTime64(3, 'UTC') DEFAULT now64(3),\n\n  robot_id     String,\n  robot_type   LowCardinality(String),\n\n  event_name   LowCardinality(String),\n  severity     LowCardinality(String) DEFAULT 'info',\n\n  trace_id     String DEFAULT '',\n  span_id      String DEFAULT '',\n\n  schema_ver   UInt16 DEFAULT 1,\n\n  attrs        Map(LowCardinality(String), String),\n\n  event_id     UUID DEFAULT generateUUIDv4()\n)\nENGINE = MergeTree\nPARTITION BY toDate(ts)\nORDER BY (robot_type, robot_id, event_name, ts)\nTTL\n  ts + INTERVAL 1 DAY TO VOLUME 'cold',\n  ts + INTERVAL 180 DAY DELETE\nSETTINGS\n  storage_policy = 'hot_cold',\n  index_granularity = 8192;</pre>\n</div></div><p local-id=\"c0eaa08b148f\"><strong>Compaction.</strong> Background merges combine small parts on EBS; run <code>OPTIMIZE TABLE events FINAL;</code> off-peak (daily is typically enough at low rate) to avoid small-object pathologies in S3.</p><p local-id=\"0bac2f0875ee\"><strong>Access &amp; security.</strong> Not exposed directly to the internet; private networking + optional ALB/Nginx front door. Grafana datasource credential in Terraform/Secrets Manager; Vector ingestion via basic auth (mTLS later).</p><h2 local-id=\"673b969e3433\" id=\"Spec:Insight-FleetObservability-11.Knownlimitations&amp;scalingpath\">11. Known limitations &amp; scaling path</h2><ul local-id=\"af6c5796cdd5\"><li local-id=\"39a3e62673ce\"><p local-id=\"9c702fbceb4b\"><strong>Single-node</strong> ClickHouse: instance failure loses hot cache and short-term unshipped parts. Acceptable for bootstrap/pilot; revisit for fleet scale.</p></li><li local-id=\"cb2ac911833a\"><p local-id=\"3dfd7065e5e6\"><strong>Multi-tenant authz deferred</strong> in Core Events \u2014 but \u00a79 shows the fleet-vs-device split is what brings it back for scale; treat as the first scale-up work item.</p></li><li local-id=\"10e19ac99191\"><p local-id=\"a0c80df2923b\"><strong>Alerting/SLOs are future work</strong> in the Observability Stack, yet the SoW SLA has Sev-1 response \u226410 min \u2014 incident detection/paging must exist for the pilot regardless.</p></li><li local-id=\"6cdeff333c0d\"><p local-id=\"0cc7fe1c5811\"><strong>Scaling path:</strong> single instance + EBS hot + S3 cold + one <code>events</code> table \u2192 dedicated instance/ECS later, keeping the table definition, storage policy, S3 cold tier, and Grafana datasource. No schema or pipeline rewrite.</p></li></ul>"
        },
        {
          "id": "2080407559",
          "title": "Spec: Studio \u2014 System-3 Agents for Workflow Operations & Deployment",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2080407559",
          "last_modified": "2026-06-10T14:23:03.407Z",
          "created_at": "2026-06-10T14:01:18.336Z",
          "body_html": "<h1 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment\">Spec: Studio \u2014 System-3 Agents for Workflow Operations &amp; Deployment</h1><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-1.ProblemDefinition\">1. Problem Definition</h2><p>The Switchboard spec makes the coordinator deliberately dumb: it answers queries, serializes coordination state, and holds no intelligence. That is the right design, and it creates an obligation \u2014 the intelligence has to live somewhere. Studio is that somewhere: the System-3 plane where agents reason about a deployment and act on it, always <em>through</em> Switchboard's API as authorized principals, never beside it.</p><p>We are not starting from zero. The workflow authoring prototype has already demonstrated the core loop end-to-end: natural-language intent in, validated multi-robot workflow out, with a symbolic simulator closing the verification loop. Running that agent in an eval-driven improvement loop over a single weekend took a 7-task suite from 57% to 100% pass, with median prompt-to-successful-workflow time around 30 seconds \u2014 including scenarios that build complex two- and three-robot workflows from an empty map. Product has run Symphony demos end-to-end without engineering in the room, including recording a new workflow and agentically editing it. The prototype proved the concept, built the verification machinery, and \u2014 through its eval suite \u2014 told us precisely where the capability frontier is. This spec is about industrializing that: splitting the prototype's two jobs into two agents, raising the natural-language bar from &quot;engineer-crafted prompt&quot; to &quot;operator sentence,&quot; and making evaluation the mechanism by which these agents earn autonomy.</p><p>Three observations drive the design:</p><p><strong>The prototype does two jobs, and they want different containment.</strong> The same agent session edits workflow source <em>and</em> operates live state (pushing runtime facts, resetting markings, editing workflows mounted on robots). The team correctly recognized the risk and added a coordinator-side guard that blocks edits to robot-loaded workflows \u2014 the right instinct, implemented at the only seam available. This spec gives that instinct an architecture: two agents with disjoint capabilities, so the guard becomes structural rather than a check.</p><p><strong>Operating is as agent-shaped a problem as editing.</strong> During a recent investor demo, a robot stuck on the vinyl floor was given &quot;fail task&quot; instead of a teleop intervention, and the failure handling left the coordinator in a stuck state; the demo was abandoned. Diagnosing <em>why a transition won't fire</em> and <em>how to safely unstick coordination state</em> is exactly the kind of structured, tool-mediated reasoning an agent does well \u2014 and today it lives in the heads of two or three engineers.</p><p><strong>The prompts are the product gap.</strong> Today, successfully driving the authoring agent requires carefully engineered requests \u2014 naming candidate workflow IDs, exact map tags, state naming conventions, which tool to prefer. That defeats the purpose. The bar is <strong>natural language from a non-domain expert</strong>: &quot;make the robot bring totes from that stack to the table, three of them&quot; should work; so should &quot;why has robot 2 been standing there for five minutes.&quot; Recent eval additions (vague prompts, empty-map-to-complex-workflow) point exactly at this bar; this spec makes it the headline requirement.</p><p>The anchor remains the Schaeffler pilot: operators expressing intent conversationally, remote uptime management over flaky links, and workflow evolution on a live deployment without resetting the fleet.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-2.WhatStudioIs\">2. What Studio Is</h2><p>Studio is the collection of System-3 agents that act on a deployment, plus the substrate they share: the intent log, the authoring workspace, the capability catalog, the evaluation harness, and the chat/UI surfaces. Two agents exist at MVP; the architecture admits more (a conformance/analytics agent is the obvious third).</p><ul><li><p>The <strong>Operator agent</strong> acts on <em>running instances</em>: diagnosing blocked transitions, injecting work, intervening on leases, resolving quarantined or stuck tokens, recording operator-directed deviations.</p></li><li><p>The <strong>Deployment agent</strong> acts on <em>definitions</em>: turning intent into validated workflow source edits, publishing versions, and authoring the migrations that move live instances between versions.</p></li></ul><p>Implementation shape: Switchboard is Rust; <strong>Studio agents are Python services</strong> speaking to Switchboard exclusively through its HTTP/JSON API via a thin typed client. Studio holds what Switchboard deliberately doesn't \u2014 agent context, drafts, intent history, reasoning \u2014 and holds none of what Switchboard does: Studio is never a second coordinator, never caches authoritative state, and every effect on shared state lands through the API, is authorized by Cedar, hits RLS, and is recorded in both audit logs.</p><p>In the Sockpuppet intervention tiering, these agents are System-3 intervenors: latency-tolerant, working entirely on Switchboard's replicated state, above remote-embodiment teleop and below nothing except humans. Deployment-by-demonstration (Sockpuppet recording \u2192 coordinator upload) remains the <em>origin</em> of many workflows; Studio is how they evolve afterward. The on-robot reactive stack \u2014 VLA policies and the visual/perception oracle that, for example, scans a shelf and reports which totes are where \u2014 is <strong>System-2</strong>; Studio's agents invoke those System-2 capabilities as grounding (\u00a78.1) but never replace them.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-3.TheTwoAgentsandtheBoundaryBetweenThem\">3. The Two Agents and the Boundary Between Them</h2><p>The split is real on three axes, not an implementation preference:</p><p><strong>Blast radius and time constant.</strong> The Operator agent acts on the strong core \u2014 markings and leases \u2014 with immediate physical-world consequences, bounded by machinery Switchboard already provides: leases serialize dispatch, conformance is advisory-and-loud, exceptions degrade-and-flag. The Deployment agent's mistakes manifest at publish/migration time and are bounded by validation, human approval, and quarantine.</p><p><strong>Grading shape.</strong> The Deployment agent is graded like a coding agent: mostly deterministic checks (does the source evaluate, do the traces replay, do the invariants hold). The Operator agent is graded like an intervention agent: a simulated deployment with an injected fault, judged on the resulting state plus how it got there. Two eval suites exist whatever we do \u2014 itself evidence these are two agents.</p><p><strong>Context discipline.</strong> A single context holding both &quot;edit the definition&quot; and &quot;poke the live instance&quot; tools will, under pressure, fix a definition bug by mutating a running marking, or &quot;fix&quot; a stuck robot by hot-editing the workflow. The separation enforces on agents the same discipline the State Model enforces on the system:</p><blockquote><p><strong>The only path from a definition change to a running instance is an explicit, validated migration. The only path from a runtime observation to a definition change is the intent log.</strong></p></blockquote><p>Concretely: one agent harness, one model family, <strong>two principals, two tool mounts, two contexts, two state models (\u00a76).</strong> A conversation is either an operating conversation or an editing conversation. When a fault needs a definition fix, the Operator agent files an intent (\u00a711); it does not open an editor.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-4.NaturalLanguageIstheBar\">4. Natural Language Is the Bar</h2><p>This is a product requirement with architectural consequences, so it gets its own section.</p><p><strong>The requirement.</strong> A non-domain expert must be able to deploy and operate workflows with ordinary language. They will not know map tag names, state naming conventions, work-item vocabulary, candidate-ID discipline, which policies exist, or which verification step to run. Every piece of knowledge the user currently has to put <em>into the prompt</em> must move into one of three places:</p><ol start=\"1\"><li><p><strong>The source format</strong> \u2014 the new-form Starlark (\u00a75) is legible enough that structure the agent used to be told about in prose is now visible in the artifact it reads.</p></li><li><p><strong>Tools and validators</strong> \u2014 invariants that used to be prompt rules (&quot;never invent a tag name&quot;, &quot;all robot states start with Robots&quot;, &quot;validate before claiming validity&quot;) become hard checks: a reference to a nonexistent place is a validation rejection, not a behavioral guideline.</p></li><li><p><strong>Retrieved context</strong> \u2014 map tags, payload schemas, seeds, the capability catalog, scene context, and recent history are assembled by the harness per turn (\u00a78), not recited by the user.</p></li></ol><p><strong>The behavioral contract for vague input.</strong> Given an underspecified intent, the agent does exactly one of three things:</p><ul><li><p><strong>Proceed</strong> with stated assumptions when the gap is inconsequential (&quot;I'll use three totes since three are on the stack&quot;).</p></li><li><p><strong>Ask one question</strong> when the gap is consequential and answerable (&quot;two tables here \u2014 which one?&quot;). One question, not a form.</p></li><li><p><strong>Refuse with a reason</strong> when the request depends on something the deployment doesn't have \u2014 a place not on the map, an object property nothing senses, a capability no policy provides or a question the visual oracle can't answer (all checked against the map and the capability catalog, \u00a78.1). Refusal happens <em>before</em> any mutation. The prototype's refusal discipline (verify feasibility before copying or editing) already implements this and carries forward.</p></li></ul><p>What the agent must never do: silently map unsupported phrases onto the nearest available concept, or invent facts (weights, colors, locations) or policies to make a request feasible. The prototype's prompt encodes this well; the target architecture enforces it with graders (Appendix A's refusal scenarios) rather than prose alone.</p><p><strong>The measurement.</strong> Every Deployment-agent eval task carries intent variations across <strong>specificity tiers</strong> \u2014 from engineer-precise (&quot;copy X to candidate Y, move three seeded tote tokens from stack1 to table1/left&quot;) down to operator-natural (&quot;get the totes from that stack onto the table&quot;). Tier-3 (vague) pass rate is the product metric; tier-1 pass rate is the floor. The recent vague-prompt eval additions are the first instance of this and become the pattern.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-5.TheWorkflowArtifact\">5. The Workflow Artifact</h2><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-5.1Theagenteditsthethingthatmatters\">5.1 The agent edits the thing that matters</h3><p>The new-form Starlark workflow (the robostore port is the reference example) is deliberately <strong>low-abstraction</strong>: work items own their states; tasks declare token flow per alias with three verbs (<code>move</code>, <code>hold</code>, <code>drop</code>); guards are plain named functions over bound token payloads; dynamic values (a shelf tag derived from a basket's payload) are ordinary functions passed as params; payload shapes are declared with <code>token_schema</code> and closed with <code>allow_extra = False</code>; <code>referenced_map_places</code> declares the map dependency. One screenful per concern, no codegen layers, no string-embedded expression language.</p><p>This settles the artifact question: <strong>the Deployment agent edits this source directly.</strong> Not an abstracted projection of it, not a parallel semantic model, not generated YAML. The source is the thing that matters, and it is now legible enough for both a model and a human reviewer to read a diff of it and understand the change. Patches are source diffs; the snapshot is <code>(source, evaluated net, canonical_hash)</code> plus seed; evaluation is hermetic and deterministic, so snapshot regeneration is <code>evaluate()</code>, never an agent call.</p><p>Two design consequences worth stating explicitly for implementers:</p><ul><li><p><strong>The prelude stays thin.</strong> <code>work_item</code>, <code>token_schema</code>, <code>state</code>, <code>task</code>, <code>move</code>/<code>hold</code>/<code>drop</code>, <code>workflow</code> \u2014 plus, sparingly, helpers for patterns that have proven genuinely recurrent. Resist growing a macro tower: every layer of abstraction between the agent and the net is a layer it can misunderstand. Where the YAML-era prototype needed a heavyweight mutation tool (counted transfers, completion gates), the question is first &quot;does the new source format make this pattern short enough to just write?&quot; before &quot;should this be a prelude helper?&quot; \u2014 and never &quot;should this be an out-of-band mutation tool.&quot;</p></li><li><p><strong>Schemas and guard-functions make the old failure modes checkable.</strong> The prototype's eval analysis identified the dominant authoring failures: invented guard helpers, payload fields nothing writes, object lifecycles that look right but don't carry tokens. Closed <code>token_schema</code>s plus guards-as-functions turn most of these into evaluation-time or validation-time errors: a guard referencing a misspelled payload field fails against the schema; a payload field no task or seed ever sets is a lint; the token-flow verbs make the lifecycle explicit in the artifact rather than implicit in input/output plumbing. This is the prototype's hardest-won lesson \u2014 <em>put the domain invariants where the agent can't violate them</em> \u2014 carried from its semantic tool layer into the format itself.</p></li></ul><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-5.2Whattheprototype&#39;stoolingbecomes\">5.2 What the prototype's tooling becomes</h3><p>The prototype's tool surface was built for a YAML world and it earned its keep there; in the Starlark world its roles redistribute rather than disappear:</p><ul><li><p><strong>Grounding tools survive intact</strong>: list workflows, query structure, <code>get_map_tags</code> (the only legitimate source of place names), list seed robots/roles, read schemas, and read the capability catalog (\u00a78.1). These feed context assembly (\u00a78).</p></li><li><p><strong>Verification tools survive intact and become the spine</strong>: evaluate, validate, symbolic-simulate, and (new) trace replay. The prototype's discipline \u2014 validate after structural edits, simulate after behavioral edits, treat a failed simulation as a failed edit \u2014 graduates from prompt rules into harness enforcement: a patch that hasn't passed validation and simulation cannot be <em>proposed</em>, whatever the model says.</p></li><li><p><strong>The render/review surfaces survive intact</strong>: the diagram, diagram-diff, YAML/source-diff, simulation player, and map-tag views are the human approval UI. This was prescient work \u2014 the tier-4 approval gate (\u00a79.2) is &quot;a human looks at exactly these.&quot;</p></li><li><p><strong>The undo journal and workspace survive intact</strong>: turn-scoped undo with snapshot verification, and the disk workspace, generalize into the Studio draft workspace \u2014 per-session, branchable, keyed off the intent log.</p></li><li><p><strong>Imperative semantic mutation tools shrink</strong> to mechanical operations a text edit does badly (copy/branch a draft, rename-with-references) \u2014 because the source is now the editing surface.</p></li></ul><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-5.3Drafts,publishing,migration\">5.3 Drafts, publishing, migration</h3><p>Drafts live in <strong>Studio, not Switchboard</strong>. Switchboard's workflow table remains append-only published versions; the registry stays data; the coordination plane stays dumb. The flow (formalized as a state machine in \u00a76):</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"a370a538-3517-4a5d-8fcd-cde59784ebd2\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">intent \u2192 draft branch \u2192 edit source \u2192 evaluate \u2192 validate \u2192 simulate/replay\n       \u2192 present (diff + checklist + replay results) \u2192 human approves\n       \u2192 publish version (PUT /v1/workflows/$id?from=$ver)\n       \u2192 [if live instances] author migration mapping \u2192 human approves \u2192 Switchboard applies</pre>\n</div></div><p>Publishing changes nothing running. The Deployment agent authors the <strong>migration mapping</strong> (old places \u2192 new places) for live instances; the mapping is itself a verified artifact \u2014 every live token either maps or is <em>deliberately</em> quarantined with a reason, checked symbolically and by replaying the drain path on a simulated instance seeded with the production marking. A mapping without total token coverage never reaches the human. <code>Migrate</code> is held by neither agent: the Deployment agent proposes, a human approves, Switchboard applies mechanically.</p><p>Runtime-backed editing of mounted workflows \u2014 the prototype mode the <code>approval_required</code> guard was built to police \u2014 is superseded by this flow. The guard's instinct was right; the architecture now delivers it by construction. Similarly, &quot;edit seed then reset-from-seed&quot; is recognized for what it is: applying a seed to a live instance rewrites markings, which is an <em>operating</em> action (a forced migration to the initial marking) and moves to the Operator agent's mount, gated accordingly.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-6.AgentStateModels\">6. Agent State Models</h2><p>The two agents have <strong>two distinct state models that share exactly one object: the intent log.</strong> This section gives the Deployment agent's <em>edit lifecycle</em> (\u00a76.1\u20136.4) and the Operator agent's <em>intervention lifecycle</em> (\u00a76.5), then states precisely what is shared and what is not (\u00a76.6). Naming the states matters because at any moment it must be unambiguous what an edit or an intervention <em>is</em>, what is true of it, who can move it forward, and what moving it costs.</p><p>The Deployment edit lifecycle has four sub-lifecycles \u2014 two Studio objects (the <strong>intent</strong>, the <em>why</em>; the <strong>patch</strong>, the <em>what</em>) that produce two Switchboard objects (the <strong>version</strong>, an immutable definition; the <strong>migration</strong>, how live instances adopt a version). The governing rule, restated from \u00a73 as a lifecycle property: <strong>publish and migrate are two distinct, separately-gated transitions.</strong> A new definition existing, and that definition running on the floor, are different events with different failure modes, and the lifecycle keeps them apart on purpose.</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-6.1Patchstates(Deployment)\">6.1 Patch states (Deployment)</h3><p>A <em>patch</em> is a proposed change to workflow source, motivated by one or more intents.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>State</p></th><th class=\"confluenceTh\"><p>What it represents</p></th><th class=\"confluenceTh\"><p>Invariant while here</p></th><th class=\"confluenceTh\"><p>Leaves via</p></th></tr><tr><td class=\"confluenceTd\"><p><code>draft</code></p></td><td class=\"confluenceTd\"><p>source edited on a branch</p></td><td class=\"confluenceTd\"><p>nothing is promised; the agent may still be iterating</p></td><td class=\"confluenceTd\"><p>submit to validation \u2192 <code>validated</code></p></td></tr><tr><td class=\"confluenceTd\"><p><code>validated</code></p></td><td class=\"confluenceTd\"><p>passed validation tiers 1\u20133 (\u00a79.2)</p></td><td class=\"confluenceTd\"><p>machine-checked: evaluates, traces replay, diff in scope</p></td><td class=\"confluenceTd\"><p>freeze for review \u2192 <code>proposed</code>; <strong>any further edit \u2192 </strong><code>draft</code></p></td></tr><tr><td class=\"confluenceTd\"><p><code>proposed</code></p></td><td class=\"confluenceTd\"><p>frozen and presented for human approval (tier 4, \u00a79.2)</p></td><td class=\"confluenceTd\"><p>source locked; validation evidence + rendered diff/replay attached</p></td><td class=\"confluenceTd\"><p>human approves \u2192 <code>approved</code>; rejects \u2192 <code>rejected</code>; author pulls \u2192 <code>withdrawn</code></p></td></tr><tr><td class=\"confluenceTd\"><p><code>approved</code></p></td><td class=\"confluenceTd\"><p>a human accepted it</p></td><td class=\"confluenceTd\"><p>transient; proceeds immediately to publish</p></td><td class=\"confluenceTd\"><p>publish API call \u2192 <code>published</code></p></td></tr><tr><td class=\"confluenceTd\"><p><code>published</code></p></td><td class=\"confluenceTd\"><p>committed: an immutable Switchboard <strong>version</strong> now exists</p></td><td class=\"confluenceTd\"><p>the patch is now history; the live artifact is the version; <strong>nothing running has changed</strong></p></td><td class=\"confluenceTd\"><p>terminal (for the patch)</p></td></tr><tr><td class=\"confluenceTd\"><p><code>rejected</code></p></td><td class=\"confluenceTd\"><p>human declined, with reason</p></td><td class=\"confluenceTd\"><p>terminal</p></td><td class=\"confluenceTd\"><p>usually spawns a follow-up intent or a fresh draft</p></td></tr><tr><td class=\"confluenceTd\"><p><code>withdrawn</code></p></td><td class=\"confluenceTd\"><p>author/agent pulled it (stale/superseded)</p></td><td class=\"confluenceTd\"><p>terminal</p></td><td class=\"confluenceTd\"><p>\u2014</p></td></tr></tbody></table></div><p>Cross-cutting invariants: a patch cannot be <code>proposed</code> unless <code>validated</code>; cannot be <code>published</code> unless <code>approved</code>; <strong>validation is not sticky</strong> \u2014 any edit after <code>validated</code> returns it to <code>draft</code>; publishing creates a version but changes nothing running.</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-6.2Migrationstates(Deployment)\">6.2 Migration states (Deployment)</h3><p>Publishing a version with live instances does not move them. The migration is its own proposable, approvable artifact.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>State</p></th><th class=\"confluenceTh\"><p>What it represents</p></th></tr><tr><td class=\"confluenceTd\"><p><code>mapping_draft</code></p></td><td class=\"confluenceTd\"><p>agent authoring the old-places \u2192 new-places mapping for a target set of live instances</p></td></tr><tr><td class=\"confluenceTd\"><p><code>mapping_validated</code></p></td><td class=\"confluenceTd\"><p>total token coverage (every live token maps, or is deliberately quarantined-with-reason) + drain-path replay on a sim instance seeded with the production marking</p></td></tr><tr><td class=\"confluenceTd\"><p><code>mapping_proposed</code></p></td><td class=\"confluenceTd\"><p>presented for human approval</p></td></tr><tr><td class=\"confluenceTd\"><p><code>migrating</code></p></td><td class=\"confluenceTd\"><p>approved; Switchboard applying mechanically</p></td></tr><tr><td class=\"confluenceTd\"><p><code>migrated</code></p></td><td class=\"confluenceTd\"><p>instances now run the new version; recorded as <code>__migrate__</code> events stamped with the mapping + approver</p></td></tr></tbody></table></div><p>A version with no live instances skips this entirely \u2014 publish suffices.</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-6.3Intentstates(shared)\">6.3 Intent states (shared)</h3><p>The intent record (its natural-language text + evidence) is immutable; its <em>status</em> is derived from what references it, plus an appended decision marker. <code>open</code> (recorded, unaddressed) \u2192 <code>addressed</code> (a draft/patch cites it) \u2192 <code>implemented</code> (a published version cites it), or <code>declined</code> (closed with a reason, no version). Append-only purity is preserved: we never mutate the text, only append references and decisions. The intent is the one object both agents touch (\u00a76.6).</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-6.4Thewholeeditchain\">6.4 The whole edit chain</h3><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"0581f500-49be-4b28-8a17-986e9a078714\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">intent:open\n  \u2192 patch:draft \u2192 patch:validated \u2192 patch:proposed \u2192 [HUMAN GATE] \u2192 patch:approved\n    \u2192 version:published                       \u2190 nothing running changes\n      \u2192 migration:mapping_draft \u2192 mapping_validated \u2192 mapping_proposed \u2192 [HUMAN GATE]\n        \u2192 migrating \u2192 migrated                \u2190 instances now on the new version</pre>\n</div></div><p>Two human gates (patch approval, migration approval); <code>Migrate</code> is held by neither agent (\u00a713). Operator-agent interventions are <strong>not on this chain at all</strong> \u2014 they act on the markings and leases of a single live instance and never produce a version (their own lifecycle is \u00a76.5). That is the entire point of the two-agent split (\u00a73): the chain above is the <em>only</em> way a definition changes, and it is disjoint from the way a running instance is nudged.</p><p>Mapped to the intuitive <code>intended \u2192 validated \u2192 proposed \u2192 applied</code>: it holds, with one deliberate refinement \u2014 <strong>&quot;applied&quot; is two gated steps, </strong><code>published</code> then <code>migrated</code> \u2014 because otherwise &quot;I shipped the new workflow&quot; and &quot;the floor is running it&quot; collapse into one word, and those are different states with different things that go wrong.</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-6.5Theinterventionlifecycle(Operator)\">6.5 The intervention lifecycle (Operator)</h3><p>The Operator agent's unit of work is a <em>session</em> against one live instance, opened by a trigger (\u00a710.3). It has its own states, none of which ever produce a version:</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>State</p></th><th class=\"confluenceTh\"><p>What it represents</p></th><th class=\"confluenceTh\"><p>Invariant while here</p></th></tr><tr><td class=\"confluenceTd\"><p><code>triggered</code></p></td><td class=\"confluenceTd\"><p>an operator question, an exception flag, or a scheduled sweep opened a session</p></td><td class=\"confluenceTd\"><p>read-only</p></td></tr><tr><td class=\"confluenceTd\"><p><code>diagnosing</code></p></td><td class=\"confluenceTd\"><p>investigation: query lenses, event log, eligibility-explain, and optionally a visual query (\u00a78.1)</p></td><td class=\"confluenceTd\"><p>read-only; no mutation</p></td></tr><tr><td class=\"confluenceTd\"><p><code>diagnosed</code></p></td><td class=\"confluenceTd\"><p>a root-cause hypothesis + a proposed action at the current autonomy tier</p></td><td class=\"confluenceTd\"><p>read-only</p></td></tr><tr><td class=\"confluenceTd\"><p><code>proposed</code></p></td><td class=\"confluenceTd\"><p>a mutating action awaiting its gate (confirm-per-action or human approval), when the tier requires one</p></td><td class=\"confluenceTd\"><p>nothing mutated yet</p></td></tr><tr><td class=\"confluenceTd\"><p><code>acting</code></p></td><td class=\"confluenceTd\"><p>executing the mutating action (intervene / inject / resolve / reset / deviate)</p></td><td class=\"confluenceTd\"><p>the one mutating window</p></td></tr><tr><td class=\"confluenceTd\"><p><code>verifying</code></p></td><td class=\"confluenceTd\"><p>re-reading state to confirm the fix took (token unstuck, lease single-granted, instance progressing)</p></td><td class=\"confluenceTd\"><p>read-only</p></td></tr><tr><td class=\"confluenceTd\"><p><code>resolved</code></p></td><td class=\"confluenceTd\"><p>state confirmed good; session closed</p></td><td class=\"confluenceTd\"><p>terminal</p></td></tr><tr><td class=\"confluenceTd\"><p><code>escalated</code></p></td><td class=\"confluenceTd\"><p>could not resolve; handed to a human or teleoperator</p></td><td class=\"confluenceTd\"><p>terminal</p></td></tr></tbody></table></div><p>Invariants: read-only states never mutate; a flag-triggered session always reaches at least <code>diagnosed</code> with a proposed action \u2014 it never silently mutates and never silently does nothing; <code>acting</code> is always followed by <code>verifying</code> (no fire-and-forget); autonomy tier (\u00a710.2) decides only whether <code>diagnosed \u2192 acting</code> needs to pass through <code>proposed</code>. From <code>diagnosed</code>, <code>verifying</code>, <code>resolved</code>, or <code>escalated</code> the session may also <strong>file an intent</strong> (evidence attached) when the root cause is a definition flaw \u2014 this is the <em>only</em> crossing into the edit lifecycle (\u00a76.4), via the shared intent log.</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-6.6Sharedvsdistinct\">6.6 Shared vs distinct</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p /></th><th class=\"confluenceTh\"><p>Deployment agent</p></th><th class=\"confluenceTh\"><p>Operator agent</p></th></tr><tr><td class=\"confluenceTd\"><p>State model</p></td><td class=\"confluenceTd\"><p>edit lifecycle (\u00a76.1\u20136.4)</p></td><td class=\"confluenceTd\"><p>intervention lifecycle (\u00a76.5)</p></td></tr><tr><td class=\"confluenceTd\"><p>Acts on</p></td><td class=\"confluenceTd\"><p>definitions (source \u2192 version \u2192 migration)</p></td><td class=\"confluenceTd\"><p>one live instance's markings/leases/facts</p></td></tr><tr><td class=\"confluenceTd\"><p>Principal / tool mount / context</p></td><td class=\"confluenceTd\"><p><code>studio-deployment</code>, edit tools, edit context</p></td><td class=\"confluenceTd\"><p><code>studio-operator</code>, operate tools, operate context</p></td></tr><tr><td class=\"confluenceTd\"><p>Produces</p></td><td class=\"confluenceTd\"><p>published versions + migrations</p></td><td class=\"confluenceTd\"><p>transient instance changes; <strong>no version</strong></p></td></tr><tr><td class=\"confluenceTd\"><p><strong>Shared</strong></p></td><td class=\"confluenceTd\"><p>the <strong>intent log</strong> (the only object both touch, \u00a76.3/\u00a711); the identity &amp; Cedar model (\u00a713); the <strong>capability catalog</strong> grounding (\u00a78.1); the eval harness &amp; vocabulary (\u00a712)</p></td></tr></tbody></table></div><p>If a future agent is added (e.g. conformance/analytics), it gets its own lifecycle and principal under the same rule: it may append intents, and it shares the catalog and harness, but it does not borrow another agent's tool mount.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-7.TheStudioDataModel\">7. The Studio Data Model</h2><p>Does Studio need its own database, with its own tenancy and RLS \u2014 or can it just be more rows on the Switchboard schema, written through the API, since the coordinator is dumb anyway? The answer is <em>mostly the latter in spirit</em>, with one sharp line.</p><p><strong>Principle.</strong> Switchboard owns what is <strong>authoritative and shared</strong>; Studio owns what is <strong>proposed and process-private</strong>. The boundary between them is exactly the authorization seam from \u00a713: <strong>publish and migrate.</strong> Everything before a commit is Studio's; the commit and everything authoritative it produces is Switchboard's. &quot;Dumb coordinator&quot; never meant &quot;stores little&quot; \u2014 Switchboard already persists facts, markings, leases, versions, and events. Dumb means <em>holds no reasoning</em>. Adding a provenance stamp to a version is not making it smart; it is making it store one more piece of dumb, authoritative data.</p><p><strong>What Switchboard stores</strong> (already, plus one addition). Definitions and versions (immutable, append-only); instances, markings, facts, leases, events, migrations; and the <strong>capability catalog</strong> (\u00a78.1) as published, versioned reference data alongside the map. <em>New:</em> a small immutable <strong>provenance stamp</strong> on each version (the intent ids + patch canonical hash that produced it) and on each migration (mapping hash + approver). This is the only Studio-origin data that lives in Switchboard; it is written at the seam through the existing publish/migrate API; and it earns its place because <em>&quot;what is running, and why&quot;</em> must be answerable by Switchboard alone, even with Studio down. This is the natural extension of the fact already true \u2014 Switchboard versions workflows \u2014 so the <em>committed</em> link from a version back to its intent belongs there too.</p><p><strong>What Studio stores</strong> (its own schema). The full intent log \u2014 branchy, with declined entries and rich evidence (Switchboard holds only the committed subset, by reference); drafts, patches, and their entire pre-publish lifecycle (\u00a76.1); snapshots <code>(source, net, hash)</code>; migration mappings before approval; Operator session records (\u00a76.5); and everything evaluation \u2014 scenarios, runs, transcripts, token telemetry, conformance computations. This is high-churn, branchy, and bulky; it has nothing to do with coordination; and it must never sit on the robots' lease-acquisition hot path.</p><p>Record shapes worth pinning now: an <strong>intent</strong> is <code>(id, author principal, timestamp, verbatim text, evidence refs [event/trace/instance/version ids], branch, status)</code>. A <strong>patch</strong> is <code>(id, branch, intent refs, source diff, state per \u00a76.1, validation evidence, snapshot ref)</code>. Verbatim intent text is load-bearing twice over: it is the provenance answer to &quot;why,&quot; and it is the dataset of what operators actually say, which seeds new eval tasks (\u00a712).</p><p><strong>Tenancy \u2014 the part not to duplicate.</strong> Studio does <strong>not</strong> reinvent the identity model. It federates against the same IdP, scopes its rows by the same tenant/site/fleet keys, and authorizes its own actions with the same Cedar principals already defined (\u00a713). One source of identity truth; Studio is a relying party. And Studio <strong>never copies Switchboard objects</strong> \u2014 it reads them live through the API under Cedar + RLS \u2014 so there is no second copy of coordination state to protect, and therefore no parallel RLS to maintain over it. Studio's <em>own</em> rows (intents, approvals) get row-scoping by the same tenant keys, but lighter than Switchboard's four-tier enforcement, because what they protect is proposals, not the strong core.</p><p><strong>Physical placement \u2014 pragmatic for a small team.</strong> At MVP, a separate <code>studio</code> schema in the <strong>same Postgres instance</strong> as Switchboard: one thing to run, back up, and observe. The discipline that keeps this honest: even sharing an instance, <strong>Studio touches Switchboard state only through the HTTP API</strong>, never by reaching into its tables. The shared instance buys operational simplicity, not a license to break the API seam \u2014 which means the provenance links are <strong>soft ids, not foreign keys</strong>, exactly the convention the State Model already uses for map\u2194workflow refs. Because the references are soft, Studio can later split to a fully separate database \u2014 for failure isolation, or because a transcript flood threatens the hot path \u2014 with no schema change. The architecture pre-approves that split; we just don't pay for it on day one.</p><p><strong>Why not all of it in Switchboard?</strong> Because the reason the coordinator is dumb is to keep its authoritative core minimal and stable, on a deliberately slow and careful (Rust) release cadence. Published versions belong there because they are authoritative and shared. Half-finished drafts, branchy intent history, and gigabytes of eval transcripts do not \u2014 putting them there would couple Studio's fast Python iteration to Switchboard's release train and drop editing churn onto the robots' hot path. Drawing the line at <em>commit</em> gives us both halves of the intuition: versions and their provenance live in Switchboard; the editing <em>process</em> that produces them does not.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-8.ContextEngineering\">8. Context Engineering</h2><p>The prototype's instruction set grew to roughly ten thousand words of carefully engineered rules, examples, and tool-preference guidance \u2014 and it worked, which is exactly why it's worth studying. Reading it closely, almost every rule is one of: (a) domain structure the new source format now expresses, (b) an invariant the validator should enforce, (c) context the harness should retrieve, or (d) genuine behavioral policy. Only (d) belongs in the prompt. The target: <strong>a system prompt an order of magnitude smaller, with everything else supplied as structured per-turn context.</strong></p><p>What the harness assembles per turn, in priority order:</p><ol start=\"1\"><li><p><strong>The working artifact</strong>: current draft source + seed (or, for the Operator agent, the instance's marking/facts/leases via the lenses). The prototype's pattern of appending the full current workflow context to workflow-scoped tool results \u2014 keeping only the latest snapshot live in history \u2014 is the right mechanism and carries forward.</p></li><li><p><strong>Grounding</strong>: map tags for the target map version, payload schemas, seed robots/roles, declared invariants, and <strong>the capability catalog (\u00a78.1)</strong> \u2014 the policies that exist, the prompts they support, and the questions the visual oracle can answer. The user never supplies these; the agent never invents them.</p></li><li><p><strong>History</strong>: the recent intent-log entries and patches for this draft branch (so the agent understands not just the state but the trajectory \u2014 the v0 Studio insight), plus a compacted conversation.</p></li><li><p><strong>Validation state</strong>: the freshest validate/simulate results, clearly marked as possibly stale after any edit.</p></li></ol><p>Compaction policy (the prototype's is correct and keeps its essentials): never touch the current turn; truncate historical tool outputs, messages, and reasoning aggressively; drop oldest-first under a hard budget; strip orphaned tool-call/return pairs after every drop; retain exactly one full artifact snapshot. Implementers should treat the prototype's session-history / history-processor modules as the reference implementation.</p><p>Two rules for whoever implements this:</p><ul><li><p><strong>Knowledge moves down the stack, never up.</strong> When a behavior needs fixing, the order of preference is: make it impossible in the source format \u2192 reject it in the validator \u2192 catch it in a grader \u2192 only then add a prompt rule. A prompt rule is a confession that the lower layers have a gap.</p></li><li><p><strong>The user's words are intent, not instructions.</strong> The harness owns naming, seeding, candidate management, and tool choreography. If an eval task can only pass when the user's prompt names a state, the task (or the agent) is wrong.</p></li></ul><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-8.1TheCapabilityCatalog\">8.1 The Capability Catalog</h3><p>The single most effective way to stop the agent inventing &quot;random shit&quot; is to give it the closed set of things the deployment can actually do, and to make anything outside that set a hard error rather than a hopeful guess. That closed set is the <strong>capability catalog</strong>: the grounding source that enumerates what the robots and the perception stack can be asked to do, on this site, at this software version.</p><p>It has two parts:</p><ul><li><p><strong>Supported policies and their prompts.</strong> Every executor-backed action a task can invoke \u2014 <code>navigate</code>, <code>policy</code>, <code>pick_policy</code>, <code>place_policy</code>, and so on \u2014 with the prompt templates each trained policy actually supports and the slots they accept (e.g. a pick policy that takes a target description and a shelf level), plus preconditions (a placement policy may require the target below torso height; a pick may require a tag-relative approach offset). A task whose <code>executor</code>+<code>task_type</code>+<code>prompt</code> does not resolve to a catalog entry is a tier-1 validation rejection (\u00a79.2), exactly as a navigation tag that isn't on the map is. This is what makes &quot;pick the {item} and juggle it&quot; fail loudly instead of producing a plausible-looking workflow that no policy can run.</p></li><li><p><strong>Visual-query (System-2) capabilities.</strong> The questions the perception oracle can answer about the scene, as a typed query schema \u2014 for CEVA, &quot;which totes are present in the shelf and where (which column, top vs bottom)&quot;; in general, occupancy, presence, identity-of-object, pose-relative-to-tag. The catalog states each query's inputs and the shape of its answer, so the Deployment agent can wire a visual query as a workflow oracle (feeding a guard or a navigation offset) only where one really exists, and the Operator agent can issue a visual query as a <strong>diagnostic</strong> \u2014 &quot;is there actually a tote in front of the robot, or is the marking lying?&quot; Crucially, the <em>answer</em> to a visual query is the perception system asserting reality, not the agent; this is what lets the Operator agent ground a diagnosis in what the robot sees without violating the no-impersonation rule (\u00a710.1). It is the sanctioned bridge from System-3 reasoning down to System-2 perception.</p></li></ul><p>The catalog is <strong>published, versioned reference data, read via the API</strong> \u2014 authoritative-and-shared in the sense of \u00a77, pinned per site and software version so that grounding always matches what is actually deployed. Both agents read it; the validator enforces against it; refusal scenarios (\u00a712) test that out-of-catalog requests are declined rather than approximated. Exact ownership \u2014 whether it is generated from the trained-policy registry on the ML side, declared in the robot software, or assembled by Switchboard \u2014 and whether it participates in a definition's canonical hash the way the prelude does, are open questions (Appendix D).</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-9.TheDeploymentAgent\">9. The Deployment Agent</h2><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-9.1Theloop\">9.1 The loop</h3><p>One intent-log entry drives one agent turn-sequence: assemble context (\u00a78) \u2192 propose a source patch \u2192 evaluate \u2192 validate \u2192 simulate/replay \u2192 either iterate on failures (the prototype's repair discipline: a non-quiescent or wrong-outcome simulation is a failed edit to keep working, not a caveat to report) or present for approval. Multi-turn is the normal case, not the exception: incremental evolution of a live workflow over many intents is the product, and the intent log is the unit of work. Each turn moves the patch through the states of \u00a76.1.</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-9.2Validationtiers\">9.2 Validation tiers</h3><p>Four tiers, ordered by cost; every patch passes them in order; a patch is not <em>proposable</em> until tiers 1\u20133 pass (the <code>draft \u2192 validated</code> gate of \u00a76.1), and tier 4 is the <code>proposed \u2192 approved</code> gate.</p><ol start=\"1\"><li><p><strong>Deterministic-structural</strong> (every edit): source evaluates hermetically within budget; every referenced place resolves in the target map version; every task's policy and prompt resolve in the capability catalog (\u00a78.1); schemas close (no undeclared payload fields, no unread/unwritten fields); every task has an executor; every token class can reach a terminal state; capacity sanity; <strong>named invariants</strong> attached to the definition (e.g., &quot;this net supports N concurrent robots&quot;) assert per version \u2014 so an edit that accidentally serializes a parallel workflow is caught before any human reads the diff.</p></li><li><p><strong>Behavioral \u2014 trace replay</strong>: the simulator runs from the draft seed; canonical traces tagged must-pass replay identically; traces the intent deliberately changes are re-tagged, and the re-tagging is part of the reviewed diff. <strong>The validator is the runtime</strong>: the Python symbolic simulator is acceptable for the inner loop exactly insofar as it implements the engine's semantics; as the Rust engine matures, behavioral truth migrates to replaying through a simulated instance of the real engine (the State Model already permits sim instances of a definition). Divergence between validator and engine semantics is the class of bug that produced the Robostore basket-swap regressions \u2014 the canonical-trace corpus exists to catch it from both sides.</p></li><li><p><strong>Model-based \u2014 scope check</strong>: a rubric-graded judgment that the diff implements the intent and <em>nothing else</em>, and that the regenerated SOP projection is consistent with the net.</p></li><li><p><strong>Human approval, made cheap</strong>: source diff, green checklist, replay results, diagram diff. The reviewer confirms judgment, not correctness \u2014 correctness was already machine-checked.</p></li></ol><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-9.3Conformancefeedsback\">9.3 Conformance feeds back</h3><p>Once a version is live, observed execution (the event log) is compared against the definition: a <strong>conformance score</strong> per instance, computed over events, with deviations attributable to a specific version and therefore to a specific patch and intent (the provenance chain, \u00a711). When conformance drops \u2014 robots improvising, operators repeatedly intervening at the same transition, the same token class quarantining \u2014 that is the system telling us the definition is wrong. The adaptive loop from the v0 Studio spec becomes concrete and stays propose-only: a conformance drop files an intent <em>with the deviating traces attached as evidence</em>; the Deployment agent proposes a patch; a human approves. No autonomous definition changes from conformance signals.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-10.TheOperatorAgent\">10. The Operator Agent</h2><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-10.1Actioncatalog\">10.1 Action catalog</h3><p>Almost entirely existing Switchboard actions, mounted as tools on the operator principal:</p><ul><li><p><strong>Diagnose</strong> \u2014 the three query lenses, the event log, and one new API requirement this spec levies on Switchboard: an <strong>eligibility-explain</strong> endpoint (<code>GET /v1/instances/$id/eligibility?explain=true</code>) returning per-transition why-not \u2014 failed guard (and which payload comparison failed), stale/wrong-epoch/wrong-map fact, capacity block, missing token, lease held by whom. The prototype's <code>analyze</code>/<code>list_enabled</code> simulator actions are the offline prototype of exactly this; the live endpoint is the same computation against the relaxed projection, with freshness annotations. Without it the agent reconstructs guard logic from raw facts \u2014 the dominant token cost observed in prototype sessions. The agent may also issue a <strong>visual query</strong> (the System-2 perception oracle, \u00a78.1) to ground a diagnosis in what the robot actually sees \u2014 &quot;is there really a tote there?&quot; \u2014 where the answer is the perception system asserting reality, not the agent.</p></li><li><p><strong>Intervene</strong> \u2014 transactional <code>release \u2192 reacquire</code> (existing primitive, capability-gated). This is the correct fix for the vinyl-floor incident class: rather than &quot;fail task&quot; wedging coordination state, the lease is reassigned atomically and the work returns to the pool or a teleoperator.</p></li><li><p><strong>Inject</strong> \u2014 work tokens via source transitions, same shape as the WMS adapter.</p></li><li><p><strong>Resolve</strong> \u2014 quarantined or stuck tokens: map to a place or terminal-ize the subject; the &quot;operator/agent resolves&quot; cell of the exception table.</p></li><li><p><strong>Apply seed / reset marking</strong> \u2014 gated like forced migration; this is where the prototype's reset-from-seed capability lives now.</p></li><li><p><strong>Record deviations</strong> \u2014 <code>conformant=false</code>, <code>actor=agent:&lt;session&gt;</code>, loud \u2014 only as <em>operator-directed</em> execution. Deviate exists for actors that know reality better than the schematic; a robot qualifies, an LLM reading Switchboard's own replica does not. A human asserts the reality claim; the agent mechanizes the resolution.</p></li><li><p><strong>Declare facts</strong> \u2014 operator-class declared facts only (TTL or sticky, <code>source</code> recorded). The Operator agent never writes a fact whose declared writer is <code>robot-exec</code>: it does not perceive reality and must not impersonate telemetry. Role changes route through operator-declared facts or assignment.</p></li></ul><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-10.2Autonomytiers,earnedbyevals\">10.2 Autonomy tiers, earned by evals</h3><p>Reads are free. Intervention and injection start confirm-per-action. Resolution, marking resets, and deviations start human-approved. Each tier graduates to autonomous-with-notification only when its eval suite holds a consistency bar (\u00a712.3) over a defined window. Autonomy is deployment configuration, not prompt content \u2014 a site can pin the agent read-only. In lifecycle terms (\u00a76.5), the tier decides only whether <code>diagnosed \u2192 acting</code> must pass through the <code>proposed</code> gate.</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-10.3Triggers\">10.3 Triggers</h3><p>Three entry points open a session (\u00a76.5): an operator asks (&quot;why is r2 just standing there&quot;); an exception flag fires (quarantine, dropped tote, lease timeout, conformance event) and the agent investigates and proposes; scheduled sweeps (stale leases, growing quarantine, eligibility deserts). Flag-triggered sessions always produce a diagnosis plus a proposed action at the current autonomy tier; they never silently mutate.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-11.Traceability\">11. Traceability</h2><p>With the state models (\u00a76) and storage (\u00a77) defined, traceability is what they buy:</p><ul><li><p><strong>Provenance, both directions.</strong> The committed chain \u2014 <em>operational incident \u2192 intent \u2192 patch \u2192 version \u2192 migration \u2192 events</em> \u2014 is queryable end to end. &quot;Why does this workflow do X&quot; resolves to a person and a sentence (the intent text); &quot;what did that change on the floor&quot; resolves to event-log deltas and conformance movement. The provenance stamps in \u00a77 are what let the chain survive even with Studio offline.</p></li><li><p><strong>The intent log is the only seam between the agents.</strong> The Operator agent <strong>appends intents</strong> (with trace evidence) and cannot author patches; the Deployment agent <strong>consumes intents</strong> and observes live instances only through published read lenses. No shared context, ever \u2014 an append-only log is the entire interface. This is how a stuck-robot session ends properly: resolve the token now (Operator), file the intent so it stops happening (the log), patch the definition later (Deployment).</p></li><li><p><strong>Undo is traceable, not magical.</strong> Within a draft, the prototype's turn-scoped undo journal applies. Across published versions, undo is just another migration with its own mapping \u2014 recorded, approved, reversible in turn.</p></li></ul><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-12.Evaluation\">12. Evaluation</h2><p>This section assumes no prior familiarity with agent-evaluation practice; the vocabulary it establishes is used by the appendices and should be used by the implementation.</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-12.1Thebasicmachinery\">12.1 The basic machinery</h3><p>An <strong>evaluation</strong> gives an agent a defined starting situation and a request, lets it run, then applies <strong>graders</strong> \u2014 checks against what it produced \u2014 to decide pass/fail. A single defined situation+request+graders is a <strong>task</strong>; one attempt at a task is a <strong>trial</strong>. Because model outputs vary, a task is run as multiple trials and we look at rates, not single results. The complete record of a trial \u2014 every message, tool call, and result \u2014 is the <strong>transcript</strong>; the final state of the environment is the <strong>outcome</strong>. A <strong>suite</strong> is a set of tasks measuring one capability area, and the <strong>harness</strong> is the infrastructure that sets up a clean environment per trial, runs trials, grades, and aggregates.</p><p>Two non-obvious rules that practice has taught everyone who does this:</p><ul><li><p><strong>Grade outcomes, not paths.</strong> Asserting the agent called tools in a particular order produces brittle suites that punish valid creativity. Assert what ended up true: the tokens are where they should be, the lease was reassigned exactly once, the workflow's simulated execution moves every tote through pick\u2192carry\u2192place. (Our existing path assertions on <em>token</em> trajectories are outcome checks \u2014 they grade the workflow's execution, not the agent's tool sequence \u2014 and are exactly right. A path assertion on the <em>agent's tool calls</em> is justified only when it encodes a safety property, e.g. &quot;map tags were fetched, therefore not invented.&quot;)</p></li><li><p><strong>Each trial starts clean.</strong> Shared state between trials (a reused database, a leftover workspace) produces correlated failures and phantom successes. For us: fresh compose stack, fresh Postgres, fresh workspace, every trial.</p></li></ul><p>Three grader families, used together: <strong>deterministic</strong> (code checks: counts, paths, validity, quiescence \u2014 fast, objective, the backbone), <strong>model-based</strong> (an LLM judging against a written rubric \u2014 for qualities code can't check, like &quot;did the diff stay in scope&quot;; must be spot-calibrated against human judgment), and <strong>human</strong> (expensive; reserved for calibrating the model graders and for approval itself).</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-12.2Capabilityvsregression\u2014howsuiteslive\">12.2 Capability vs regression \u2014 how suites live</h3><p>A <strong>capability suite</strong> asks &quot;what can the agent do?&quot; It is <em>supposed</em> to have a low pass rate: it encodes the frontier, and its score is the hill the team climbs. The realistic-suite baseline is a textbook example \u2014 it measured exactly where the agent stood and decomposed the gap into named failure categories, which is what made the weekend improvement loop possible. A <strong>regression suite</strong> asks &quot;does it still do everything it used to?&quot; and should sit near 100%; any drop is an alarm. Tasks graduate from capability to regression as they're conquered, and the regression suite then gates every change \u2014 agent prompts, model swaps, harness changes, <em>and Switchboard engine changes</em>, since the canonical traces exercise the engine and the agent simultaneously.</p><p>Two corollaries we adopt as policy:</p><ul><li><p>A task at 0% across many trials is presumed a <strong>broken task</strong> before a broken agent \u2014 check the spec and graders first. Every task should have a known <strong>reference solution</strong> that passes its own graders, proving the task is solvable as written.</p></li><li><p>When a suite is recalibrated, the baseline resets: <strong>suite changes and agent changes are reported separately, never blended into one number.</strong> The calibration round established this discipline; it is policy.</p></li></ul><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-12.3Thetworeliabilitynumbers\">12.3 The two reliability numbers</h3><p>For a per-trial success rate p over k trials: the chance of <em>at least one</em> success (&quot;pass@k&quot;) rises with k; the chance that <em>all k</em> succeed (&quot;pass^k&quot;) falls with k. Which matters depends on the product moment. For an engineer iterating in a workspace, pass@k is fine \u2014 retry is cheap. For an operator at a customer site, <strong>consistency is the metric: pass^k is the headline number for both agents</strong>, and it is the number autonomy tiers (\u00a710.2) ratchet on. Cost and latency (tokens per accepted patch, time to proposal) are tracked alongside as budgets, not afterthoughts \u2014 the baseline's worst single task burned ~870k tokens, which is a cost bug a budget grader would have flagged.</p><h3 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-12.4Oursuites\">12.4 Our suites</h3><p><strong>Deployment agent.</strong> Tasks are <code>(baseline workflow source, map, seed, intent[, follow-up intents]) \u2192 outcome properties</code>, with intents in specificity tiers (\u00a74). Corpora in order of acquisition cost: the existing mini/realistic/fresh suites, recalibrated (the fresh suite \u2014 empty map to multi-robot workflow \u2014 is the strongest capability signal and stays hard); YAML\u2192Starlark conversion of every existing workflow, where &quot;convert and preserve behavior&quot; is a task with trace replay as oracle, so conversion tooling and eval corpus are one body of work; named historical regressions (the basket-swap/duplicate-item coupling, with the traces that would have caught it); migration-mapping tasks (live marking + definition change \u2192 total mapping). Multi-turn tasks are first-class \u2014 the round-trip finding (one-shot prompts under-test incremental editing) generalizes: the suite must contain author-then-amend sequences because that is the product.</p><p><strong>Operator agent.</strong> The State Model's G.1\u2013G.12 scenarios are the seed corpus, nearly verbatim: each is already preconditions \u2192 fault \u2192 oracle. The harness injects the fault into the compose stack (expired lease, epoch-stale fact, quarantined token, interrupted migration, a wedged &quot;fail task&quot;), and graders check outcome state (token unstuck, no double-granted lease, expected events with <code>actor=agent:*</code>), transcript constraints (no mutating call absent from the proposed plan; call budget), and a diagnosis-quality rubric. New tasks are minted continuously from production exception flags: every real incident that reaches a human becomes a task.</p><p><strong>Refusal and restraint, both directions.</strong> Suites must be balanced: tasks where the agent should act and tasks where it must not (unsupported requests, infeasible placements, requests requiring a policy the catalog doesn't list or a visual query the oracle can't answer, requests requiring facts nothing senses). Refusal prompts must not lead (&quot;sort totes by weight&quot;, not &quot;refuse to sort totes&quot;); <code>refused</code> means no mutating calls, reads allowed. One-sided suites produce one-sided agents \u2014 grade both the doing and the declining.</p><p><strong>Read the transcripts.</strong> Scores are not trusted until someone reads transcripts from failing <em>and</em> passing trials and confirms the failures are fair and the passes are real. The eval reports written for the baseline and calibration rounds set the standard; one such report accompanies every suite revision.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-13.Authorization\">13. Authorization</h2><p>Two principals, expressible almost entirely in existing State Model actions:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"3da6cf7e-8bae-4f7b-bbaa-0675c9a3c1a1\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">// Deployment agent: config plane only. Never touches live coordination.\npermit (principal == Service::&quot;studio-deployment&quot;,\n        action in [Action::&quot;PublishDefinition&quot;, Action::&quot;ReadMap&quot;, Action::&quot;ReadInstance&quot;], resource);\nforbid (principal == Service::&quot;studio-deployment&quot;, action, resource)\nunless { action in [Action::&quot;PublishDefinition&quot;, Action::&quot;ReadMap&quot;, Action::&quot;ReadInstance&quot;] };\n\n// Operator agent: operator-shaped; no config plane.\npermit (principal == Service::&quot;studio-operator&quot;,\n        action in [Action::&quot;Intervene&quot;, Action::&quot;InjectWork&quot;, Action::&quot;WriteFact&quot;,\n                   Action::&quot;ReadFleet&quot;, Action::&quot;ReadMap&quot;, Action::&quot;ReadInstance&quot;], resource)\nwhen { resource in principal.fleet };\nforbid (principal == Service::&quot;studio-operator&quot;,\n        action in [Action::&quot;PublishDefinition&quot;, Action::&quot;Migrate&quot;], resource);</pre>\n</div></div><p><code>WriteFact</code> for the operator principal is constrained at the fact-writer-declaration layer to operator-class keys \u2014 never <code>robot-exec</code>-owned telemetry. <code>Migrate</code> is held by <strong>neither</strong> principal; the human-approval flow fires it. <code>Deviate</code> is granted to the operator principal only under an operator-directed context flag. Sessions are distinguished in the event log via <code>actor = agent:&lt;session-uuid&gt;</code> rather than per-session principals. Whether one Python service or two hosts both agents, the audit log distinguishes the principals \u2014 which is what matters when a customer asks who moved a token.</p><p>This authorization seam is also the <strong>data seam</strong> (\u00a77): the two actions the Deployment agent and the approval flow can perform \u2014 <code>PublishDefinition</code> and <code>Migrate</code> \u2014 are exactly the points where Studio-origin data crosses into Switchboard.</p><p>Placement: the Deployment agent is a development-loop service and can live in the cloud. The Operator agent must run <strong>with the deployment</strong> \u2014 it is useless if it cannot reach Switchboard during the WAN flap that caused the fault \u2014 making it part of the Outpost footprint at site-authoritative tiers.</p><h2 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-14.Doctrine\">14. Doctrine</h2><p>Switchboard is dumb; Studio is smart; Studio acts only through Switchboard as an authorized principal. The agent edits the source that matters, not an abstraction of it; abstraction lives in a thin prelude and a strict validator, never between the agent and the net. Natural language is the bar: knowledge moves into the format, the tools, and the retrieved context \u2014 the prompt shrinks, the user's words stay intent. The agent grounds every prompt against the capability catalog and never invents a policy; the same catalog tells it what the System-2 visual oracle can be asked, and a request outside it is refused, not approximated. Two agents, two state models, two principals, two contexts \u2014 sharing exactly one object, the intent log. An edit is always in exactly one named state; definitions change by draft \u2192 validate \u2192 propose \u2192 publish \u2192 migrate, and <strong>publish and migrate are two gated transitions, never one</strong>; instances change by operator interventions that never produce a version; the two paths never share a context. The data seam is the authorization seam is the API seam \u2014 publish and migrate: Switchboard owns what is authoritative and shared, Studio owns what is proposed and process-private, and the committed provenance stamp is the only Studio-origin data in Switchboard. The intent log is the only seam between the agents and the provenance root for every change. The validator is the runtime. Conformance closes the loop, propose-only. Neither agent migrates \u2014 humans do. Autonomy is earned by consistency on evals, not asserted in config. The Operator agent never impersonates telemetry; when it needs to know reality, it asks perception. Grade outcomes, not paths; keep one suite climbing and one suite green; reset baselines when suites change; read the transcripts.</p><hr/><h1 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-AppendixA\u2014EvalScenarioSchemaandAssertionVocabulary\">Appendix A \u2014 Eval Scenario Schema and Assertion Vocabulary</h1><p>The existing scenario format is sound and carries forward with targeted extensions. A scenario is one YAML document:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"9a6f498e-4d69-4c79-990c-1bdba523e847\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">scenario_id: &lt;stable id&gt;\ndescription: &lt;one sentence: what capability this measures&gt;\nagent: deployment | operator                # NEW: which suite this belongs to\nsuite: capability | regression               # NEW: lifecycle stage; graduation flips this\ntarget_workflow_id: &lt;candidate id the harness manages&gt;   # deployment tasks\nbaseline_workflow: &lt;path or version ref&gt;     # starting source; omit for fresh tasks\ncapability_catalog: &lt;ref&gt;                    # NEW: the policy/visual-query universe in scope (\u00a78.1)\nsimulation_seed: &lt;path or inline tokens/facts&gt;  # ALWAYS seed physical state inline or by ref;\n                                                # never expect the agent to invent seeds\nfault: &lt;operator tasks only \u2014 injected condition, see below&gt;\ncanonical_intent: &lt;one sentence&gt;\nintent_variations:                           # specificity tiers (\u00a74)\n  tier_1: [...]   # engineer-precise\n  tier_2: [...]   # informed user\n  tier_3: [...]   # operator-natural / vague\nfollow_up_intents: [...]                     # multi-turn tasks; applied after first success\nprompt_sampling: {sample_size, seed}\nsimulation: {max_steps}\nbudgets: {max_tool_calls, max_total_tokens}  # hard on regression, tracked on capability\nreference_solution: &lt;path&gt;                   # proves the task solvable as written\nsuccess_criteria: [...]                      # assertion list, below</pre>\n</div></div><p><strong>Assertion vocabulary</strong> (existing types retained, semantics unchanged unless noted):</p><ul><li><p><code>workflow_exists</code>, <code>workflow_valid</code> \u2014 candidate present; tier-1 validation passes.</p></li><li><p><code>policy_supported {task}</code> \u2014 NEW: the task's executor + task_type + prompt resolve to a capability-catalog entry (\u00a78.1); the structural complement of &quot;tag is on the map.&quot;</p></li><li><p><code>visual_query_supported {query}</code> \u2014 NEW: a workflow-wired or operator-issued visual query resolves to a catalog query type.</p></li><li><p><code>workflow_has_work_items</code> / <code>workflow_lacks_task_types</code> \u2014 structural presence checks (renamed from <code>work_types</code> to match the new source vocabulary).</p></li><li><p><code>workflow_state_capacity {state, expected}</code> \u2014 buffer/capacity properties.</p></li><li><p><code>invariant_holds {name}</code> \u2014 a named invariant attached to the definition (parallelism, boundedness) asserts true post-edit.</p></li><li><p><code>task_param {task_name, param_key, expected_value}</code> \u2014 exact param checks (e.g., a policy prompt).</p></li><li><p><code>token_count {state, expected}</code> \u2014 final-marking counts after simulation.</p></li><li><p><code>sim_token_path_count {work_item, work_data?, expected, comparison, sequence}</code> \u2014 the workhorse: asserts N tokens of a class traverse a given lifecycle (with <code>consumed</code>/<code>produced</code>/<code>alias</code> locations and <code>repeat</code> blocks). <strong>Assert paths for every relevant token class</strong> \u2014 object <em>and</em> robot <em>and</em> order \u2014 final counts alone miss role merging and order/flow decoupling.</p></li><li><p><code>quiescent</code> \u2014 simulation terminates with no enabled transitions (no infinite loops, no premature termination).</p></li><li><p><code>trace_replay {trace_id, expectation: identical | retagged}</code> \u2014 canonical-trace replay for regression tasks.</p></li><li><p><code>migration_total {instance_ref}</code> \u2014 every live token maps or is deliberately quarantined with reason.</p></li><li><p><code>refused</code> \u2014 no mutating tool calls; read-only calls permitted. Used for out-of-catalog and infeasible requests.</p></li><li><p><code>state_check {path, expected}</code> \u2014 operator tasks: arbitrary checks against Switchboard state (lease tables, quarantine, event log entries incl. <code>actor</code>).</p></li><li><p><code>tool_used {tool_name}</code> \u2014 permitted only when it encodes a safety property (e.g., <code>get_map_tags</code> before authoring navigation), never as path preference.</p></li><li><p><code>max_tool_calls</code>, <code>max_total_tokens</code> \u2014 budget graders.</p></li></ul><p><strong>Operator-task fault vocabulary</strong> (initial set, drawn from G.1\u2013G.12 and incident history): <code>lease_expired</code>, <code>lease_wedged_by_failed_task</code>, <code>fact_stale {key, epoch_behind}</code>, <code>token_quarantined {reason}</code>, <code>migration_interrupted</code>, <code>capacity_deadlock</code>, <code>robot_delocalized</code>. Each fault is an idempotent setup script against the fresh compose stack.</p><p><strong>Naming discipline.</strong> Terminal/state names in oracles follow the standard conventions (<code>TotesOn_&lt;place&gt;</code>, <code>RobotsAt_done</code>, <code>CompletedOrder</code>), and seeds + prelude establish those names so the agent inherits rather than invents them. Do not build semantic-equivalence graders; standardize the names. (Calibration finding; adopted as policy.)</p><h1 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-AppendixB\u2014GradingTechniques\">Appendix B \u2014 Grading Techniques</h1><p><strong>Deterministic graders</strong> run in-process against the harness's Switchboard client and the evaluated net: structural checks (A's vocabulary), final-marking queries, event-log queries, replay comparison. They are the backbone; prefer them whenever the property is expressible in code.</p><p><strong>Trace replay</strong> is the behavioral regression mechanism: a canonical trace is a recorded sequence of transition firings with bound tokens from a known-good run (real or simulated). Replay = instantiate the definition on a sim deployment, drive the trace through the real commit path, diff resulting markings and events. <code>identical</code> expects exact agreement; <code>retagged</code> records a reviewed new expectation when an intent deliberately changes behavior. Trace corpus sources: golden demo runs, eval reference solutions, and production event-log extracts (sanitized).</p><p><strong>Model-based graders</strong> are used for exactly two judgments at MVP: <em>scope</em> (&quot;does this diff implement the intent and nothing else&quot; \u2014 rubric over intent text + source diff) and <em>diagnosis quality</em> (operator tasks \u2014 rubric over the transcript's stated diagnosis vs the injected fault). Rules: one rubric per judgment, graded by an isolated call (don't ask one judge for five dimensions); give the judge an explicit &quot;Unknown&quot; escape; spot-calibrate against human judgment on a sample each suite revision; record judge model+rubric version with every score.</p><p><strong>Partial credit</strong> applies to multi-property tasks: an operator trial that correctly diagnoses but proposes the wrong remedy is meaningfully better than one that mutates blindly; score dimensions separately and report the vector, not only the conjunction. The pass/fail used for pass^k remains the conjunction.</p><p><strong>Trial mechanics</strong>: fresh compose stack + Postgres + workspace per trial; fixed prompt-sampling seeds for reproducibility; N trials per task (default 3; raise for graduation decisions); transcripts persisted with per-request token usage (the prototype's usage plumbing carries forward); one written report per baseline or suite revision, in the established report format (summary table, per-scenario results, failure-assertion histogram, interpretation, trustworthiness caveats).</p><h1 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-AppendixC\u2014PrototypeDispositionMap\">Appendix C \u2014 Prototype Disposition Map</h1><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Prototype component</p></th><th class=\"confluenceTh\"><p>Disposition</p></th></tr><tr><td class=\"confluenceTd\"><p>Symbolic simulator, validator, reachability analysis</p></td><td class=\"confluenceTd\"><p>Carry forward; spine of tiers 1\u20132; converges toward replay through the Rust engine</p></td></tr><tr><td class=\"confluenceTd\"><p>Render surfaces (diagram, diffs, sim player, map tags)</p></td><td class=\"confluenceTd\"><p>Carry forward; they are the tier-4 approval UI</p></td></tr><tr><td class=\"confluenceTd\"><p>Undo journal (turn-scoped, snapshot-verified)</p></td><td class=\"confluenceTd\"><p>Carry forward; draft-workspace primitive</p></td></tr><tr><td class=\"confluenceTd\"><p>Disk workspace</p></td><td class=\"confluenceTd\"><p>Carry forward; becomes the branchable, intent-keyed Studio workspace</p></td></tr><tr><td class=\"confluenceTd\"><p>Session compaction + tool-result context retention</p></td><td class=\"confluenceTd\"><p>Carry forward; reference implementation for \u00a78</p></td></tr><tr><td class=\"confluenceTd\"><p>Grounding tools (map tags, seed robots, structure queries)</p></td><td class=\"confluenceTd\"><p>Carry forward; feed context assembly; extended with the capability catalog (\u00a78.1)</p></td></tr><tr><td class=\"confluenceTd\"><p>Visual/image-query oracle (e.g. CEVA shelf scan)</p></td><td class=\"confluenceTd\"><p>Promote to a catalogued System-2 capability (\u00a78.1): wired by the Deployment agent, queried by the Operator agent for perception-grounded diagnosis</p></td></tr><tr><td class=\"confluenceTd\"><p>Semantic mutation tools</p></td><td class=\"confluenceTd\"><p>Honorably retired as the editing surface; their invariants live on in the prelude + validator; mechanical ops (copy/branch/rename) remain</p></td></tr><tr><td class=\"confluenceTd\"><p>Raw YAML edit tools</p></td><td class=\"confluenceTd\"><p>Become source-text edit tools</p></td></tr><tr><td class=\"confluenceTd\"><p>Runtime-backed editing + <code>approval_required</code> guard</p></td><td class=\"confluenceTd\"><p>Superseded by draft \u2192 publish \u2192 migrate (the guard's instinct, structural)</p></td></tr><tr><td class=\"confluenceTd\"><p><code>reset-from-seed</code>, live fact pushes</p></td><td class=\"confluenceTd\"><p>Move to the Operator agent's mount, gated as marking-rewrite operations</p></td></tr><tr><td class=\"confluenceTd\"><p>Eval scenarios, harness, reports (incl. the weekend improvement loop)</p></td><td class=\"confluenceTd\"><p>Carry forward; recalibrated per Appendix A; the improvement loop is the development methodology</p></td></tr></tbody></table></div><h1 id=\"Spec:Studio\u2014System-3AgentsforWorkflowOperations&amp;Deployment-AppendixD\u2014OpenQuestions\">Appendix D \u2014 Open Questions</h1><ul><li><p><strong>Capability catalog ownership &amp; versioning</strong> \u2014 is it generated from the trained-policy registry (ML side), declared in the robot software, or assembled by Switchboard? How is it pinned per site/software version, and does it participate in a definition's canonical hash the way the prelude does?</p></li><li><p><strong>Visual-query schema</strong> \u2014 the formal set of questions the System-2 oracle answers (inputs + answer shape), and how a new query type is registered so the catalog stays truthful.</p></li><li><p><strong>Intent schema details</strong> \u2014 evidence attachment types and retention; whether declined intents need a review queue.</p></li><li><p><strong>Provenance stamp shape</strong> \u2014 exactly which fields land on the Switchboard version/migration rows (intent ids + patch hash at minimum) vs stay Studio-side by reference.</p></li><li><p><strong>Studio store split trigger</strong> \u2014 concrete signal (transcript volume, hot-path contention) that moves Studio from the shared <code>studio</code> schema to a separate database.</p></li><li><p><strong>Eligibility-explain consistency</strong> \u2014 relaxed projection with freshness annotations (position) vs strong read; and whether explain should include counterfactuals (&quot;would fire if fact X were fresh&quot;).</p></li><li><p><strong>Prelude governance</strong> \u2014 who may add helpers, and versioning: the prelude is pinned per definition and participates in the canonical hash.</p></li><li><p><strong>Operator-agent inference at site-authoritative tiers</strong> \u2014 local model vs degraded explain-only mode during WAN loss (Outpost question).</p></li><li><p><strong>Per-session principals</strong> vs <code>actor=agent:session</code> in the event log (position: the latter, until an auditor demands otherwise).</p></li><li><p><strong>Trace sanitization</strong> for production-derived canonical traces at customer sites.</p></li><li><p><code>move</code>/<code>hold</code>/<code>drop</code> exact semantics \u2014 confirm the consume/produce behavior of <code>drop</code> against the prelude before finalizing \u00a75 prose.</p></li></ul>"
        },
        {
          "id": "2061434886",
          "title": "Spec: HMND Outpost & Site Authority",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2061434886",
          "last_modified": "2026-06-05T13:03:57.477Z",
          "created_at": "2026-06-05T13:00:41.587Z",
          "body_html": "<p local-id=\"7de159bb0370\"><strong>Summary</strong>: One logical control plane with movable operational authority \u2014 cloud or on-prem outpost \u2014 for site robotics deployments.</p><p local-id=\"ffca0fe07c60\"><strong>Owner</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a></p><p local-id=\"e420cf842403\"><strong>Date</strong>: <time datetime=\"2026-06-05\" class=\"date-past\">05 Jun 2026</time></p><p local-id=\"7708f21b9256\"><strong>Approvers</strong>: </p><p local-id=\"4dc4b3e1f5e8\"><strong>Informed</strong>: </p><p local-id=\"931703f47894\"><strong>Related</strong>: </p><p local-id=\"b34ff7639d88\"><a href=\"/wiki/spaces/ROBOT/pages/1170341889/Spec+HMND+Fleet+Control+Plane\" data-linked-resource-id=\"1170341889\" data-linked-resource-version=\"16\" data-linked-resource-type=\"page\">Spec: HMND Fleet Control Plane</a></p><p local-id=\"b91ea396c853\"><a href=\"/wiki/spaces/ROBOT/pages/1151303693/Spec+HMND+Core+Control+Plane\" data-linked-resource-id=\"1151303693\" data-linked-resource-version=\"8\" data-linked-resource-type=\"page\">Spec: HMND Core Control Plane</a></p><h2 local-id=\"d3bc40e876ed\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-ProblemStatement\">Problem Statement</h2><p local-id=\"e71a5aec1029\">As we move robots out of demo areas and into real customer factories, a single architectural question keeps recurring: where does operational truth live? Some deployments are happy talking to HMND cloud over WAN. Others need low latency, local autonomy, offline operation, or on-prem provisioning, and cannot tolerate a factory that stops working when the internet hiccups.</p><p local-id=\"723c284a0c19\">The naive response is to fork the product: a &quot;cloud&quot; version and an &quot;edge&quot; version, plus a separate factory provisioning tool, plus a pile of bespoke install scripts. That path leads to two codebases, two mental models, YAML archaeology, and a field engineer who is the only person who knows the working incantation.</p><p local-id=\"8458dc3ec459\">We want a single control plane where <strong>authority is placeable</strong>, not a family of divergent products. The same Switchboard, the same identity model, the same provisioning machinery \u2014 deployed with the authority either in the cloud or on a local outpost cluster, depending on what the customer is paying for.</p><p local-id=\"1eff07410a57\">A second recurring problem is that we do not own the customer's network. In most real deployments the customer provides Wi-Fi, switching, routing, firewall policy, DNS, DHCP, NTP, power, and egress. The outpost has to <em>qualify and survive</em> that infrastructure rather than pretend it owns it.</p><h2 local-id=\"5027e06a772a\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-Scope\">Scope</h2><p local-id=\"531bf0714b3f\"><strong>In Scope:</strong></p><ul local-id=\"de12c6de292c\"><li local-id=\"6f8644132357\"><p local-id=\"77bb94708d29\">The site / outpost / authority abstraction and the product tiers (Tier 0, 1, 3, Airgap) derived from it.</p></li><li local-id=\"b89f2759817e\"><p local-id=\"a641a2ad703d\">Placement model for the Site Authority: cloud-hosted vs. local outpost cluster, with one authority per site.</p></li><li local-id=\"37ecec1e0c6a\"><p local-id=\"300d0b993fb7\">Local edge software stack (k3s, Postgres/PostGIS/pgvector, NATS JetStream, ZFS blob store, OTel/Prometheus/Grafana).</p></li><li local-id=\"67b9b413b6dd\"><p local-id=\"04aa1789b531\">State classification and sync semantics: runtime-local vs. durable-authored, and lost-write / split-brain behavior per tier.</p></li><li local-id=\"7e37a69cc6c1\"><p local-id=\"86ffb129b2c5\">Outpost as a fleet device (identity, enrollment, versioning, lifecycle) and as a provisioning appliance.</p></li><li local-id=\"18f84a2d537b\"><p local-id=\"53241bd5c60a\">Identity &amp; PKI model separating device identity, fleet identity, entitlement, and lease.</p></li><li local-id=\"ee06897f996c\"><p local-id=\"cc4b4c5bcd10\">BYON (bring-your-own-network) as a first-class deployment mode, including network &amp; power qualification.</p></li><li local-id=\"48f6110a07cc\"><p local-id=\"aa1c7843b392\">Segregation model across tenant, network, trust, and data dimensions.</p></li><li local-id=\"9291349df833\"><p local-id=\"2bafbba2aaad\">Reference hardware profile and rough BOM targets.</p></li></ul><p local-id=\"00f2bb46c0c6\"><strong>Out of Scope:</strong></p><ul local-id=\"6fefc5e0435f\"><li local-id=\"6072f35c661f\"><p local-id=\"91da9f833582\">Detailed workflow / coordinator semantics \u2014 owned by <a href=\"/wiki/spaces/ROBOT/pages/1170341889/Spec+HMND+Fleet+Control+Plane\" data-linked-resource-id=\"1170341889\" data-linked-resource-version=\"16\" data-linked-resource-type=\"page\">Spec: HMND Fleet Control Plane</a>.</p></li><li local-id=\"d63f37d307f0\"><p local-id=\"e7794d25756c\">Full PKI cert lifecycle implementation detail \u2014 see <a href=\"/wiki/spaces/ROBOT/pages/1151303693/Spec+HMND+Core+Control+Plane\" data-linked-resource-id=\"1151303693\" data-linked-resource-version=\"8\" data-linked-resource-type=\"page\">Spec: HMND Core Control Plane</a>; this spec only covers placement and trust posture.</p></li><li local-id=\"68f79b9f4e68\"><p local-id=\"c14621271beb\">Local GPU inference on the outpost (slot is reserved in the hardware profile; not part of the default operational surface).</p></li><li local-id=\"9d5b4bcf8e86\"><p local-id=\"b4588f3b8f56\">Multi-tenant outposts (default customer outpost is single-tenant).</p></li><li local-id=\"68fbc3f5432a\"><p local-id=\"b6c177bc9440\">Concrete airgap transfer tooling (acknowledged as a separate operational contract, priced and specced separately).</p></li></ul><h2 local-id=\"4a4b3657de08\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-DesignOverview\">Design Overview</h2><p local-id=\"07e7e5d5daff\">The system is built around one abstraction: a <strong>site</strong> has an operational control plane, and that control plane can be placed either in HMND cloud or on customer premises. The <strong>outpost</strong> is the hardware/software substrate that lets us place the control plane locally when the customer needs autonomy, low latency, provisioning, or offline operation.</p><p local-id=\"b65d026c3121\">The key idea is that <strong><span class=\"inline-comment-marker\" data-ref=\"faf09b41-3fe8-4f33-a7f6-9ef629051079\">outpost size</span></strong><span class=\"inline-comment-marker\" data-ref=\"faf09b41-3fe8-4f33-a7f6-9ef629051079\"> and </span><strong><span class=\"inline-comment-marker\" data-ref=\"faf09b41-3fe8-4f33-a7f6-9ef629051079\">authority placement</span></strong><span class=\"inline-comment-marker\" data-ref=\"faf09b41-3fe8-4f33-a7f6-9ef629051079\"> are separate concepts</span>. An outpost may have zero, one, or three local nodes. Authority may live in the cloud or at the site. Those two axes combine into a small set of product tiers \u2014 not a product fork.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20260605-130347.png\" width=\"1536\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/2061434886/image-20260605-130347.png?version=1&amp;modificationDate=1780664629536&amp;cacheVersion=1&amp;api=v2&amp;width=1536&amp;height=1024\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/2061434886/image-20260605-130347.png?version=1&amp;modificationDate=1780664629536&amp;cacheVersion=1&amp;api=v2\" data-height=\"1024\" data-width=\"1536\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"2061795335\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20260605-130347.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"2061434886\" data-linked-resource-container-version=\"3\" data-media-id=\"05d5ce0c-107d-4630-84b1-9ed21421c69a\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/2061434886/image-20260605-130347.png?version=1&amp;modificationDate=1780664629536&amp;cacheVersion=1&amp;api=v2&amp;width=1536&amp;height=1024 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/2061434886/image-20260605-130347.png?version=1&amp;modificationDate=1780664629536&amp;cacheVersion=1&amp;api=v2&amp;width=1536&amp;height=1024 1x\"></span><p local-id=\"15d5b9836154\" /><div class=\"confluence-information-macro confluence-information-macro-information conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"info\" data-macro-id=\"f7b3a13e-b257-401f-afb0-8759134c4163\" data-local-id=\"cbc3a66919aa\"><span class=\"aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon\"> </span><div class=\"confluence-information-macro-body\"><p local-id=\"66dcf3e28123\"><strong>Invariant:</strong> Every site has exactly one operational authority. For Tier 0 and Tier 1 that authority is the cloud; for Tier 3 and Airgap it is the local outpost cluster. Everything else is cache, proxy, mirror, provisioning appliance, or analytics sink.</p></div></div><h3 local-id=\"c64f2f2ac636\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-CoreConcepts\">Core Concepts</h3><p local-id=\"8c0b6ac787ba\"><strong>Site</strong> \u2014 the physical deployment boundary: one factory, lab, warehouse, customer location, or logically isolated operating area. A site contains robots, maps, workflows, semantic zones, operators, provisioning state, local integrations, and runtime state.</p><p local-id=\"3138aacc541d\"><strong>Outpost</strong> \u2014 HMND-managed edge infrastructure at the site. Absent, single-node, or three-node HA. It can run robot gateway services, local caches, artifact stores, provisioning flows, factory integration adapters, local UI, observability, and (in Tier 3) the Site Authority itself. The outpost is treated as a fleet device: device identity, enrollment state, software version, certificates, health, logs, cloud-managed lifecycle.</p><p local-id=\"c15f6a37383c\"><strong>Authority</strong> \u2014 the writer of operational truth. Operational truth includes workflow markings, robot leases, task ownership, active map versions, active policy versions, fleet configuration, command authorization, and site-local runtime decisions. In Tier 0/1 the cloud is authoritative; in Tier 3 the local outpost is authoritative and cloud receives an async mirror.</p><p local-id=\"1de4942dcb42\"><strong>Segregation</strong> \u2014 whether customer workloads, robot traffic, factory integrations, management traffic, and cloud egress share the same network and trust surface. The default is logically segregated even when the customer provides the physical network: separate identities, separate mTLS policies, separate entrypoints, VLAN separation where available.</p><h3 local-id=\"165e7a3b4283\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-DeploymentTiers\">Deployment Tiers</h3><p local-id=\"062a8cd64393\">The two axes (outpost size, authority placement) collapse into four product modes with explicit contracts:</p><div class=\"table-wrap\"><table data-table-width=\"760\" data-layout=\"default\" data-local-id=\"27de98fecbad\" class=\"confluenceTable\"><tbody><tr data-local-id=\"04a9be5f003f\"><th data-local-id=\"234ee2a152d2\" class=\"confluenceTh\"><p local-id=\"3cf88a3fbfdc\">Tier</p></th><th data-local-id=\"6554d96eaeba\" class=\"confluenceTh\"><p local-id=\"bc3dc91ec2bd\">Local nodes</p></th><th data-local-id=\"ceeabd8e27f6\" class=\"confluenceTh\"><p local-id=\"3099a57479d2\">Authority</p></th><th data-local-id=\"9a489cdb1af1\" class=\"confluenceTh\"><p local-id=\"ced2c8190710\">Use case</p></th><th data-local-id=\"fbc1ab00591c\" class=\"confluenceTh\"><p local-id=\"ba28a7d4ec82\">WAN-outage behavior</p></th></tr><tr data-local-id=\"03ff0b0c185a\"><td data-local-id=\"50d17f6b372a\" class=\"confluenceTd\"><p local-id=\"e20d4d4c4cce\"><strong>Tier 0</strong></p></td><td data-local-id=\"7990820d1a6f\" class=\"confluenceTd\"><p local-id=\"3f7e71e85bfa\">0</p></td><td data-local-id=\"2e2d24250378\" class=\"confluenceTd\"><p local-id=\"85b0fbfc5468\">Cloud</p></td><td data-local-id=\"37d2b030e921\" class=\"confluenceTd\"><p local-id=\"17e3bf13dcfb\">Demo / trial / lab</p></td><td data-local-id=\"e3b5afdde599\" class=\"confluenceTd\"><p local-id=\"05937560158a\">Fleet operation stops or degrades to robot-local safe behavior. Acceptable \u2014 not sold as production autonomy.</p></td></tr><tr data-local-id=\"976d69b6b05a\"><td data-local-id=\"cbae728812ea\" class=\"confluenceTd\"><p local-id=\"0e29ce5d62cc\"><strong>Tier 1</strong></p></td><td data-local-id=\"fff1edb02ee7\" class=\"confluenceTd\"><p local-id=\"7c17fb6c3eca\">1</p></td><td data-local-id=\"68e9f4471159\" class=\"confluenceTd\"><p local-id=\"153633c391fb\">Cloud</p></td><td data-local-id=\"377e186c6c61\" class=\"confluenceTd\"><p local-id=\"54113f173057\">Small deployments wanting local latency, buffering, aggregation, better operator UX</p></td><td data-local-id=\"e150370db71c\" class=\"confluenceTd\"><p local-id=\"9e8a97cc5506\">Local cache/UX degrades; durable config unaffected because it lives in cloud. Node replacement hydrates from cloud.</p></td></tr><tr data-local-id=\"96cb077fc495\"><td data-local-id=\"1f8fdd2d3e4c\" class=\"confluenceTd\"><p local-id=\"18d27c2fa965\"><strong>Tier 3</strong></p></td><td data-local-id=\"822f62171941\" class=\"confluenceTd\"><p local-id=\"654944842ea9\">3 (HA)</p></td><td data-local-id=\"c0d604fb248f\" class=\"confluenceTd\"><p local-id=\"44dca136979a\">Site</p></td><td data-local-id=\"b6c19e737017\" class=\"confluenceTd\"><p local-id=\"4aa13b7654a7\">Serious production factories needing local autonomy</p></td><td data-local-id=\"de727b483941\" class=\"confluenceTd\"><p local-id=\"e9c429049ef7\">Becomes a visibility / remote-management problem, not a factory-death problem. Local operation continues.</p></td></tr><tr data-local-id=\"46fbb419aac5\"><td data-local-id=\"1a21e7e04e14\" class=\"confluenceTd\"><p local-id=\"bb20ab1f66ec\"><strong>Airgap</strong></p></td><td data-local-id=\"2a108f3651d9\" class=\"confluenceTd\"><p local-id=\"4a25abccec70\">3 (usually)</p></td><td data-local-id=\"93e934830bca\" class=\"confluenceTd\"><p local-id=\"b7c516af0aad\">Site</p></td><td data-local-id=\"d19ff56ca2df\" class=\"confluenceTd\"><p local-id=\"93f38cb7c72f\">Regulated / disconnected sites</p></td><td data-local-id=\"61fefb15143e\" class=\"confluenceTd\"><p local-id=\"14e692752b43\">No cloud sync, or delayed/manual/sanitized. Separate operational contract; priced for the field burden it transfers.</p></td></tr></tbody></table></div><p local-id=\"b59ded7e78fa\">This avoids a product fork. There is no &quot;cloud Switchboard&quot; and &quot;edge Switchboard&quot; \u2014 there is one Site Authority implementation with different placement. Tier 0 still uses device and fleet identity so a demo robot is never a snowflake that has to be reprovisioned through a bespoke pipe later.</p><h3 local-id=\"647a88d48c71\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-LocalSoftwareStack\">Local Software Stack</h3><p local-id=\"2e65ac674b40\">The edge stack stays close enough to cloud deployment patterns that engineering does not maintain two religions. Cloud may run ECS and Kubernetes; the outpost runs a small Kubernetes-compatible environment (k3s + containerd). ECS is not reproduced on-prem \u2014 product services are containerized with a placement abstraction (cloud ECS / cloud k8s / site k3s).</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"e5ebde7d-7d27-40c7-94fa-7288aa401516\" data-local-id=\"c0d53aaf8f27\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">OS:        Ubuntu LTS (immutable/container-focused Linux later)\nRuntime:   k3s, containerd, Helm/Flux/Argo-style deploy, local image cache\nStorage:   ZFS local disks; content-addressed blob store on ZFS; MinIO only if S3 semantics needed\nDatabase:  Postgres + PostGIS + pgvector; WAL archiving / snapshot / backup\nMessaging: NATS JetStream for local fanout; Postgres remains source of truth\nSecurity:  mTLS, local trust bundles, TPM-backed node identity, sealed/SOPS secrets, outbound-only tunnel\nObserve:   OpenTelemetry Collector, Prometheus, Grafana, structured logs, local health UI</pre>\n</div></div><p local-id=\"649667dc3ace\">Main local services: Switchboard, Robot Gateway, Map/Semantic API, Artifact Cache, Sync Agent, Provisioning Service, Factory Integration Gateway, local Operator UI. The same components run in a <em>gateway/cache profile</em> for Tier 1 and an <em>authority profile</em> for Tier 3.</p><h3 local-id=\"e0ca6147abb6\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-Switchboard&amp;SpatialStorage\">Switchboard &amp; Spatial Storage</h3><p local-id=\"758f9095b10d\">Switchboard is Postgres-backed. Workflow markings live in Postgres; transition firing is transactional; robot leases use epochs/fencing tokens; command state is durable and idempotent.</p><p local-id=\"0d865c0fef74\">The map system starts boring and expandable \u2014 Postgres + PostGIS + pgvector for metadata, semantic objects, geometry, spatial indexes, and embeddings; ZFS-backed blobs for the chunky cursed spatial things (voxel chunks, point clouds, map tiles, MCAP logs, meshes, TSDFs, occupancy grids). A clean split matters:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"f7e60568-5dd1-4881-aa3f-4c8d6bf922d0\" data-local-id=\"6c3a50f20917\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">Observations:            what robots/sensors saw\nCanonical semantic facts: what the site currently accepts as operationally true\nMap versions:            what robots are allowed to operate against\nBlob chunks:             heavy spatial data streamed as needed</pre>\n</div></div><p local-id=\"f118d2adcf4e\">Robots never download the whole factory. They request the active map version, route-corridor chunks, local workcell chunks, and semantic objects in relevant bounds; dense voxel blobs stream on demand and cache locally. Tier 1 commits map/semantic edits to cloud (and caches active chunks fast); Tier 3 commits map activation and canonical facts locally, then mirrors up.</p><h3 local-id=\"8f34b1cb0a54\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-Authority,Sync&amp;Lost-WriteBehavior\">Authority, Sync &amp; Lost-Write Behavior</h3><p local-id=\"5ef7653f41f3\">Tier 1 is the subtle case: it wants local speed but cloud truth. The answer is to classify state.</p><div class=\"confluence-information-macro confluence-information-macro-tip conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"tip\" data-macro-id=\"598e3de8-b7a2-4d94-90fd-7134bfff11f1\" data-local-id=\"50d1fc583ba9\"><span class=\"aui-icon aui-icon-small aui-iconfont-approve confluence-information-macro-icon\"> </span><div class=\"confluence-information-macro-body\"><p local-id=\"36fe85b0e14b\"><strong>Rule:</strong> Runtime state may be local-fast. Durable authored state must be cloud-committed.</p></div></div><p local-id=\"0b6b7dcd9c8c\"><strong>Runtime state</strong> (local-first, async replicated): heartbeats, command acks, local workflow progress, transient Petri markings, telemetry, traces, local UI state, buffered observations.</p><p local-id=\"2a5a653b7abf\"><strong>Durable authored state</strong> (cloud-committed in Tier 0/1): workflow definitions, fleet configuration, robot enrollment, site config, map activation, policy activation, semantic-zone edits, factory integration config, user/RBAC changes, artifact version activation.</p><p local-id=\"456bb65c4723\">If a Tier 1 node accepts an authored edit, it treats it as a draft/pending intent until cloud acknowledges. Die before cloud commit \u2192 the write didn't happen. Die after cloud commit \u2192 the replacement node hydrates from cloud and converges. This prevents dropped writes and split-brain without sacrificing operator responsiveness. In Tier 3, the local Site Authority commits operational and authored state locally, emits an append-only event log, and replicates events / snapshots / logs / blobs upward; cloud is a mirror and analytics plane, not the writer of site truth.</p><p local-id=\"a47060d9bada\">Tier 3 cloud views must be explicitly stale-aware: a shadow copy fed by replicated events/snapshots is a different thing from a live proxied view through a healthy tunnel, and the two should never be blurred.</p><h3 local-id=\"0e0d5b3a159c\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-ProvisioningRole\">Provisioning Role</h3><p local-id=\"35a094d88bfe\">The same outpost handles factory provisioning. This is not an optional convenience \u2014 it is how the system becomes installable without every field deployment turning into performance art. A site bring-up is a state machine, not a bag of scripts, and each transition emits durable events for auditability, repeatability, supportability, and recovery after someone unplugs the wrong cable (because of course they did):</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"08c42cc1-2f74-429b-902a-b0dad6db521b\" data-local-id=\"a3059a87ad5a\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">uninitialized -&gt; claimed by tenant -&gt; network qualified -&gt; outpost enrolled\n-&gt; robots discovered -&gt; robots enrolled -&gt; artifacts staged\n-&gt; map imported/created -&gt; frames calibrated -&gt; factory integrations connected\n-&gt; workflows staged -&gt; acceptance tests passed -&gt; production ready</pre>\n</div></div><p local-id=\"e49c95210853\">The same provisioning model runs inside the HMND factory, where the outpost can act as a secure local provisioning authority \u2014 issuing local enrollment material even when cloud is unavailable, then batch-syncing manufacturing/provisioning records back. That factory case has a different (stronger) trust posture than customer fleet operation: offline signing requires stronger key protection and clearer audit semantics.</p><h3 local-id=\"04e08caf2f54\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-Identity&amp;PKI\">Identity &amp; PKI</h3><p local-id=\"ad56e01c4c3a\">The model separates four things that must not be collapsed:</p><div class=\"table-wrap\"><table data-table-width=\"760\" data-layout=\"default\" data-local-id=\"2e4750a37c0f\" class=\"confluenceTable\"><tbody><tr data-local-id=\"406ee6d6c6cf\"><th data-local-id=\"a173651c4d1a\" class=\"confluenceTh\"><p local-id=\"4c786fea29a7\">Concept</p></th><th data-local-id=\"1d7f90f6a588\" class=\"confluenceTh\"><p local-id=\"16790d990ff1\">Answers the question</p></th><th data-local-id=\"ac2b4230152d\" class=\"confluenceTh\"><p local-id=\"aeba344e0368\">Lifetime</p></th></tr><tr data-local-id=\"45b32d0a595a\"><td data-local-id=\"5efdfecb63c8\" class=\"confluenceTd\"><p local-id=\"cd41b0f68c5f\"><strong>Device identity</strong></p></td><td data-local-id=\"ec7051ae8309\" class=\"confluenceTd\"><p local-id=\"4f679dd2fb8b\">What physical HMND-managed thing is this?</p></td><td data-local-id=\"6a4adc34b3d8\" class=\"confluenceTd\"><p local-id=\"41cec39a20ef\">Long-lived / immutable (provenance)</p></td></tr><tr data-local-id=\"270770a985a1\"><td data-local-id=\"c04ccefa7352\" class=\"confluenceTd\"><p local-id=\"255d471dbbbc\"><strong>Fleet identity</strong></p></td><td data-local-id=\"ce12ee38b5e1\" class=\"confluenceTd\"><p local-id=\"da8914c7908b\">Which customer/site/fleet may this thing participate in?</p></td><td data-local-id=\"262edc77076b\" class=\"confluenceTd\"><p local-id=\"cba6d3271662\">Medium-lived, mutable, rotated</p></td></tr><tr data-local-id=\"0826accf9dc0\"><td data-local-id=\"9e87bfeb30a2\" class=\"confluenceTd\"><p local-id=\"3f6213d5fa93\"><strong>Policy / entitlement</strong></p></td><td data-local-id=\"1fa468c0b3c9\" class=\"confluenceTd\"><p local-id=\"3fb645c1c8fd\">What is this thing allowed to do?</p></td><td data-local-id=\"7bf7f48ae98d\" class=\"confluenceTd\"><p local-id=\"82cea30686d5\">Per entitlement doc</p></td></tr><tr data-local-id=\"35daa3ce81fd\"><td data-local-id=\"0a4249c76b3b\" class=\"confluenceTd\"><p local-id=\"57478758b032\"><strong>Lease</strong></p></td><td data-local-id=\"ad12b9bfe134\" class=\"confluenceTd\"><p local-id=\"8afb3c53a0da\">What is this thing allowed to do right now?</p></td><td data-local-id=\"fcc4a615c403\" class=\"confluenceTd\"><p local-id=\"49e4754b91b1\">Short-lived, renewable</p></td></tr></tbody></table></div><p local-id=\"5c1fdd256ba9\"><strong>Device identity</strong> roots in AWS PCA. During manufacturing/provisioning we mint a device cert for each robot, outpost node, gateway, or managed device. Outpost nodes are first-class devices (type e.g. <code>outpost_node</code>) \u2014 visible in the cloud control plane with serial, SKU, cert status, software version, site assignment, health, audit trail.</p><p local-id=\"d83979f19f30\"><strong>Fleet identity</strong> is mutable enrollment identity, minted under a per-fleet/per-site intermediate CA in the HMND hierarchy when a device is assigned to a customer/site/fleet. The outpost terminates mTLS using fleet trust: it validates that a presented cert chains to the correct fleet CA, isn't expired, isn't locally revoked, matches the right tenant/site/fleet, and corresponds to an enrolled robot. Same fleet-identity model whether robots connect to cloud authority (Tier 0/1) or local Site Authority (Tier 3).</p><p local-id=\"a71d6558b1c8\"><strong>Outpost identity</strong> has at least three layers: device identity (physical node), cluster-membership identity (allowed to join this outpost cluster), and service identity (local services present mTLS certs). A Tier 3 Site Authority needs local serving certs plus the fleet trust bundle to authenticate robots without a cloud round trip.</p><div class=\"confluence-information-macro confluence-information-macro-note conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"note\" data-macro-id=\"bbe6da3f-f80f-4796-9cfd-f467866a1baf\" data-local-id=\"13d4174a7645\"><span class=\"aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon\"> </span><div class=\"confluence-information-macro-body\"><p local-id=\"946eb6dc69cb\"><strong>Local CA delegation:</strong> For ordinary connected deployments, cloud mints fleet certs and distributes trust bundles; the outpost validates, it does not mint long-lived fleet identity. Only factory provisioning / airgap / special offline modes get a delegated local intermediate CA or short-lived signing authority \u2014 TPM/HSM-backed, tightly audited, rotated, scoped. Do not casually give every customer outpost a powerful intermediate CA. That's how you create a certificate pi\u00f1ata.</p></div></div><p local-id=\"ae7683bcb963\"><strong>Revocation</strong> is bounded by connectivity. Online sites sync revocation/denylist from cloud; offline periods rely on last-known revocation state plus cert expiry to bound risk. Lifetimes: device cert long-lived (bootstrap/provenance), fleet cert medium-lived (rotated), session/workload cert short-lived (runtime mTLS). If a robot is removed from a fleet while the site is offline, that revocation can't take effect locally until sync resumes \u2014 unless the local operator performs it. No amount of PKI incense changes physics.</p><h3 local-id=\"77651ba1a726\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-BYON:Customer-ProvidedNetwork\">BYON: Customer-Provided Network</h3><p local-id=\"6625c8450eba\">Assume the customer provides Wi-Fi, switching, routing, firewall policy, DNS, DHCP/static addressing, NTP, power, rack space, and egress unless contracted otherwise. BYON is not an exception \u2014 it is a first-class deployment mode. The outpost must qualify and survive customer infrastructure, not pretend it owns the network.</p><p local-id=\"1e1ddca6abe4\">Connectivity is <strong>outbound-only</strong> to HMND cloud for Tier 1/3 \u2014 no inbound firewall holes for normal operation; remote access runs over a mutually authenticated tunnel the outpost initiates. The architecture supports network segregation where available:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"ebd765a8-e147-43a0-8337-04fca81fecad\" data-local-id=\"d99a79f513b0\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">robot network:               robot-to-outpost traffic\nfactory integration network: WMS/MES/VDA5050/OPC UA/MQTT/etc.\nmanagement network:          BMC, admin UI, support access\negress network:              outbound tunnel and cloud sync</pre>\n</div></div><p local-id=\"4c4a26c83ea7\">Small deployments may collapse these onto one customer LAN; production should strongly prefer VLAN separation; regulated deployments may mandate it. The outpost should not depend on customer Wi-Fi being good \u2014 it should measure it, complain loudly, and refuse production readiness if the network is below minimum.</p><h3 local-id=\"7c1b101d0f21\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-Network&amp;PowerQualification\">Network &amp; Power Qualification</h3><p local-id=\"e4cdd1f3cf77\">The customer is responsible for power and network meeting defined requirements. We provide a qualification checklist and an automated qualification tool. The network-qualification phase tests outbound cloud reachability, DNS, NTP sanity, TLS interception, proxy requirements, MTU, packet loss, latency, jitter, robot VLAN reachability, multicast assumptions, firewall rules, and required ports; power covers outlet/circuit/UPS/grounding/rack/thermal.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"84ffe89a-4c2a-4787-a597-165498f02222\" data-local-id=\"fa01244effab\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">Tier 1:  one of everything  (one node, one path, one UPS \u2014 degrades if any dies, by contract)\nTier 3:  three servers, two switches, dual-homed nodes, redundant power/UPS,\n         separate management access \u2014 enough redundancy to avoid cosplay HA</pre>\n</div></div><p local-id=\"4ae0a935ee90\">WAN redundancy is optional for Tier 3 because the factory continues locally without WAN; dual WAN helps cloud visibility/support/analytics freshness but is not required for local autonomy.</p><h3 local-id=\"4da4b423b5db\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-SegregationModel\">Segregation Model</h3><p local-id=\"c6cd67c75e21\">Four dimensions, kept distinct:</p><ul local-id=\"294bb781c3bc\"><li local-id=\"eb0dd35c1e1a\"><p local-id=\"f52e660a85d2\"><strong>Tenant/site</strong> \u2014 each site belongs to exactly one tenant; the default customer outpost is single-tenant and assigned to exactly one site (or a tightly controlled set).</p></li><li local-id=\"3f01701b6285\"><p local-id=\"4e5e074fc52e\"><strong>Network</strong> \u2014 robot / factory-integration / management / egress traffic separable; not mandatory for every pilot, but cleanly supported.</p></li><li local-id=\"2f063209e14f\"><p local-id=\"aef53e830bf9\"><strong>Trust</strong> \u2014 device PKI, fleet PKI, service/workload identity, and entitlement policy are separate. Manufacturing provenance does not authorize joining ACME's fleet; a fleet cert does not authorize every action; a lease grants current operational authority.</p></li><li local-id=\"3b03b0752843\"><p local-id=\"e6aa43fc0ff3\"><strong>Data</strong> \u2014 runtime telemetry, customer maps, semantic facts, robot logs, support sessions, training exports all carry explicit tenant/site ownership and retention policy. Cloud analytics can be multi-tenant internally, but the control plane preserves tenant boundaries.</p></li></ul><h2 local-id=\"9e66fb6047d3\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-ProductContract\">Product Contract</h2><p local-id=\"0f0445d940f3\">The contract per tier should be explicit and surfaced in the UI so operators and support never have to infer which side owns truth (that's how you get ghost stories):</p><ul local-id=\"2982bc73bff9\"><li local-id=\"262ff4208828\"><p local-id=\"4b860d0af0ea\"><strong>Tier 0</strong> \u2014 cloud authority, no local autonomy guarantee.</p></li><li local-id=\"8c467193a590\"><p local-id=\"6232495a0364\"><strong>Tier 1</strong> \u2014 cloud authority with local acceleration; fast while gateway + WAN are healthy; runtime data may buffer locally; durable config requires cloud commit; if the node dies, cloud truth survives.</p></li><li local-id=\"76d514704c74\"><p local-id=\"6d0e03459194\"><strong>Tier 3</strong> \u2014 local HA authority; continues during WAN outage; cloud receives a replicated mirror; remote support/analytics degrade when disconnected but local operation continues.</p></li><li local-id=\"992820b977cd\"><p local-id=\"c9ce4fd52227\"><strong>Airgap</strong> \u2014 local authority with restricted sync; operational responsibility and update mechanics are special and priced accordingly.</p></li></ul><p local-id=\"f3ccf413928d\">A site page in the UI should show: authority placement, outpost size, current authority health, cloud sync lag, local mode, certificate status, robot enrollment status, network qualification status, last successful backup, last successful artifact sync.</p><h2 local-id=\"c8227c322441\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-FinalArchitecturePrinciple\">Final Architecture Principle</h2><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"0b98afa6-4696-43a6-8a6a-4c09aa35cc86\" data-local-id=\"8a3e1cec0d9e\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">Device identity proves the hardware.\nFleet identity proves enrollment.\nPolicy proves entitlement.\nLease proves current authority.\n\nCloud authority gives low-footprint deployments.\nSite authority gives local autonomy.\n\nThe outpost is the movable substrate:\n  zero nodes for demos,\n  one node for gateway/cache/proxy/provisioning,\n  three nodes for local HA authority.</pre>\n</div></div><p local-id=\"684a65065917\">The system is sold and built as one logical control plane with movable authority \u2014 not cloud product plus edge product plus factory tool plus bespoke provisioning scripts. That way lies madness, YAML archaeology, and a field engineer named Dave who knows the only working incantation.</p><h1 local-id=\"0d03b6d9e3f6\" id=\"Spec:HMNDOutpost&amp;SiteAuthority-AppendixA:HardwareProfile&amp;BOM\"><span class=\"inline-comment-marker\" data-ref=\"083dbd5b-d246-4d08-9894-3d2cc899face\">Appendix A: Hardware Profile &amp; BOM</span></h1><p local-id=\"c038e1de3bb7\">The same server hardware is usable for Tier 1 and Tier 3 \u2014 Tier 1 ships one node, Tier 3 ships three. Same image, same provisioning path, same spare strategy, same thermal/power assumptions.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"6eb4ea62-b090-42af-bfcc-5da58d434b82\" data-local-id=\"3758d26b921a\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">short-depth 1U/2U edge server\n24-32 CPU cores\n256 GB ECC RAM\n2x NVMe OS mirror\n4x SSD/NVMe data drives\n2x 10/25GbE\ndedicated BMC/IPMI/iDRAC-style management\nTPM 2.0\ndual PSU\nPCIe x16 GPU-capable slot (GPU optional; reserved for possible local inference)\nPSU + airflow headroom for a future GPU</pre>\n</div></div><p local-id=\"feb804e392fe\">Rough installed-BOM targets (excluding field labor, support margin, spare pool, and customer network remediation \u2014 where the little goblins hide):</p><div class=\"table-wrap\"><table data-table-width=\"760\" data-layout=\"default\" data-local-id=\"e12da6b1ca55\" class=\"confluenceTable\"><tbody><tr data-local-id=\"2245b9ad694f\"><th data-local-id=\"9c68fcc4a3a8\" class=\"confluenceTh\"><p local-id=\"8c549f100dbc\">Tier</p></th><th data-local-id=\"be821577d518\" class=\"confluenceTh\"><p local-id=\"4128675bda16\">Range</p></th><th data-local-id=\"350a1621a994\" class=\"confluenceTh\"><p local-id=\"3e61b060dbe3\">Target SKU</p></th></tr><tr data-local-id=\"6470094599e7\"><td data-local-id=\"14e543944590\" class=\"confluenceTd\"><p local-id=\"a47fd4f3d82a\">Tier 1</p></td><td data-local-id=\"ef88e89ad36c\" class=\"confluenceTd\"><p local-id=\"615e701bc9a3\">\u00a312k\u2013\u00a330k</p></td><td data-local-id=\"27995f08720b\" class=\"confluenceTd\"><p local-id=\"f7a2f310b369\">~\u00a320k for a serious SKU</p></td></tr><tr data-local-id=\"bb72e1f9be72\"><td data-local-id=\"05f76074e257\" class=\"confluenceTd\"><p local-id=\"c160da65efb3\">Tier 3</p></td><td data-local-id=\"a87d9ed6c272\" class=\"confluenceTd\"><p local-id=\"81d21b967b5d\">\u00a340k\u2013\u00a390k</p></td><td data-local-id=\"4a6ca4fd1521\" class=\"confluenceTd\"><p local-id=\"d85bf9234a5e\">~\u00a360k\u2013\u00a380k for production HA</p></td></tr></tbody></table></div>"
        },
        {
          "id": "1968111692",
          "title": "Capability Planning",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1968111692",
          "last_modified": "2026-06-02T10:03:08.959Z",
          "created_at": "2026-05-12T16:55:21.278Z",
          "body_html": "<p local-id=\"a1e9d2ae054d\" /><blockquote local-id=\"c9e9ec84f28f\"><p local-id=\"7e0cf71ae404\">This builds on the <a href=\"https://docs.google.com/document/d/11ZV_GzaNN1R7v8E01K4uLY9pVBi7CTG4T2XSkOWS26A/edit?tab=t.0\" class=\"external-link\" rel=\"nofollow\">May framework doc</a> \u2014 the proposal that introduced maturity levels (L1\u2013L5) and the case for organizing engineering goals by <em>capability</em> rather than by team. What follows extends that into a complete planning system: where each layer lives, who owns it, what rituals run them, and how AI maintains the day-to-day state so we don't end up with another 100KB Google Doc.</p><p local-id=\"46b325502487\">Working draft. Tooling and schemas are in an appendix to keep the body focused on intent.</p></blockquote><h1 local-id=\"d526dc395fae\" id=\"CapabilityPlanning-Motivation\">Motivation</h1><p local-id=\"f8d16e7b233a\">Our <a href=\"https://docs.google.com/document/d/1CXLoFfaE7sZpUYq6lqSiSLtr-CCNq_kDBFXX4aESMQ4/\" class=\"external-link\" rel=\"nofollow\">previous planning doc</a> was trying to do many things at the same time \u2014 strategic roadmap, cross-team planning, research bets \u2014 but it failed as a tool to make engineering work <em>legible </em>to the rest of the org.  Product and other stakeholders had a difficult seeing what engineering is working on and why.  Additionally, there were a number of other artifacts like robot allocations and goals that existed which often could fall out of sync.  This doc outlines a new capability planning process which aims to resolve these challenges without adding too much additional toil onto engineering leaders.</p><h1 local-id=\"c956e94b420a\" id=\"CapabilityPlanning-ThreeLayers\">Three Layers</h1><p local-id=\"1c4831192db3\">Instead of trying to flatten everything out, we\u2019ll consider 3 broad layers to planning:</p><p local-id=\"ae693c48aab8\"><strong>Opportunity</strong> is what the market wants \u2014 customer asks, partner interest, expansion targets \u2014 written as outcomes, not as solutions. &quot;Amazon wants box handling by July, mixed SKUs, 80% accuracy.&quot; Not &quot;implement box handling.&quot; Opportunities are owned by Product and live in the <a href=\"https://sklvc.atlassian.net/jira/polaris/projects/PB\" class=\"external-link\" rel=\"nofollow\"><span class=\"inline-comment-marker\" data-ref=\"1be21ced-ae9a-43dd-a110-b14c3a4ec044\">PB board</span></a>; engineering reads them but doesn't write them.</p><p local-id=\"d58ec5dd3755\"><strong>Capability</strong> is what the robot can do, at some maturity.  Capabilities are generally never completed \u2014 they mature over time, potentially regressing in maturity if expectations shift.  Capabilities should be granular enough to allow for meaningful planning (\u201cThe robot can robot\u201d would be a capability, but a pretty terrible one), but not so granular as to overwhelm planning efforts.  Think of efforts like \u201cOne-Click Bringup\u201d, \u201cWorkflow Authoring\u201d or \u201cTote Handling at Kinematic Limits\u201d as broad capabilities we may consider here.</p><p local-id=\"7694e44f00b4\"><strong>Delivery</strong> is the work. A capability isn't owned by any one team \u2014 it pulls work from controls, applications, simulation, navigation, and so on \u2014 and that work is broken into epics, mostly team-bounded. Each team owns its own epics under the capability; the collection of those epics across teams is what makes cross-team dependencies visible naturally. When a capability is stuck, the gating epic (in whichever team's board it lives) is the locator. Stories live under their team's epic in whatever board the team already uses (HEAP, HECP, HELM, HERE, HERM, HESA, HECO, DCP, etc.).</p><p local-id=\"547313985d30\">The Capability layer here is the glue which ties ongoing engineering deliverables (the \u201chow\u201d) to specific product opportunities (the \u201cwho\u201d, \u201cwhere\u201d and \u201cwhy\u201d).</p><div class=\"panel conf-macro output-block\" style=\"background-color: #EAE6FF;border-color: #998DD9;border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"panel\" data-macro-id=\"\"><div class=\"panelContent\" style=\"background-color: #EAE6FF;\">\n<p local-id=\"202843be581f\">Note that this relationship isn\u2019t strictly hierarchical.  Delivery items may contribute to many capabilities, and capabilities may enable many product opportunities.  The goal here isn\u2019t to perfect model all work and dependencies in this dogmatic way.  <strong>We want to make the simplest approximation we can to keep engineering legible to our stakeholders while minimizing our own planning overhead</strong>.</p>\n</div></div><h1 local-id=\"b74efbe8580d\" id=\"CapabilityPlanning-CapabilityMaturitylevels\">Capability Maturity levels</h1><p local-id=\"b30a271d7709\">Maturity is the shared language between engineering and every other function. It replaces the unstable, jargon-heavy way engineering currently describes progress. The five levels are TRL-style and named for what each one <em>unlocks externally</em>:</p><div class=\"table-wrap\"><table data-table-width=\"1572\" data-layout=\"center\" data-local-id=\"0f6948ec050a\" class=\"confluenceTable\"><tbody><tr data-local-id=\"7401cbb06729\"><th data-local-id=\"8a02a1fe3196\" class=\"confluenceTh\"><p local-id=\"6b3bada4cadf\">Level</p></th><th data-local-id=\"56ad3d6bbcec\" class=\"confluenceTh\"><p local-id=\"587b50718417\">Name</p></th><th data-local-id=\"2ffb65454bdc\" class=\"confluenceTh\"><p local-id=\"73c877ae180b\">What it unlocks</p></th></tr><tr data-local-id=\"af460f0e83c4\"><td data-local-id=\"a5a695ece2be\" class=\"confluenceTd\"><p local-id=\"3b4e3a48b60e\"><strong>L1</strong></p></td><td data-local-id=\"198c7bda8cfe\" class=\"confluenceTd\"><p local-id=\"17a4b857a439\"><strong>Developer-ready</strong></p></td><td data-local-id=\"d36bb2b65b0c\" class=\"confluenceTd\"><p local-id=\"5e2df18fbe1d\">Internal eng testing and integration. Works enough to develop against. Not repeatable under observation. Validates feasibility.</p></td></tr><tr data-local-id=\"fea749b0c8f3\"><td data-local-id=\"8d86727371a4\" class=\"confluenceTd\"><p local-id=\"4c90e35a81f0\"><strong>L2</strong></p></td><td data-local-id=\"631b4e67e9d2\" class=\"confluenceTd\"><p local-id=\"5c2f72115c0c\"><strong>Film-ready</strong></p></td><td data-local-id=\"3e8844d8c6fe\" class=\"confluenceTd\"><p local-id=\"8dafc9050d74\">Repeatable under controlled conditions. Failures recoverable and editable around. Unlocks team updates, recruiting content, PR video, early marketing.</p></td></tr><tr data-local-id=\"c7d23f5e9f78\"><td data-local-id=\"d93006eba9aa\" class=\"confluenceTd\"><p local-id=\"e0bfbe0b5438\"><strong>L3</strong></p></td><td data-local-id=\"b651ea1df049\" class=\"confluenceTd\"><p local-id=\"bf8f28d9cbf2\"><strong>Demo-ready</strong></p></td><td data-local-id=\"84f5c4bedf9d\" class=\"confluenceTd\"><p local-id=\"6997734c3405\">Reliable enough to run live for VIPs without a developer on standby. Failure modes known and recoverable. Unlocks investor demos, partner exec meetings, Tier-1 customers.</p></td></tr><tr data-local-id=\"ec321440c13f\"><td data-local-id=\"9c8eaa88fcc0\" class=\"confluenceTd\"><p local-id=\"d62643d8ba2c\"><strong>L4</strong></p></td><td data-local-id=\"b8e3362db239\" class=\"confluenceTd\"><p local-id=\"926bc39c5e63\"><strong>POC-ready</strong></p></td><td data-local-id=\"22be5c11c921\" class=\"confluenceTd\"><p local-id=\"80c978af2b07\">Works reliably outside Humanoid's lab. Operable by a Humanoid deployment engineer (no specialized R&amp;D eng on standby). Unlocks CEVA, Amazon, Schaeffler POC programs.</p></td></tr><tr data-local-id=\"db0fd72c2c2a\"><td data-local-id=\"43fb96439175\" class=\"confluenceTd\"><p local-id=\"306c043fda5b\"><strong>L5</strong></p></td><td data-local-id=\"5e4a40ab3523\" class=\"confluenceTd\"><p local-id=\"0d0bfa14fb09\"><strong>Pilot-ready</strong></p></td><td data-local-id=\"3fb3b1929e45\" class=\"confluenceTd\"><p local-id=\"d4ac39d6e2a3\">Hits customer-agreement reliability and performance targets. Ideally operable outside of Humanoid entirely \u2014 by the customer's own staff. Incident response and update mechanisms exist. Unlocks pilot agreements, recurring revenue, SLAs.</p></td></tr></tbody></table></div><div class=\"panel conf-macro output-block\" style=\"background-color: #EAE6FF;border-color: #998DD9;border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"panel\" data-macro-id=\"\"><div class=\"panelContent\" style=\"background-color: #EAE6FF;\">\n<p local-id=\"1b3843a3da6e\">Not all capabilities are expected to reach all levels of maturity.  For example, we don\u2019t really expect to expose our CI infrastructure to customers, but we may peel off pieces as part of the capability factory.  Similar for Simulation and other more engineering-centric capabilities.</p>\n</div></div><p local-id=\"7184cefb1ad9\">The names matter because they're what non-engineers read. When an investor asks &quot;what can I see today?&quot; \u2014 L3 answers. When a customer asks &quot;will this work in my facility?&quot; \u2014 L4 answers. Marketing wants L2. Production sales targets are L5 commitments.</p><p local-id=\"752aa42387cc\">Each capability carries its current maturity <em>as its workflow status</em>, with the level names as the status values. Transitions are auditable \u2014 when a capability advances to L3 the date and author are captured in history automatically, no separate maturity log needed. Transitions are allowed in both directions because capabilities can regress (a stable L3 demo can become L2 if reliability degrades) and honest regression tracking matters.</p><h1 local-id=\"e531a319e5a5\" id=\"CapabilityPlanning-GoalsandEpics\">Goals and Epics</h1><p local-id=\"b2c828548a16\">As mentioned above, Capabilities are implemented by various engineering teams tracking deliverables as epics, stories and tasks.  In addition to deliverables, we also may want to track goals when it makes sense.  Capabilities have a \u201cGoal\u201d field to allow tracking goals at the capability level, in addition to the various epics that teams may be executing on to make the capability more mature.  In this framework, its possible that a goal could be achieved prematurely, without ever closing out epics.  Its also possible that finishing all the planned work doesn\u2019t advance the goal as far as desired.</p><div class=\"panel conf-macro output-block\" style=\"background-color: #EAE6FF;border-color: #998DD9;border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"panel\" data-macro-id=\"\"><div class=\"panelContent\" style=\"background-color: #EAE6FF;\">\n<p local-id=\"3afc2f73a6fd\">Goals define a measurable outcome related to some capability.  Epics define the scope of work to make progress toward these goals.</p>\n</div></div><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20260601-174333.png\" width=\"1338\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1968111692/image-20260601-174333.png?version=1&amp;modificationDate=1780335831237&amp;cacheVersion=1&amp;api=v2&amp;width=1338&amp;height=423\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1968111692/image-20260601-174333.png?version=1&amp;modificationDate=1780335831237&amp;cacheVersion=1&amp;api=v2\" data-height=\"790\" data-width=\"2496\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"2040430643\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20260601-174333.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1968111692\" data-linked-resource-container-version=\"10\" data-media-id=\"09261d9e-ed8c-43f1-974c-d93b8ecf1640\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1968111692/image-20260601-174333.png?version=1&amp;modificationDate=1780335831237&amp;cacheVersion=1&amp;api=v2&amp;width=2676&amp;height=846 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1968111692/image-20260601-174333.png?version=1&amp;modificationDate=1780335831237&amp;cacheVersion=1&amp;api=v2&amp;width=1338&amp;height=423 1x\"></span><p local-id=\"0ab351220a0a\">Some efforts may be more amenable to goals while others may be more about landing big changes as epics.  Depending on the level of maturity, different perspectives may be needed to effectively manage the effort.  We can at least organize these around top-level capabilities to provide a consistent view to external stakeholders, while internally we can choose to emphasize one or the other as it makes sense.  In this example above, notice that there are a few existing HECO tickets linked as implementation details, along with 2 goals defined in the right-hand side.</p><p local-id=\"99ccf29b76e6\">Note also the <code>Amount</code> field - this, along with the <code>alpha-wheelbase-poc-symphony</code> label, is used to <a href=\"https://live.internal.hmnd.ai/agents/?file=alphaclaw%2F019e5019-9ba8-7691-8bc9-f71b20924729%2Frobot-allocation-dashboard%2Fapp.py\" class=\"external-link\" rel=\"nofollow\">compute robot allocations dynamically</a>.  </p><h1 local-id=\"342b62c8420f\" id=\"CapabilityPlanning-Timeline\">Timeline</h1><p local-id=\"bd5f93aae4af\">Every capability is expected to be a long-duration effort which doesn\u2019t really have a defined start or end date, but not all capabilities are \u201cactive\u201d at the same time.  Each capability has a Target Start Date and Target End Date which can be used to create a simple timeline to help assist in planning activities.  This is how we know which capabilities are the focus of any given month or quarter.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20260601-174515.png\" width=\"1330\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1968111692/image-20260601-174515.png?version=1&amp;modificationDate=1780335921313&amp;cacheVersion=1&amp;api=v2&amp;width=1330&amp;height=691\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1968111692/image-20260601-174515.png?version=1&amp;modificationDate=1780335921313&amp;cacheVersion=1&amp;api=v2\" data-height=\"1248\" data-width=\"2401\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"2041184301\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20260601-174515.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1968111692\" data-linked-resource-container-version=\"10\" data-media-id=\"0dce2669-84ef-4a69-993f-b483c8b19ad1\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1968111692/image-20260601-174515.png?version=1&amp;modificationDate=1780335921313&amp;cacheVersion=1&amp;api=v2&amp;width=2660&amp;height=1382 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1968111692/image-20260601-174515.png?version=1&amp;modificationDate=1780335921313&amp;cacheVersion=1&amp;api=v2&amp;width=1330&amp;height=691 1x\"></span><h1 local-id=\"a175290f8502\" id=\"CapabilityPlanning-MonthlyScope\">Monthly Scope</h1><p local-id=\"1a44618e7742\">We can use the monthly filter (which will be updated each month) to see the current month\u2019s capabilities.   In the monthly planning meeting for example, we can go through the in-scope capabilities (see the left-hand side) and ensure that we have the right epics linked and goals defined.  </p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20260601-174923.png\" width=\"1321\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1968111692/image-20260601-174923.png?version=1&amp;modificationDate=1780336172267&amp;cacheVersion=1&amp;api=v2&amp;width=1321&amp;height=681\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1968111692/image-20260601-174923.png?version=1&amp;modificationDate=1780336172267&amp;cacheVersion=1&amp;api=v2\" data-height=\"1240\" data-width=\"2404\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"2040594512\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20260601-174923.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1968111692\" data-linked-resource-container-version=\"10\" data-media-id=\"ae4c5124-9349-4197-b8d7-cedd17cef832\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1968111692/image-20260601-174923.png?version=1&amp;modificationDate=1780336172267&amp;cacheVersion=1&amp;api=v2&amp;width=2642&amp;height=1362 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1968111692/image-20260601-174923.png?version=1&amp;modificationDate=1780336172267&amp;cacheVersion=1&amp;api=v2&amp;width=1321&amp;height=681 1x\"></span><p local-id=\"11145587a075\">What\u2019s nice about this is that we can see a direct view of this in Confluence itself for a nice table:</p><table class=\"jiraWorkItemMacroListViewTable\"><thead><tr><th class=\"confluenceTh\">Type</th><th class=\"confluenceTh\">Key</th><th class=\"confluenceTh\">Summary</th><th class=\"confluenceTh\">Assignee</th><th class=\"confluenceTh\">Priority</th><th class=\"confluenceTh\">Status</th><th class=\"confluenceTh\">Updated</th></tr></thead><tbody><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-10\">HMND-10</a></td><td class=\"confluenceTd\">One-Click Bringup</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7655017b-55c7-4902-aafd-678b431ce466/ccc59fd7-ece7-4b2d-ab53-f2ce4d68278d/48\" alt=\"Matt Klingensmith\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Matt Klingensmith</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L3 Demo-ready</td><td class=\"confluenceTd\">16 Jul 2026, 13:15</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-14\">HMND-14</a></td><td class=\"confluenceTd\">OTA and Release Lifecycle Management</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:1c39ff9c-40f1-4814-8ddd-22275692d623/bbeb01d5-1ca3-44b1-ac36-4de63b40d017/48\" alt=\"Daniel Hoffman\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Daniel Hoffman</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L4 POC-ready</td><td class=\"confluenceTd\">03 Jul 2026, 15:17</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-15\">HMND-15</a></td><td class=\"confluenceTd\">AI-enabled Workflow Editing</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7655017b-55c7-4902-aafd-678b431ce466/ccc59fd7-ece7-4b2d-ab53-f2ce4d68278d/48\" alt=\"Matt Klingensmith\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Matt Klingensmith</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L3 Demo-ready</td><td class=\"confluenceTd\">21 Jul 2026, 08:44</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-16\">HMND-16</a></td><td class=\"confluenceTd\">Map &amp; Workflow Sharing and Synchronization</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7655017b-55c7-4902-aafd-678b431ce466/ccc59fd7-ece7-4b2d-ab53-f2ce4d68278d/48\" alt=\"Matt Klingensmith\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Matt Klingensmith</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L3 Demo-ready</td><td class=\"confluenceTd\">16 Jul 2026, 13:50</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-21\">HMND-21</a></td><td class=\"confluenceTd\">Operational Metrics and KPIs</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:15d56293-96ff-40d2-a06d-912f776e2042/a630846a-6205-4c5f-ad3e-4fa46817e742/48\" alt=\"Cody Griffin\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Cody Griffin</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L1 Developer-ready</td><td class=\"confluenceTd\">10 Jul 2026, 14:37</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-25\">HMND-25</a></td><td class=\"confluenceTd\">Site Mapping</td><td class=\"confluenceTd\"></td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L3 Demo-ready</td><td class=\"confluenceTd\">25 Jun 2026, 08:42</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-27\">HMND-27</a></td><td class=\"confluenceTd\">Fleet Visualization</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7655017b-55c7-4902-aafd-678b431ce466/ccc59fd7-ece7-4b2d-ab53-f2ce4d68278d/48\" alt=\"Matt Klingensmith\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Matt Klingensmith</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L1 Developer-ready</td><td class=\"confluenceTd\">17 Jul 2026, 15:26</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-79\">HMND-79</a></td><td class=\"confluenceTd\">Execution (System 2) Agent</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7655017b-55c7-4902-aafd-678b431ce466/ccc59fd7-ece7-4b2d-ab53-f2ce4d68278d/48\" alt=\"Matt Klingensmith\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Matt Klingensmith</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L1 Developer-ready</td><td class=\"confluenceTd\">24 Jul 2026, 15:48</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-39\">HMND-39</a></td><td class=\"confluenceTd\">Workflow Deployment</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7655017b-55c7-4902-aafd-678b431ce466/ccc59fd7-ece7-4b2d-ab53-f2ce4d68278d/48\" alt=\"Matt Klingensmith\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Matt Klingensmith</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L1 Developer-ready</td><td class=\"confluenceTd\">24 Jul 2026, 15:48</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-38\">HMND-38</a></td><td class=\"confluenceTd\">Robot Enrollment</td><td class=\"confluenceTd\"></td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">03 Jun 2026, 12:46</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-47\">HMND-47</a></td><td class=\"confluenceTd\">Fleet Health &amp; Diagnostics</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:7655017b-55c7-4902-aafd-678b431ce466/ccc59fd7-ece7-4b2d-ab53-f2ce4d68278d/48\" alt=\"Matt Klingensmith\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Matt Klingensmith</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L1 Developer-ready</td><td class=\"confluenceTd\">17 Jul 2026, 15:26</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-53\">HMND-53</a></td><td class=\"confluenceTd\">Universal Cloud Client for all Devices</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:1c39ff9c-40f1-4814-8ddd-22275692d623/bbeb01d5-1ca3-44b1-ac36-4de63b40d017/48\" alt=\"Daniel Hoffman\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Daniel Hoffman</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">26 Jun 2026, 21:51</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-54\">HMND-54</a></td><td class=\"confluenceTd\">Scaled Secure Manufacturing - Test Harness and SQL Database</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:1c39ff9c-40f1-4814-8ddd-22275692d623/bbeb01d5-1ca3-44b1-ac36-4de63b40d017/48\" alt=\"Daniel Hoffman\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Daniel Hoffman</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">10 Jul 2026, 18:58</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-55\">HMND-55</a></td><td class=\"confluenceTd\">Device Platform Security (Secure Boot)</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:1c39ff9c-40f1-4814-8ddd-22275692d623/bbeb01d5-1ca3-44b1-ac36-4de63b40d017/48\" alt=\"Daniel Hoffman\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Daniel Hoffman</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">25 Jun 2026, 15:40</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-56\">HMND-56</a></td><td class=\"confluenceTd\">Realistic Simulation</td><td class=\"confluenceTd\"><img src=\"https://secure.gravatar.com/avatar/f0a051628aecd1e437b2727d2045e491?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FDS-5.png\" alt=\"Dmitriy Shingarey\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Dmitriy Shingarey</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L1 Developer-ready</td><td class=\"confluenceTd\">21 Jul 2026, 18:28</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-57\">HMND-57</a></td><td class=\"confluenceTd\">CI [Placeholder]</td><td class=\"confluenceTd\"><img src=\"https://secure.gravatar.com/avatar/831d6988a914f8d065871e450bd83377?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FRD-5.png\" alt=\"Ricardo Delfin\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Ricardo Delfin</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">06 Jul 2026, 16:22</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-58\">HMND-58</a></td><td class=\"confluenceTd\">Capability Factory</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:0a41c0f4-871a-4fcb-a0b5-a76cb1fbadf5/4ae5b15b-e260-478e-8943-382abe4f5f04/48\" alt=\"Artem Shutak\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Artem Shutak</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">26 Jun 2026, 15:20</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-63\">HMND-63</a></td><td class=\"confluenceTd\">Runtime Performance</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:15d56293-96ff-40d2-a06d-912f776e2042/a630846a-6205-4c5f-ad3e-4fa46817e742/48\" alt=\"Cody Griffin\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Cody Griffin</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">L1 Developer-ready</td><td class=\"confluenceTd\">26 Jun 2026, 14:12</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-68\">HMND-68</a></td><td class=\"confluenceTd\">Teleoperation throughput readiness for Pilot</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:9cc8637e-abee-4674-93b2-db86a8818e0f/85373a38-4848-41d2-a115-3ccdb68d95f2/48\" alt=\"Giulio Cerruti\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Giulio Cerruti</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">23 Jul 2026, 17:02</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-69\">HMND-69</a></td><td class=\"confluenceTd\">Single WBC interface for upper-body and base</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:9cc8637e-abee-4674-93b2-db86a8818e0f/85373a38-4848-41d2-a115-3ccdb68d95f2/48\" alt=\"Giulio Cerruti\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Giulio Cerruti</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">25 Jun 2026, 13:32</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-70\">HMND-70</a></td><td class=\"confluenceTd\">[Biped] Full-body Teleop Human-like Locomanip</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:9cc8637e-abee-4674-93b2-db86a8818e0f/85373a38-4848-41d2-a115-3ccdb68d95f2/48\" alt=\"Giulio Cerruti\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Giulio Cerruti</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">17 Jul 2026, 12:58</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-71\">HMND-71</a></td><td class=\"confluenceTd\">Whole-body manipulation (VLA)</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:dc96becb-2860-44b9-a22c-54a8419f4360/aa29fbcd-d488-4a0d-a94e-fcc84af94621/48\" alt=\"Diogo Almeida\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Diogo Almeida</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">25 Jun 2026, 10:32</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-72\">HMND-72</a></td><td class=\"confluenceTd\">VLA post-training recipe</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:dc96becb-2860-44b9-a22c-54a8419f4360/aa29fbcd-d488-4a0d-a94e-fcc84af94621/48\" alt=\"Diogo Almeida\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Diogo Almeida</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">25 Jun 2026, 12:23</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-73\">HMND-73</a></td><td class=\"confluenceTd\">Reinforcement learning for manipulation</td><td class=\"confluenceTd\"><img src=\"https://secure.gravatar.com/avatar/9cff63edec3eecd6c64557405e974b91?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FOS-0.png\" alt=\"Oleg Sinavski\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Oleg Sinavski</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">21 Jul 2026, 18:28</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-74\">HMND-74</a></td><td class=\"confluenceTd\">Foundational model</td><td class=\"confluenceTd\"><img src=\"https://secure.gravatar.com/avatar/9cff63edec3eecd6c64557405e974b91?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FOS-0.png\" alt=\"Oleg Sinavski\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Oleg Sinavski</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">21 Jul 2026, 18:28</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-75\">HMND-75</a></td><td class=\"confluenceTd\">3D navigation planning</td><td class=\"confluenceTd\"><img src=\"https://secure.gravatar.com/avatar/eefb653672f5b0d16f598325cab8a0c9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FKS-0.png\" alt=\"Karim Shaban\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Karim Shaban</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">10 Jul 2026, 14:57</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-76\">HMND-76</a></td><td class=\"confluenceTd\">Visual global localization</td><td class=\"confluenceTd\"><img src=\"https://secure.gravatar.com/avatar/eefb653672f5b0d16f598325cab8a0c9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FKS-0.png\" alt=\"Karim Shaban\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Karim Shaban</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">25 Jun 2026, 16:47</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-77\">HMND-77</a></td><td class=\"confluenceTd\">Visual-Lidar SLAM</td><td class=\"confluenceTd\"><img src=\"https://secure.gravatar.com/avatar/eefb653672f5b0d16f598325cab8a0c9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FKS-0.png\" alt=\"Karim Shaban\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Karim Shaban</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">25 Jun 2026, 17:16</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-78\">HMND-78</a></td><td class=\"confluenceTd\">Mindmap</td><td class=\"confluenceTd\"><img src=\"https://secure.gravatar.com/avatar/eefb653672f5b0d16f598325cab8a0c9?d=https%3A%2F%2Favatar-management--avatars.us-west-2.prod.public.atl-paas.net%2Finitials%2FKS-0.png\" alt=\"Karim Shaban\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Karim Shaban</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">25 Jun 2026, 17:05</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-80\">HMND-80</a></td><td class=\"confluenceTd\">Agentic Platform</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:14696d05-fc0a-461c-9ba5-8565a0981437/1862e4ad-72fb-4bf7-9b0a-7cb76ceb69d1/48\" alt=\"Mustafa Atakan\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Mustafa Atakan</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">06 Jul 2026, 13:54</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-81\">HMND-81</a></td><td class=\"confluenceTd\">Storage &amp; Compute Infra</td><td class=\"confluenceTd\"><img src=\"https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/712020:14696d05-fc0a-461c-9ba5-8565a0981437/1862e4ad-72fb-4bf7-9b0a-7cb76ceb69d1/48\" alt=\"Mustafa Atakan\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /> Mustafa Atakan</td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">06 Jul 2026, 14:21</td></tr><tr><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10310?size=medium\" alt=\"Capability\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\"><a href=\"https://sklvc.atlassian.net/browse/HMND-90\">HMND-90</a></td><td class=\"confluenceTd\">Fleet-Scale Simulation</td><td class=\"confluenceTd\"></td><td class=\"confluenceTd\"><img src=\"https://sklvc.atlassian.net/images/icons/priorities/medium_new.svg\" alt=\"Medium\" width=\"16\" height=\"16\" style=\"vertical-align:middle;object-fit:contain;\" /></td><td class=\"confluenceTd\">Awaiting implementation</td><td class=\"confluenceTd\">16 Jul 2026, 13:15</td></tr></tbody></table><p local-id=\"203382845abc\">Unfortunately Jira\u2019s goals are a different product and aren\u2019t yet visible via the API - though this may get addressed in a future release.   </p><h1 local-id=\"ed058e17033f\" id=\"CapabilityPlanning-Rituals&amp;Cadence(inprogress)\"><span class=\"inline-comment-marker\" data-ref=\"f00acdaf-e9dc-4bc5-8e00-e61ccfcac1e5\">Rituals &amp; Cadence (in progress)</span></h1><p local-id=\"6c6a8d909dfa\">Each layer has its own forum, with AlphaClaw-prepared briefings replacing verbal status updates.</p><p local-id=\"6f1a8a54fbcf\"><strong><span class=\"inline-comment-marker\" data-ref=\"d32a8f0b-9758-4792-9e02-453cd1f0bf15\">Quarterly capability planning</span></strong><span class=\"inline-comment-marker\" data-ref=\"d32a8f0b-9758-4792-9e02-453cd1f0bf15\"> brings product and engineering leads together to agree the 7\u201310 capabilities for the quarter, set their targets and trade-offs, and sign owner+sponsor commitments. This is where the contract gets signed.</span></p><p local-id=\"f2115c1703a6\"><strong>Monthly capability review</strong> is engineering leads only. Each owner reports maturity delta vs target, surfaces cross-team blockers, and confirms or corrects the AlphaClaw-generated briefing from 24 hours ago. No story-level discussion \u2014 that's not what this forum is for.</p><p local-id=\"42c6034283c1\"><strong>Monthly product backlog grooming</strong> brings product back in with engineering leads to debate new opportunities, surface engineering discoveries, and adjust the capability portfolio. This replaces the current weekly grooming meeting \u2014 the cadence shifts because the artifact (capability portfolio) only changes at monthly rhythm, and weekly grooming without commitment teeth is theater.</p><p local-id=\"c9fa6c1abe16\"><strong>Team planning</strong> runs at whatever cadence each team picks \u2014 weekly, biweekly, async, whatever fits. The capability is the cross-team commitment, but how each team gets to it is theirs.</p><p local-id=\"c936f5a73878\"><strong>Weekly opportunity refinement</strong> is product only \u2014 refining PB ideas, writing outcomes clearly, gathering customer and sales input. Engineering doesn't attend.</p><h1 local-id=\"e4ade0dfae4a\" id=\"CapabilityPlanning-Theplanningcycle\">The planning cycle</h1><p local-id=\"102256d48356\">Work flows in both directions across the layers.</p><p local-id=\"c11f63eaa300\"><strong>Forward.</strong> An opportunity <em>pulls</em> a capability into existence (or accelerates one that exists). The capability <em>commits</em> to a maturity by a date. That commitment opens delivery epics across the teams that need to contribute, which <em>deliver</em> stories. Each layer's commitment is the input to the layer below.  In addition to the maturity goal, additional goals may be associated with a capability.</p><p local-id=\"9acf52ae7de5\"><strong>Reverse.</strong> Delivery work sometimes <em>reveals</em> a capability nobody asked for \u2014 &quot;we accidentally got X working at a level that's actually demo-able.&quot; That surfaces upstream as a candidate opportunity. Half the real roadmap shifts in any technical org come from this reverse path; it isn't an edge case. Capabilities also propose new opportunities back to product when they unlock conversations that weren't possible before.</p><p local-id=\"d06752c83fbc\">When both directions work, the system breathes \u2014 product pulls, engineering pushes back with reality, and the negotiation surface is real. When only one direction works, it devolves into either a product wishlist that engineering ignores or an engineering roadmap that product doesn't recognize.</p><h1 local-id=\"5276b2f40694\" id=\"CapabilityPlanning-Appendix:Schemas\">Appendix: Schemas</h1><p local-id=\"a1e1b1b4f8d2\"><strong>Capability</strong> (long-lived parent, renamed Initiative, persists across quarters):</p><ul local-id=\"c9f842cca95e\"><li local-id=\"406162545ab8\"><p local-id=\"277f3940d5f3\"><strong>Status</strong> = current maturity (workflow): L1 Developer-ready / L2 Film-ready / L3 Demo-ready / L4 POC-ready / L5 Pilot-ready / Retired. Transitions allowed in both directions. No &quot;Done&quot; state.</p></li><li local-id=\"1107d237fc84\"><p local-id=\"e24e9aef2f75\"><strong>Target Maturity (this quarter)</strong> \u2014 single-select L1\u2013L5</p></li><li local-id=\"641291c9de76\"><p local-id=\"30a0763b15db\"><strong>Health</strong> \u2014 On Track / At-Risk / Slipped</p></li><li local-id=\"7b850cac5d6d\"><p local-id=\"d5dc5d302adf\"><strong>Engineering Owner</strong> \u2014 single user (builder)</p></li><li local-id=\"f6aba0313916\"><p local-id=\"110250306258\"><strong>Sponsor</strong> \u2014 single user (buyer: product, strategic, or research)</p></li><li local-id=\"dab8444c1360\"><p local-id=\"68035dd758c7\"><strong>Capability Type</strong> \u2014 Customer-pulled / Strategic-foundational / Operations</p></li><li local-id=\"62bc196a7f4a\"><p local-id=\"e90f19298fb2\"><strong>Linked Opportunities</strong> \u2014 relationship to PB Ideas (multi-select)</p></li><li local-id=\"6b16fba69a19\"><p local-id=\"3df2ce445f37\"><strong>Dependencies</strong> \u2014 linked Capabilities (issue links)</p></li><li local-id=\"5d3f76c7aa84\"><p local-id=\"e54466c35c1c\"><strong>For bets:</strong> Hypothesis, Kill Criterion, Spend (eng-weeks)</p></li></ul><p local-id=\"9155a977d72d\">The three things you read on any capability tile: <em>where it is</em> (Status), <em>where it's going this quarter</em> (Target), <em>how that's going</em> (Health).</p><p local-id=\"ae7a9d645c42\"><strong>Delivery Epic</strong> (typically team-bounded, multiple per Capability):</p><ul local-id=\"7ba78193c83b\"><li local-id=\"c6732a14ddff\"><p local-id=\"e1fd7b3215d9\">Parent: linked Capability</p></li><li local-id=\"e5aa5c554867\"><p local-id=\"79d21ac91aef\">Owning team: implicit in the project the epic lives in</p></li><li local-id=\"612403ff29f0\"><p local-id=\"060cf691be21\">Start/End dates: quarter window (or shorter if scope fits in a sprint)</p></li><li local-id=\"10ba200fa90e\"><p local-id=\"f887be19eff7\">Standard Done workflow at scope completion</p></li><li local-id=\"0e4ad1ba7427\"><p local-id=\"276a95ed0cfc\">The capability advances when <em>enough</em> of its underlying epics close to satisfy the maturity transition criteria</p></li></ul><p local-id=\"382539c45e4d\"><strong>Story:</strong></p><ul local-id=\"eed7111f29bf\"><li local-id=\"df89d38c0cd6\"><p local-id=\"55c4c65c24d8\">Standard story fields plus Parent (the Epic)</p></li><li local-id=\"604e4d887d6c\"><p local-id=\"ae4ba46649d9\">Trace upward: Story \u2192 Epic \u2192 Capability \u2192 Opportunity</p></li><li local-id=\"fceeba275959\"><p local-id=\"2ba80195fa52\">Lives in team boards (HEAP, HECP, HELM, HERE, HERM, HESA, HECO, DCP, etc.)</p></li><li local-id=\"88811807ca46\"><p local-id=\"1c802f8afff0\">Auto-created from PRs by AlphaClaw</p></li></ul><h1 local-id=\"c8778a0ba5cf\" id=\"CapabilityPlanning-Appendix:AIfront-endimplementation\">Appendix: AI front-end implementation</h1><div class=\"confluence-information-macro confluence-information-macro-information conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"info\" data-macro-id=\"76905632-4b63-48dc-9d93-54d852cdd9f9\" data-local-id=\"2c25ae48-84ca-4266-8a3f-5e6a14e3f098\"><span class=\"aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon\"> </span><div class=\"confluence-information-macro-body\"><p local-id=\"6996a9e91ac7\">The AI stuff here will likely need to wait until after we run this process manually a full times to get things started.</p></div></div><p local-id=\"cd00ed38cdfe\">Before the rituals: the operating model of the system itself. AI is the new front-end. Jira is the database; almost nobody opens it directly. AlphaClaw \u2014 the AI maintaining the system day-to-day \u2014 is what each role talks to.</p><p local-id=\"ae7dc43576d8\">Devs interact through Slack and git. Each capability has a Slack channel with a AlphaClaw-maintained pinned summary at the top \u2014 current maturity, target, recent signals, open decisions. Pull request descriptions and commit messages auto-link to capabilities by inference. Stories get auto-created from PRs without anyone filing a ticket. The PR is the unit of dev intent; everything else is bookkeeping the bot handles.</p><p local-id=\"80b36408133e\">Leads interact through weekly DM digests and pre-meeting briefings. Monday morning, each owner gets a summary of what changed last week on their capabilities, with proposed updates and the evidence. Reply in natural language to confirm or correct. Twenty-four hours before the monthly review AlphaClaw generates the meeting briefing; the meeting itself is spent on decisions, not verbal status.</p><p local-id=\"aec7cc33f186\">Product and business interact through conversational queries: &quot;what's ready for Schaeffler phase 3?&quot;, &quot;which capabilities are at risk for June?&quot;, &quot;who owns box handling?&quot; The answer comes from live state. Product stops trying to interpret engineering Jira because it doesn't need to.</p><p local-id=\"80acbcdd408e\">AlphaClaw operates with confidence scores and provenance on every change. High-confidence updates auto-apply; low-confidence queue for human review. Maturity transitions always require human confirmation, regardless of confidence. The audit trail is reversible.</p><p local-id=\"9798e43aa09a\">Trust is earned over time. First six-plus weeks AlphaClaw is read-only \u2014 proposes, never writes. Per-capability write access unlocks after proposal accuracy stays above ninety percent for several weeks. Maturity changes stay human-confirmed forever.</p><p local-id=\"71ff25f18483\">The strategic bet underneath: once the AI front-end is the only surface anyone touches, the backend is implementation detail. If Jira becomes painful we migrate; if the agent platform pivots we migrate. The durable thing is the taxonomy and the rituals, not the tooling.</p><p local-id=\"f29b415a440d\"><strong>Runtime stack:</strong></p><ul local-id=\"d467a31b065c\"><li local-id=\"4dd069f83cd0\"><p local-id=\"6fd36218ea6d\">Anthropic Managed Agents for runtime (~$200\u2013500/month operational)</p></li><li local-id=\"3e63e97ea391\"><p local-id=\"50842bcd2503\">MCPs: Atlassian (official Remote MCP), GitHub (official), Slack</p></li><li local-id=\"1e4bd230d0be\"><p local-id=\"0442a9e4cc9f\">Webhook routing from GitHub/Slack/Jira to the Managed Agent</p></li><li local-id=\"9abd36881f10\"><p local-id=\"bf334ab5e3a4\">System prompt + capability manifest = bulk of &quot;code&quot;</p></li><li local-id=\"56e4600379c7\"><p local-id=\"b749cfc421ec\">Operator UI = Slack (no dashboard to build)</p></li><li local-id=\"9ea18e88a8b4\"><p local-id=\"a1ac4b8fa88b\">Half FTE for one month to MVP; 0.1\u20130.2 FTE ongoing</p></li></ul><p local-id=\"958d2d7e02d1\"><strong>Git integration:</strong></p><ul local-id=\"22730fdd9ca4\"><li local-id=\"0cafe0a449dd\"><p local-id=\"fdb5d9c3d7b4\">PR opens \u2192 bot infers capability from branch name, PR title, files touched, description; auto-creates Story; comments with link</p></li><li local-id=\"c139c1fa001a\"><p local-id=\"96323ce224cd\">PR merges \u2192 bot updates story status, posts to capability channel; proposes maturity transition if the PR closed a maturity-blocking item</p></li><li local-id=\"3015ef0d392f\"><p local-id=\"76ee28f6b7f2\">Periodic sweep (hourly) synthesizes signal across Slack/git/Jira</p></li><li local-id=\"fd0860c3403c\"><p local-id=\"95b3cfccc62b\">The one hard gate: PR cannot merge to main without a capability link. Soft everywhere else.</p></li><li local-id=\"f71b9c3dae6e\"><p local-id=\"586b605d9317\">Cross-team dependency detection: PRs touching another team's component propose capability dependency links</p></li><li local-id=\"aaa773a90b88\"><p local-id=\"d76a1ffb8243\">Stale detection: no git activity for 3 weeks against an open epic gets flagged</p></li><li local-id=\"542c2a2fe637\"><p local-id=\"8ae566c3fe76\">Accidental discovery: signals that something works better than expected surface as candidate new capability or upstream opportunity</p></li></ul>"
        },
        {
          "id": "2002059272",
          "title": "Spec: Pose -> Approach -> Prompt",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/2002059272",
          "last_modified": "2026-05-21T18:19:27.736Z",
          "created_at": "2026-05-21T13:36:28.166Z",
          "body_html": "<h2 local-id=\"73e29589-2e32-41ac-946d-c97f331515a7\" id=\"Spec:Pose-&gt;Approach-&gt;Prompt-ProblemStatement\">Problem Statement</h2><p local-id=\"62a82b474731\">One of the more annoying aspects of our current autonomy solution is the \u201cpose \u2192 approach \u2192 prompt\u201d problem, where we need to carefully orchestrate the robot before we can hand over to the VLA to run policy.  There are a few reasons we do this.  First, we often need to adjust the pose of the robot (specifically the torso) to avoid collisions or to put the robot close to the object being manipulated.  Second, we sometimes need to start the policy from an in-distribution pose to get any success (though this has improved greatly with recent tote-handling policies).  But overall we still suffer some major issues here:</p><ol start=\"1\" local-id=\"5d49a94ca43e\"><li local-id=\"08da5d130d26\"><p local-id=\"126980a5dc20\">The sequence needs to be carefully preserved during workflow editing/deployment - which makes things a bit more brittle and fragile</p></li><li local-id=\"21a5ae8758a9\"><p local-id=\"eb68ff11020d\">The distinct \u201cphases\u201d, even when executed end-to-end without pauses, looks jerky and \u201crobotic\u201d since control itself is being handled by ~3ish different systems during this time</p></li><li local-id=\"43e71005eb82\"><p local-id=\"dd0e6b4fea28\">It mixes the what and how at the system-2 and system-1 boundaries.  System-2 needs to know too much about how to position the robot or the last ~10-20cm of navigation to perform the task.</p></li><li local-id=\"5f0355cf7137\"><p local-id=\"5c3178b8a10c\">Future vision-based navigation may not be precise enough to reliably do this anymore, and some points of interest may not be fixed so precisely in the real world anyway.  </p></li></ol><p local-id=\"7eff5f7158df\"><span class=\"inline-comment-marker\" data-ref=\"4a2fdae5-ad55-4b50-83d3-020f24bea643\">Broadly, it should be possible for the policy to do all of this smoothly.  System-2 just needs to get the robot \u201cclose enough\u201d, rather than trying to get centimeter precision within navigation and posing the robot blindly.  System-1 should be able to pose appropriately conditioned on the prompt and the scene, close the last few centimeters using base navigation while executing the manipulation policy as one fluid motion.  This will look better, perform better and ultimately be more robust to real-world dynamic environments and workflow edits.</span></p><h2 local-id=\"fd2eeeadf7e3\" id=\"Spec:Pose-&gt;Approach-&gt;Prompt-Solution\">Solution</h2><p local-id=\"bb93195f1332\">One possibility is to actually use system-2 to record the sequence and just train a policy to do the things.  Unfortunately this has some major downsides.  For one, there will be almost no data diversity in the pose and approach phases since they are so deterministically executed.  The second problem is that this preserves the stilted, disjoint motion - even if the sequence itself runs as a single longer-horizon behavior.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"794\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/2002059272/Untitled%20Diagram-1779372547043.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/2002059272/Untitled%20Diagram-1779372547043.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p local-id=\"e113e8d19aac\" /><p local-id=\"e111dd414c99\"><strong>WBC and Data Collection</strong></p><p local-id=\"835e12273e57\"><span class=\"inline-comment-marker\" data-ref=\"794522d8-252d-4c93-b168-48abed997858\">In order to get this fluid, overlapping motion, we need to actually get this addressed during data collection.  Base control has been a missing piece, and because policy can\u2019t do the \u201capproach\u201d, it forces us to break things up into these distinct pieces to be orchestrated.</span></p><p local-id=\"c5980e171d45\"><span class=\"inline-comment-marker\" data-ref=\"230354b2-1f29-4248-8bc9-26671692c056\">The most recent idea here is to effectively extend the WBC with a 3dof planar \u201cvirtual joint\u201d with some fake impedance between the base and the floor.  The \u201cstiffness\u201d of this would determine how far we allow the base to move - thus bounding the approach</span>.  Its almost like the robot is attached to some springy tether when we enable policy.</p><p local-id=\"8b06926845aa\">In this world, system-2 merely gets the robot close the desired point of interest.  Perhaps a meter from the table.  The WBC (and thus teleoperators or policy) can then smoothly extend the torso, move the base forward and position the arms over the tote for grasping before picking it up and returning back a location which is safely clear of the table.</p><p local-id=\"9ef92a8ba7a0\">This is superior to having the DCs doing manual base control, as it would be extremely difficult to get this natural overlapping motion with a wheelbase in this way.</p><p local-id=\"e9862023be48\"><strong>The \u201cPrecision Problem\u201d</strong></p><p local-id=\"05dd511a2e2f\">One of the areas highlighted above as a problem is that currently we rely on the base being positioned with centimeter level accuracy using lidar mapping and localization before we kick off the policy.  In the real world, we cannot expect our various \u201cpoints of interest\u201d to be located so accurately anyway - it will be impossible for us to actually hit pilot-level performance on something like de-stacking totes from a pallet (dropped off by a forklift or a human) unless the base can make some \u201clast-mile\u201d adjustments.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"733\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/2002059272/Untitled%20Diagram-1779384960197.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/2002059272/Untitled%20Diagram-1779384960197.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p local-id=\"cd2e1f6b029d\"><strong>Risks</strong></p><p local-id=\"fb932b6fac24\">Moving the base adds a bit of risk since now the robot can move about a bit.  Obviously a base lock (similar to the torso lock) can be implemented to avoid accidental base motion.  Its not clear how well the policy will learn to approach and pose to avoid obstacles though.  We have some evidence that the policy can learn to avoid obstacles, just by the nature of the task its performing in tight spaces like the shelves or trolley - so why wouldn\u2019t this extend to the base on approach?</p><p local-id=\"0a3c51f77371\">First - the policy is memory-less.  If we blindly move the base forward because of some policy error while we are already up against the table, the robot could push further into the table resulting in some pretty severe collisions.  Second - the safety system is active on the base which could result in strange behaviors if the safety is tripped while policy is executing.</p><p local-id=\"43d9ea28eeef\" />"
        },
        {
          "id": "1653407830",
          "title": "Robostore Demo Setup Instructions - DEPRECATED",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1653407830",
          "last_modified": "2026-05-19T06:54:11.516Z",
          "created_at": "2026-02-19T19:39:42.022Z",
          "body_html": "<span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"379\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1653407830/Untitled%20Diagram-1771530753132.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1653407830/Untitled%20Diagram-1771530753132.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p local-id=\"19782f47b5b8\">See <a href=\"/wiki/spaces/product/pages/1858142310/Robostore+Demo+Running+Guide\" data-linked-resource-id=\"1858142310\" data-linked-resource-version=\"45\" data-linked-resource-type=\"page\">Robostore + Ring picking demo running Guide</a>  for the latest demo guide</p><p local-id=\"0ef90466406f\" /><p local-id=\"10710a5d7051\"><strong>TL;DR State of the Demo (</strong>Alpha06 is the stationary robot, Alpha08 should be the moving robot. Place the moving robot at <code>init</code>, place the stationary robot at <code>table_1</code>.)<strong> </strong><code>/home/hmnd/robostore/hmnd</code>, <code>/mnt/ssd/robostore/hmnd</code>, branch: releases/2026.03.02)</p><ul local-id=\"c23461be8c6f\"><li local-id=\"38c40e7577f6\"><p local-id=\"4b8a03d5c224\">We can have a single robot pick and offer item 1 and item 3 in the above example.  </p></li><li local-id=\"b5ebdeb194e3\"><p local-id=\"83744c043446\">Item 2 fails because the policy will grab item 1 (maybe due to how popcorn was never trained with the left arm?)</p></li><li local-id=\"86c20597cbea\"><p local-id=\"32704ed466b5\">Item 4 fails because its on the shelf - which we cannot safely approach with the existing workflow (need more approach waypoints)</p></li><li local-id=\"861883210bc2\"><p local-id=\"46298ef8316c\">We cannot ask for items 1 and 3 at the same time - the robot will simply oscillate between Table 1 and Table 2 (simple workflow change needed).</p></li></ul><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"1000002973.jpg\" width=\"609\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1653407830/1000002973.jpg?version=1&amp;modificationDate=1771532697722&amp;cacheVersion=1&amp;api=v2&amp;width=609&amp;height=458\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1653407830/1000002973.jpg?version=1&amp;modificationDate=1771532697722&amp;cacheVersion=1&amp;api=v2\" data-height=\"3072\" data-width=\"4080\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1654685758\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"1000002973.jpg\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/jpeg\" data-linked-resource-container-id=\"1653407830\" data-linked-resource-container-version=\"28\" data-media-id=\"f4678eb3-cdae-4251-9468-1d9432cc27de\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1653407830/1000002973.jpg?version=1&amp;modificationDate=1771532697722&amp;cacheVersion=1&amp;api=v2&amp;width=1218&amp;height=916 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1653407830/1000002973.jpg?version=1&amp;modificationDate=1771532697722&amp;cacheVersion=1&amp;api=v2&amp;width=609&amp;height=458 1x\"></span><p local-id=\"a5ff09a39d75\" /><p local-id=\"92ea90e4d95c\"><strong>RTPC Bringup</strong><br/>For robots with F/T sensors (check status <a href=\"/wiki/spaces/ROBOT/pages/1644068885/Force+Integration+in+the+alpha+series+UMI+-+Project+Tracker\" data-linked-resource-id=\"1644068885\" data-linked-resource-version=\"10\" data-linked-resource-type=\"page\">here</a>):</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"52b836d7-ae4d-4319-9013-e3c35be5317e\" data-local-id=\"fe0c7d2449ee\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">cd hmnd_robot\npixi run reverb_robostore_rtpc_alpha_ft</pre>\n</div></div><p local-id=\"3815e6ddd33d\">For robots without F/T sensors:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"08ce47f0-d797-4380-a39e-27b2b9f7e1fb\" data-local-id=\"a5417f54-b92a-4854-b616-f92a5c4b59a3\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">cd hmnd_robot\npixi run reverb_robostore_rtpc_alpha</pre>\n</div></div><p local-id=\"73cd25d43f46\">As always, sometimes this just doesn\u2019t work.  No point in continuing if its not happy.  Make sure to localize w/ Foxglove.</p><p local-id=\"2cbefdda8a3e\"><strong>Initialization/Checkout</strong></p><p local-id=\"7f1414f36c1c\">Navigate robot to &quot;init&quot; point (\u26a0\ufe0f Use it only for mobile robot):</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"38f185f6-fcbc-4b9d-a8f9-57cbede7a89a\" data-local-id=\"e1d2e1fc-1e53-42c1-93cd-bc80c472ebab\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">pixi run ros2 action send_goal /navigate_to_tag hmnd_msgs/action/NavigateToTag &quot;{tag_name: init, controller_id: omni}&quot; --feedback</pre>\n</div></div><p local-id=\"84097dec70d3\">Set arms to initial pose (\u26a0\ufe0f without obstacle avoidance): </p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"0e764e42-5a61-40c1-a306-80141764e15a\" data-local-id=\"88c65ef020b3\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">pixi run ros2 action send_goal /whole_body_controller_interface/reset_robot_joint_config \\\nhmnd_msgs/action/ResetRobotJointConfig &quot;{config_name: home, group_name: arms, skip_planning: true}&quot; --feedback</pre>\n</div></div><p local-id=\"7558e9d4044f\">This will put the robot in the middle of the space on the right hand (from the audience) side.</p><p local-id=\"4fe6d2c7db65\"><strong>Orin Bringup</strong></p><p local-id=\"2d6c5a245a72\"><strong>Option 1: Run coordinator etc. on a robot (alpha11 for example).</strong></p><p local-id=\"c8d263cc1241\">For a \u201cStationary\u201d robot, <strong>it will move to the table_1 tag </strong>(the left side of the table if you\u2019re sitting at it).</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"c3ddc4b5-f99b-44f4-b749-e9876d0c062d\" data-local-id=\"20721dad7154\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">pixi run reverb_robostore_orin_alpha_local_stationary</pre>\n</div></div><p local-id=\"9ffbd3691d76\">I\u2019m not super thrilled about the robot moving when the stack is started - this is from the original mock setup and I\u2019ll probably tweak this to be a bit safer, especially as it takes a bit for the robot to actually boot and move.</p><p local-id=\"ce92f1a75c23\">The stationary robot will only attempt items 1 and 2.</p><p local-id=\"f4ec1c0236a3\">For a \u201cMobile\u201d robot, <strong>it will move to the table_2 tag</strong> (the right side of the table)</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"5e040027-e048-48f8-b29e-c1ae2692fb76\" data-local-id=\"4265b8a3dcd0\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">pixi run reverb_robostore_orin_alpha_local</pre>\n</div></div><p local-id=\"3b225aa3867f\">And it will reach all points.</p><p local-id=\"2908edf5b604\">For some reason (<span class=\"inline-comment-marker\" data-ref=\"9837c880-a436-4c65-8bd6-bcbaea2aba96\">maybe </span><span class=\"inline-comment-marker\" data-ref=\"9837c880-a436-4c65-8bd6-bcbaea2aba96\"><a class=\"confluence-userlink user-mention\" data-account-id=\"712020:abf9e8eb-c03c-4e45-9358-15be423b0ab1\" href=\"https://sklvc.atlassian.net/wiki/people/712020:abf9e8eb-c03c-4e45-9358-15be423b0ab1?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"1528004626\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Sam Pfeiffer</a></span><span class=\"inline-comment-marker\" data-ref=\"9837c880-a436-4c65-8bd6-bcbaea2aba96\"> knows?)</span> the launch file doesn\u2019t fully clean up the docker-compose stack for the fleet services, leaving an orphaned coordinator.  Its very important to clean this up when resetting the demo:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"0f05bf99-4cd2-4a0c-a4fc-d4c514a45618\" data-local-id=\"2050325aaee3\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">docker stop robostore-coordinator-1\ndocker ps # verify nothing is running</pre>\n</div></div><p local-id=\"5c9cb58fd04e\">The coordinator (switchboard) contains all the workflow state, and so if its not reset properly weird shit can happen.</p><p local-id=\"a1843db4cf13\"><strong>Option 2: Run Coordinator on a laptop</strong></p><ol start=\"1\" local-id=\"c248e5079bae\"><li local-id=\"a5a48e1ee249\"><p local-id=\"ef559385fd7c\">Connect a laptop to the same network as the robots.</p></li><li local-id=\"36184c3a6efb\"><p local-id=\"e16825fa957e\">run <code>ifconfig</code> on the laptop to find your IP address. It should be under something like <code>wlp...</code> under a field called <code>inet</code> call this \u201cLAPTOP_IP\u201d</p></li><li local-id=\"32e55654b071\"><p local-id=\"e9c72c6634bf\">On the orin of the robot make a change like so. Edit <code>hmnd_fleet/switchboard/examples/robostore/config/robostore_demo_config.yaml</code> so that the IP addresses in <code>laptop</code> correspond to the laptop\u2019s IP address. Afterwards, your git diff should look like this:</p><ol start=\"1\" local-id=\"7a632cf1b0a5\"><li local-id=\"1e879377afff\"><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"05eccae8-5e3e-4a6e-a166-1a1734a60110\" data-local-id=\"fc6de02d-29f1-4827-a11a-699799852647\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">hmnd@orinalpha8:/mnt/ssd/robostore/hmnd/hmnd_robot$ git diff\ndiff --git a/hmnd_fleet/switchboard/examples/robostore/config/robostore_demo_config.yaml b/hmnd_fleet/switchboard/examples/robostore/config/robostore_demo_config.yaml\nindex 12aa8a81f..c72bcb245 100644\n--- a/hmnd_fleet/switchboard/examples/robostore/config/robostore_demo_config.yaml\n+++ b/hmnd_fleet/switchboard/examples/robostore/config/robostore_demo_config.yaml\n@@ -118,9 +118,9 @@ fleet:\n       cims: &quot;http://localhost:20003&quot;\n     laptop:\n       # Remote peer fleet services (e.g., another robot running docker-compose)\n-      coordinator: &quot;http://10.44.68.111:20000&quot;\n-      robot_exec: &quot;http://10.44.68.111:20001/robot&quot;\n-      map_exec: &quot;http://10.44.68.111:20001/map&quot;\n+      coordinator: &quot;http://&lt;LAPTOP_IP&gt;:20000&quot;\n+      robot_exec: &quot;http://&lt;LAPTOP_IP&gt;:20001/robot&quot;\n+      map_exec: &quot;http://&lt;LAPTOP_IP&gt;:20001/map&quot;</pre>\n</div></div></li></ol></li><li local-id=\"428f47293ff4\"><p local-id=\"fc1fb15ec865\">On the laptop run <code>./hmnd_fleet/switchboard/examples/robostore/scripts/launch_kiosk.sh coordinator</code></p></li><li local-id=\"a313c906fff3\"><p local-id=\"a939300278d7\"><code>docker ps</code> to confirm at least <code>coordinator</code> and <code>map</code> are running.</p></li><li local-id=\"94d81191701e\"><p local-id=\"4f03fd6b7d45\">On the<strong> robot orin run:</strong></p><ol start=\"1\" local-id=\"6b82b59fcfb2\"><li local-id=\"51b152a02557\"><p local-id=\"a3a0d7baa53c\">For the stationary robot (alpha 06):</p><ol start=\"1\" local-id=\"b5faaff3188c\"><li local-id=\"e70f154046d3\"><p local-id=\"fe43c5bca105\"><code>pixi run reverb_robostore_orin_alpha_laptop_stationary</code> </p></li></ol></li><li local-id=\"934f66b85466\"><p local-id=\"4f23f0b0a347\">For the moving robot (alpha 08):</p><ol start=\"1\" local-id=\"56e09d60ab4d\"><li local-id=\"9d343aae67e4\"><p local-id=\"b620ba219346\"><code>pixi run reverb_robostore_orin_alpha_laptop</code></p></li></ol></li></ol></li></ol><p local-id=\"201fdeb1da0b\"><strong>Ordering via test script</strong></p><p local-id=\"f06e025b22f7\">Once the system is up, and the robot has moved to the the correct table location depending on the stationary/mobile role, you can send orders</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"a85b0d71-ef64-454b-994c-fcdd370769f6\" data-local-id=\"ff16b3eb24c5\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">hmnd@orinalpha11:/mnt/ssd/codg/hmnd/hmnd_fleet/switchboard/examples/robostore$ ./robostore_order.sh 1 2</pre>\n</div></div><p local-id=\"bba73718eee1\">The arguments are the item types.  You can pass 1 or 3.  (as mentioned before, one at a time for now).  The robot should get to the right basket (swapping with the shelf in the best of times) and then offer the item to the audience member. </p><p local-id=\"a373c1e3d2de\"><strong>WTF is Happening?</strong></p><p local-id=\"de1b0496f305\">When you place an Order, its injected as an IncomingOrder to the workflow.  The \u201cpos-agent\u201d takes care of breaking that IncomingOrder into PendingItems (one item per object being picked/offered), with some metadata like the specific item or left/right needed for policy execution.  This is sorta the \u201csystem 3\u201d agent, and where <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:4a88ef3e-c1fc-40ec-945f-1ad7efb95080\" href=\"https://sklvc.atlassian.net/wiki/people/712020:4a88ef3e-c1fc-40ec-945f-1ad7efb95080?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"143589446\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Yuriy Strezhik</a> 's kiosk app will eventually integrate.</p><p local-id=\"3fd43f1269a8\">The robots will take pending items and work to offer them to audience members according to the workflow.  Once all the items of an order are completed, the pos-agent will receive the event notifying that its completed (which we can key off to update a GUI or some voice line).</p><p local-id=\"222b71ef367f\">I\u2019m not entirely satisfied with how the data is split over tokens and facts - but for now I was just trying to get something mostly working.</p><p local-id=\"4a8b7a556f1f\">Item mappings are here: <a href=\"https://github.com/HumanoidTeam/hmnd/blob/codg/heco-2589-robostore-workflow/hmnd_fleet/switchboard/examples/robostore/config/robostore_demo_config.yaml#L13\" class=\"external-link\" rel=\"nofollow\">https://github.com/HumanoidTeam/hmnd/blob/codg/heco-2589-robostore-workflow/hmnd_fleet/switchboard/examples/robostore/config/robostore_demo_config.yaml#L13</a>  ( don\u2019t mind all the leftover Boschisms)</p><p local-id=\"c8970b64be81\"><strong>Frontend Kiosk Setup</strong></p><p local-id=\"233f6a5c207f\">On a different machine (not on a robot), you will need to launch the kiosk app. The kiosk app consists of two components:</p><ul local-id=\"bb011c127b05\"><li local-id=\"c1b82431b992\"><p local-id=\"39a2994251cd\">The <strong>Order Service </strong>handles receiving user orders and converting them into commands to the fleet service (the coordinator on the \u201cserver\u201d robot).</p></li><li local-id=\"c791d3f20b4f\"><p local-id=\"73a83a255bad\">The <strong>Frontend </strong>creates a react UI that can run in firefox in kiosk mode, and be displayed on the touch screen.</p></li></ul><p local-id=\"bf10b4f28c67\" /><p local-id=\"9221a310b46d\"><strong>Running with real Robots</strong></p><ol start=\"1\" local-id=\"be72310c3b38\"><li local-id=\"74edd473df1c\"><p local-id=\"7aba86bbe1e4\">Set up your environment. You will need to have <code>node</code> and <code>docker</code> installed locally.</p><ol start=\"1\" local-id=\"eb9afe23bb95\"><li local-id=\"d3f13e37de0d\"><p local-id=\"7ac992e385c3\"><a href=\"https://docs.docker.com/engine/install/\" local-id=\"0a69e934fbd9\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://docs.docker.com/engine/install/</a> </p></li></ol></li><li local-id=\"6e72b6c26014\"><p local-id=\"5c48d36afede\">Set up the ports and IP address of the \u201cserver\u201d robot. This will mean port forwarding from the server robot to your laptop.</p><ol start=\"1\" local-id=\"d33bdf30b5c9\"><li local-id=\"0495d2e4ee00\"><p local-id=\"42da6d7ced68\">For me, this is a command like so <code>ssh -A -p 2022 -L 20000:localhost:20000 -L 20001:localhost:20001 -L 20002:localhost:20002 -L 20004:localhost:20004 -o ExitOnForwardFailure=yes -N hmnd@&lt;your_robot_ip&gt;</code></p></li><li local-id=\"04d55f064c5b\"><p local-id=\"7506fd6ebc74\">NOTE: if the \u201cserver\u201d is just a laptop, and that laptop is the same IP as the frontend \u2013 you DO NOT need to port forward!</p></li></ol></li><li local-id=\"3e68f53c2de3\"><p local-id=\"5c98ad529f95\">First, try running the kiosk order service <em>without</em> voice.</p><ol start=\"1\" local-id=\"14697ca26297\"><li local-id=\"591a5f472444\"><p local-id=\"688934f48184\"><code>export VOICE_ENABLED=0; bash ./hmnd_fleet/switchboard/examples/robostore/scripts/launch_kiosk.sh service</code></p></li><li local-id=\"db532e531235\"><p local-id=\"c40184e0e819\">This should start running without errors.</p></li></ol></li><li local-id=\"13fb13ac0820\"><p local-id=\"54209f019dd6\">In another terminal, try running the kiosk frontend.</p><ol start=\"1\" local-id=\"6f085c99b008\"><li local-id=\"2bc2fd4d9b64\"><p local-id=\"fe3f196c0ba8\"><code>bash ./hmnd_fleet/switchboard/examples/robostore/scripts/launch_kiosk.sh frontend</code></p></li></ol></li><li local-id=\"7a896b4c700a\"><p local-id=\"2a829783f478\">Launch Firefox in kiosk mode pointed at the frontend</p><ol start=\"1\" local-id=\"109e1b9ccef6\"><li local-id=\"7810e8657970\"><p local-id=\"cffc146a54fc\"><code>firefox --private-window --kiosk &quot;http://localhost:5173/&quot;</code></p></li></ol></li><li local-id=\"8bcf11a7860b\"><p local-id=\"64d09842ff1f\">This should pull up the kiosk UI. Since voice is disabled, you will have to \u201corder by touch.\u201d </p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20260303-095844.png\" width=\"841\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1653407830/image-20260303-095844.png?version=1&amp;modificationDate=1772531926734&amp;cacheVersion=1&amp;api=v2&amp;width=841&amp;height=478\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1653407830/image-20260303-095844.png?version=1&amp;modificationDate=1772531926734&amp;cacheVersion=1&amp;api=v2\" data-height=\"478\" data-width=\"841\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1695285260\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20260303-095844.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1653407830\" data-linked-resource-container-version=\"28\" data-media-id=\"650d4a8b-5624-47ff-8097-1d9e6d14cc33\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1653407830/image-20260303-095844.png?version=1&amp;modificationDate=1772531926734&amp;cacheVersion=1&amp;api=v2&amp;width=841&amp;height=478 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1653407830/image-20260303-095844.png?version=1&amp;modificationDate=1772531926734&amp;cacheVersion=1&amp;api=v2&amp;width=841&amp;height=478 1x\"></span></li><li local-id=\"575b868d6408\"><p local-id=\"30ff8cf89e4b\">Now we can try to do the audio setup.</p><ol start=\"1\" local-id=\"172b926a4aad\"><li local-id=\"d0be1256bc5a\"><p local-id=\"de23f495a80c\">Start by plugging in the desired device(s).</p></li><li local-id=\"9ac4552a1b89\"><p local-id=\"6ee5d0f5229c\">Open up audio settings, and see if you see a new microphone device. You can verify this by unplugging and replugging the device.</p></li><li local-id=\"33de7da0105c\"><p local-id=\"b49e433beec4\">Now you will need to set up the <code>OPENAI_API_KEY</code>. <code>export OPENAI_API_KEY=&lt;your_key&gt;</code> in a terminal. Ask <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:7655017b-55c7-4902-aafd-678b431ce466\" href=\"https://sklvc.atlassian.net/wiki/people/712020:7655017b-55c7-4902-aafd-678b431ce466?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"1472135186\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Matt Klingensmith</a> or <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a> for a valid key in a private message.</p></li><li local-id=\"ae40c00b6a77\"><p local-id=\"68ec47f979d7\">This key can persist if you put it in ~/.bashrc</p></li><li local-id=\"c9b3a4868782\"><p local-id=\"9ac6ba15714e\">Now, we will try to run the <em>voice agent</em> on its own without the robostore component. This is just to verify that the audio and OpenAI connection is working.</p></li><li local-id=\"bf902a1808be\"><p local-id=\"970cc5a8b28c\"><code>export PA_ALSA_PLUGHW=1;PYTHONPATH=/home/mklingen/hmnd/hmnd_robot/apps pixi run python -m voice_agents.openai_voice_agent</code></p></li><li local-id=\"889ceae636dc\"><p local-id=\"5873b1e7f24c\">This will pull up a list of audio devices. Select the device that you found in step (b) for the input device. Note the ID of the device (on the right side) not the index.</p></li><li local-id=\"41b5d34c25f6\"><p local-id=\"60394e183044\">If this is successful you should be able to start talking to the agent.</p></li><li local-id=\"425e66618f30\"><p local-id=\"4127c47d80cf\">Troubleshooting: linux is terrible at audio. Try unplugging and replugging the device several times. Make sure you don\u2019t have multiple apps trying to record audio simultaneously.</p></li><li local-id=\"a0bf254a1395\"><p local-id=\"03ccfb68d09c\">Noting the device indices that you found in step (g), rerun the order service with:</p><ol start=\"1\" local-id=\"73da72c74bfe\"><li local-id=\"4f0ec51d4db0\"><p local-id=\"3a2deb49e7e7\"><code>export PA_ALSA_PLUGHW=1; export ROBOSTORE_VOICE_INPUT_DEVICE_INDEX=6; export ROBOSTORE_VOICE_OUTPUT_DEVICE_INDEX=7; export VOICE_ENABLED=1; bash ./hmnd_fleet/switchboard/examples/robostore/scripts/launch_kiosk.sh service</code></p></li><li local-id=\"f1f77f4e9bcf\"><p local-id=\"281cda9a3c60\">Note that in my case, the input index was 6, and the output index was 7. Although they\u2019re called index, we\u2019re referring to the device ID that you found in step (g).</p></li></ol></li></ol></li><li local-id=\"8e24fdcfd837\"><p local-id=\"c7c2c15b05cc\">Verify that audio works. You should be able to just start talking into the microphone to order items.</p></li></ol><p local-id=\"f1f5ce23e986\" /><p local-id=\"af63a0f1df55\"><strong>Once Everything is Working: The Single Command</strong></p><p local-id=\"7f886a5460af\">Once you\u2019ve verified everything is working, you can run the coordinator, order service, and kiosk frontend all with one command. Make sure that ROBOSTORE_VOICE_INPUT and output are correct first!:<br/></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"8630e3e5-1fb3-4063-971d-dca5cd869218\" data-local-id=\"55a7743b43d7\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">export PA_ALSA_PLUGHW=1; export ROBOSTORE_VOICE_INPUT_DEVICE_INDEX=&lt;input&gt;; export ROBOSTORE_VOICE_OUTPUT_DEVICE_INDEX=&lt;output&gt;; export VOICE_ENABLED=1; bash ./hmnd_fleet/switchboard/examples/robostore/scripts/launch_kiosk.sh all</pre>\n</div></div><p local-id=\"efd0fcb7c851\" /><p local-id=\"3bbe242410c2\" /><p local-id=\"0124cebcf9cd\" /><p local-id=\"1ec76bff5b69\"><strong>Running with Mock Mode</strong></p><p local-id=\"3022bae958fd\">You will probably find it useful to debug the front end separately from the robots. After installing the dependencies (Docker),  run a mock robot setup using:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"db861c87-274f-40ae-80ef-aae47132c2df\" data-local-id=\"3d88d9e4790d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">KEEP_RUNNING=1 \\\nORDER_COUNT=0 \\\nWAIT_COMPLETED_ORDERS=999 \\\nPOS_MULTIMODAL_URL=http://localhost:20006 \\\nCOORDINATOR_URL=&quot;http://localhost:20000/workflows/robostore&quot; \\\nMAP_EXEC_URL=&quot;http://localhost:20001/workflows/robostore/map&quot; \\\nROBOT_EXEC_URL=&quot;http://localhost:20001/workflows/robostore/robot&quot; \\\nWAREHOUSE_URL=&quot;http://localhost:20002/workflows/robostore&quot; \\\nMOCK_WMS_URL=&quot;http://localhost:20004&quot; \\\nbash hmnd_robot/apps/reverb/scripts/run_reverb_ros_mock_dual_robostore_multimodal.sh\n</pre>\n</div></div><p local-id=\"605fbe5c5203\">This should boot up several docker instances that run simulated (mock) robots and services. Then all the other front end steps should work as expected.</p><p local-id=\"d55400ea867e\"><strong>Debug Monitoring</strong></p><p local-id=\"6380d13e291e\">The debug monitor developed for Bosch can also be used in Robostore. To use it, simply navigate to the IP of the robot at port 5555</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20260305-150855.png\" width=\"1733\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1653407830/image-20260305-150855.png?version=1&amp;modificationDate=1772723337344&amp;cacheVersion=1&amp;api=v2&amp;width=1733&amp;height=623\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1653407830/image-20260305-150855.png?version=1&amp;modificationDate=1772723337344&amp;cacheVersion=1&amp;api=v2\" data-height=\"855\" data-width=\"2375\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1708294152\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20260305-150855.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1653407830\" data-linked-resource-container-version=\"28\" data-media-id=\"bab13f1d-bc3f-45e8-b0e8-b7c0a6f3a1fd\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1653407830/image-20260305-150855.png?version=1&amp;modificationDate=1772723337344&amp;cacheVersion=1&amp;api=v2&amp;width=2375&amp;height=855 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1653407830/image-20260305-150855.png?version=1&amp;modificationDate=1772723337344&amp;cacheVersion=1&amp;api=v2&amp;width=1733&amp;height=623 1x\"></span><p local-id=\"7609304a8a9f\">The <em>Pause Acquisition</em> button will prevent that particular robot from ever taking on orders. The <em>Stop Robot</em> button completely removes the robot from the workflow entirely and prevents it from moving (both policies and navigation). You can add the robot back to the workflow by pressed <em>Start Robot</em>.</p><h2 local-id=\"f17bcba7f889\" id=\"RobostoreDemoSetupInstructions-DEPRECATED-GettingLogsfromtheInferenceServer\">Getting Logs from the Inference Server</h2><ol start=\"1\" local-id=\"10c76b853504\"><li local-id=\"58b5514a58b9\"><p local-id=\"7207595ad9dc\">Log in to either spark or thor.</p></li><li local-id=\"04d76419224a\"><p local-id=\"4bde686f94a9\"><code>docker logs hmnd-inference -f</code></p></li><li local-id=\"27bc2adeb499\"><p local-id=\"de4316671d03\">You will now see the logs from the inference server, which should look something like this</p></li></ol><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"e56217bd-02dc-4f79-a8f9-3facc6e3c43d\" data-local-id=\"2a734ad1a89f\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[03/05/26 15:30:50] INFO     hmnd_training.serve.server: === gRPC   server.py:76\n                             Request [Client                                    \n                             ipv4:10.44.52.106:54282] ===                       \n                             E2E infer_ms: 220.06                               \n                             policy_inference_ms: 211.83 +                      \n                             grpc_serialize_ms: 1.19                            \n                                                                                \n[03/05/26 15:30:50] INFO     hmnd_training.serve.server: === gRPC   server.py:76\n                             Request [Client                                    \n                             ipv4:10.44.52.106:54282] ===                       \n                             E2E infer_ms: 234.72                               \n                             policy_inference_ms: 220.99 +                      \n                             grpc_serialize_ms: 1.18                            \n                                                                                \n[03/05/26 15:30:51] INFO     hmnd_training.serve.server: === gRPC   server.py:76\n                             Request [Client                                    \n                             ipv4:10.44.52.106:54282] ===                       \n                             E2E infer_ms: 235.79                               \n                             policy_inference_ms: 222.13 +                      \n                             grpc_serialize_ms: 1.17                            \n                                                                                \n[03/05/26 15:30:51] INFO     hmnd_training.serve.server: === gRPC   server.py:76\n                             Request [Client                                    \n                             ipv4:10.44.52.106:54282] ===                       \n                             E2E infer_ms: 231.76                               \n                             policy_inference_ms: 217.85 +                      \n                             grpc_serialize_ms: 1.16                            \n                                                                                \n[03/05/26 15:30:51] INFO     hmnd_training.serve.server: === gRPC   server.py:76\n                             Request [Client                                    \n                             ipv4:10.44.52.106:54282] ===                       \n                             E2E infer_ms: 226.94                               \n                             policy_inference_ms: 218.03 +                      \n                             grpc_serialize_ms: 1.20   </pre>\n</div></div><h2 local-id=\"b08533a4cef0\" id=\"RobostoreDemoSetupInstructions-DEPRECATED-OtherErrata\">Other Errata</h2><ol start=\"1\" local-id=\"b998d1fd09b9\"><li local-id=\"729a361867d6\"><p local-id=\"0beb44e07ca9\">It doesn\u2019t seem like the robot can offer items from sku-2 (popcorn in this case), even with the specific prompt (<code>Pick the popcorn from the left basket and give it to a person</code>) - I\u2019m guessing this is due to the combinatorics and we could maybe shuffle the items around to make this work\u2026</p></li><li local-id=\"ed147fde0258\"><p local-id=\"53ef8856afb2\">Shelves are sketchy AF.  Right now there is only a single shelf_approach way point, which is near the init position (but facing the shelves).  Unfortunately this isn\u2019t enough - the robot will simply run the basket its carrying into the basket on the shelf, which can result in tipping the shelves over.  These shelves are VERY easy to tip.</p></li><li local-id=\"184c218cefc0\"><p local-id=\"577d178438b4\">When grasping items from the side of the basket, the policy will grab the basket itself and try to hand it over, with predictable results.  Occasionally the gripper can get jammed up on itself resulting in an \u201cempty offer\u201d.  I noticed this most on baskets that are nearly empty. </p></li><li local-id=\"4a3c50f588d4\"><p local-id=\"818f02fe9474\">robot IDs aren\u2019t being set properly (r1 is not right - should be 11)</p></li></ol><p local-id=\"381750c21ebd\" /><h1 local-id=\"512d2f0600ac\" id=\"RobostoreDemoSetupInstructions-DEPRECATED-WhenThingsgoWrong\">When Things go Wrong</h1><ol start=\"1\" local-id=\"562bc895b6c1\"><li local-id=\"9ccfa19d4315\"><p local-id=\"4f390569c9f4\">You will often see the robots go into teleop mode the HRI system on the face will turn blue.</p></li><li local-id=\"abd4beaf2292\"><p local-id=\"b92d55a9f964\">When this happens the only thing possible really is to go into sockpuppet and disable teleop, then <em>kill the code that\u2019s running on the orin</em></p></li><li local-id=\"1d2b8ae6b6e5\"><p local-id=\"8aa4172220cf\">Then move all the robots back to their initial states, and move all the baskets back.</p></li><li local-id=\"4ce40e449bb2\"><p local-id=\"8c652ac6fd1a\">Then reset the <em>coordinator</em>.</p></li><li local-id=\"73691adf8969\"><p local-id=\"24f8182c091e\">Then restart the front end.</p></li></ol>"
        },
        {
          "id": "1816592386",
          "title": "Getting Started with AI",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1816592386",
          "last_modified": "2026-05-13T20:26:37.780Z",
          "created_at": "2026-03-31T08:34:34.380Z",
          "body_html": "<div class=\"panel conf-macro output-block\" style=\"background-color: #EAE6FF;border-color: #998DD9;border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"panel\" data-macro-id=\"\"><div class=\"panelContent\" style=\"background-color: #EAE6FF;\">\n<p local-id=\"57b7e19e96b4\">This is a living document - I\u2019m sure there will be all sorts of snags onboarding here (especially with tools/MCPs/accounts) - let\u2019s try and pile all the context/comments/issues into this doc so we can get things cleared up.</p>\n</div></div><h1 local-id=\"06134fe4590e\" id=\"GettingStartedwithAI-GettingStartedwithClaudeAITools\">Getting Started with Claude AI Tools</h1><p local-id=\"7e1b006829a5\">Claude is Humanoid's AI assistant, powered by Anthropic. This guide walks you through logging in, the core tools available, and how to connect them to your everyday workflows. </p><div class=\"confluence-information-macro confluence-information-macro-note conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"note\" data-macro-id=\"e3b84af8-bb19-46b9-8fed-51b4231d6cf9\" data-local-id=\"e4a78d0c0e29\"><span class=\"aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon\"> </span><div class=\"confluence-information-macro-body\"><p local-id=\"000fc306c022\"><strong>Important: Use your </strong><code>thehumanoid.ai</code> email</p><p local-id=\"cae82bbf71fe\">Humanoid's Claude access is provisioned through Google Workspace at <code>thehumanoid.ai</code>. Many team members are signed into their browsers with a personal or legacy <code>skl.vc</code> Google account \u2014 <strong>you must manually enter your </strong><code>@thehumanoid.ai</code> email when signing in, rather than using the &quot;Continue with Google&quot; auto-fill. If you sign in with the wrong account, you won't have access to the team workspace, integrations, or shared memory.</p></div></div><h2 local-id=\"60e9ad3b575c\" id=\"GettingStartedwithAI-SigningIn\">Signing In</h2><ol start=\"1\" local-id=\"75ce0173e6b8\"><li local-id=\"168e37d9fd14\"><p local-id=\"a389b43fe257\">Browse to <a href=\"https://claude.ai/login\" class=\"external-link\" rel=\"nofollow\">https://claude.ai/login</a> and use your @thehumanoid.ai login (or submit an IT ticket for an account)</p></li><li local-id=\"07bb0aa658d9\"><p local-id=\"4666966ea711\">Follow the link on the email issued to your account.</p></li><li local-id=\"2b6f8ce62e43\"><p local-id=\"f0fb0f2a6ef8\"><span class=\"inline-comment-marker\" data-ref=\"2f17927c-d4c3-4cd3-b974-312876f064e3\">Click </span><strong><span class=\"inline-comment-marker\" data-ref=\"2f17927c-d4c3-4cd3-b974-312876f064e3\">Sign in with Google</span></strong></p></li><li local-id=\"d800caf1b52b\"><p local-id=\"689e82de586f\"><span class=\"inline-comment-marker\" data-ref=\"2f17927c-d4c3-4cd3-b974-312876f064e3\">When prompted, </span><strong><span class=\"inline-comment-marker\" data-ref=\"2f17927c-d4c3-4cd3-b974-312876f064e3\">manually type</span></strong><span class=\"inline-comment-marker\" data-ref=\"2f17927c-d4c3-4cd3-b974-312876f064e3\"> </span><code><span class=\"inline-comment-marker\" data-ref=\"2f17927c-d4c3-4cd3-b974-312876f064e3\">alias@thehumanoid.ai</span></code><span class=\"inline-comment-marker\" data-ref=\"2f17927c-d4c3-4cd3-b974-312876f064e3\"> \u2014 do not use the pre-filled account if it shows a different email</span></p></li><li local-id=\"f6b754a1fda8\"><p local-id=\"46658868aab0\">Complete Google authentication</p></li><li local-id=\"ce2470769da8\"><p local-id=\"1b1140a80f50\">You should land in the Humanoid team workspace</p></li></ol><p local-id=\"58062d47f95b\">If you see a personal or free-tier Claude workspace instead of the team one, you've signed in with the wrong account \u2014 sign out and repeat step 4.</p><h2 local-id=\"4492781a8fe7\" id=\"GettingStartedwithAI-UsingClaude\u2019sWebApp\">Using Claude\u2019s Web App</h2><p local-id=\"ead4223898dc\">Once you're in, here's what you need to know:</p><ul local-id=\"e8749a1a3acb\"><li local-id=\"9d403c7d50a9\"><p local-id=\"4bd9a96b3517\"><strong>Chat</strong>: The main interface for asking questions, drafting content, reasoning through problems, and more. Think of it as a highly capable thinking partner.</p></li><li local-id=\"4ddb1b0150a1\"><p local-id=\"7e21042d3f40\"><strong>Projects</strong>: Group related conversations and give Claude persistent context (e.g. a project brief, codebase context, or team norms). Great for ongoing workstreams.</p></li><li local-id=\"af994936cb1f\"><p local-id=\"becc976a2696\"><strong>Memory</strong>: Claude can remember things across conversations. You can review and edit your memories in Settings \u2192 Memory.</p></li><li local-id=\"31af3be0d77c\"><p local-id=\"42e78e52f57e\"><strong>Artifacts</strong>: When Claude generates code, documents, or structured outputs, they appear as shareable Artifacts in a side panel \u2014 you can copy, download, or iterate on them.</p></li><li local-id=\"39c6b2c73bd5\"><p local-id=\"bf2755212111\"><strong>Integrations / Connectors</strong>: Claude can connect to your tools (Slack, GitHub, Jira, Google Drive, etc.) and take actions on your behalf.</p></li></ul><h2 local-id=\"03ea37f91632\" id=\"GettingStartedwithAI-InstallingClaudeDesktopApps\">Installing Claude Desktop Apps</h2><h3 local-id=\"62e20b5ed96e\" id=\"GettingStartedwithAI-ClaudeCowork(foreveryone)\">Claude Cowork (for everyone)</h3><p local-id=\"8a8a82844001\">Claude Cowork is a desktop app for non-developers that lets you automate file management, document workflows, and everyday tasks \u2014 no coding required.</p><ol start=\"1\" local-id=\"527ecee8464d\"><li local-id=\"91b4e209ed43\"><p local-id=\"df1838a8972a\">Download from <a href=\"https://claude.ai/download\" class=\"external-link\" rel=\"nofollow\">claude.ai/download</a> \u2192 select <strong>Claude Cowork</strong></p></li><li local-id=\"7d77f73fd204\"><p local-id=\"dfaf36a575d0\">Install and sign in with your <code>@thehumanoid.ai</code> Google account (same caveat as above \u2014 type it manually)</p></li><li local-id=\"7272fcfc8e3c\"><p local-id=\"739808d883b0\">From Cowork, you can also launch <strong>Claude in Chrome</strong>, <strong><span class=\"inline-comment-marker\" data-ref=\"8a06386d-3e24-4903-ab4a-a81788d1ceed\">Claude in Excel</span></strong><span class=\"inline-comment-marker\" data-ref=\"8a06386d-3e24-4903-ab4a-a81788d1ceed\">, and </span><strong><span class=\"inline-comment-marker\" data-ref=\"8a06386d-3e24-4903-ab4a-a81788d1ceed\">Claude in PowerPoint</span></strong><span class=\"inline-comment-marker\" data-ref=\"8a06386d-3e24-4903-ab4a-a81788d1ceed\"> \u2014 browser and Office integrations for in-context AI assistance</span></p></li></ol><h3 local-id=\"fb3c9d6c4ea8\" id=\"GettingStartedwithAI-ClaudeCode(fordevelopers)\">Claude Code (for developers)</h3><p local-id=\"2bba96558fc5\">Claude Code is a command-line tool and desktop app for agentic coding \u2014 it can read your repo, write code, run tests, and make commits.</p><ol start=\"1\" local-id=\"d47511908e37\"><li local-id=\"60642867c574\"><p local-id=\"8f2cddf292bf\">Install via terminal:</p></li></ol><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"60c0a6e4-e566-4c39-af57-98feb551c20a\" data-local-id=\"31e1015e04fd\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">npm install -g @anthropic-ai/claude-code</pre>\n</div></div><ol start=\"2\" local-id=\"bd5cce43db1c\"><li local-id=\"16b86e01b90f\"><p local-id=\"07b10c36b758\">Or download the desktop app from <a href=\"https://claude.ai/download\" class=\"external-link\" rel=\"nofollow\">claude.ai/download</a> \u2192 <strong>Claude Code</strong></p></li><li local-id=\"0666b854ab3a\"><p local-id=\"97d47204c18c\">Authenticate with your <code>@thehumanoid.ai</code> account when prompted</p></li><li local-id=\"9d39558ca61c\"><p local-id=\"6b302cce9b6c\">Open a project directory and run <code>claude</code> to start a session</p></li></ol><h2 local-id=\"4bb44166b3ee\" id=\"GettingStartedwithAI-ConnectingYourTools\"><span class=\"inline-comment-marker\" data-ref=\"4fdc6fa4-c2c6-47d2-b09b-53b2bee905e8\">Connecting Your Tools</span></h2><p local-id=\"aa89bfab1c0b\">Navigate to <strong>Settings \u2192 Integrations</strong> in Claude to connect the following. Each integration allows Claude to read context from and take actions in those tools.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20260331-085417.png\" width=\"1282\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1816592386/image-20260331-085417.png?version=1&amp;modificationDate=1774947258519&amp;cacheVersion=1&amp;api=v2&amp;width=1282&amp;height=710\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1816592386/image-20260331-085417.png?version=1&amp;modificationDate=1774947258519&amp;cacheVersion=1&amp;api=v2\" data-height=\"711\" data-width=\"1282\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1816068106\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20260331-085417.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1816592386\" data-linked-resource-container-version=\"7\" data-media-id=\"065b859e-1730-486a-83fe-7a85c1525ca9\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1816592386/image-20260331-085417.png?version=1&amp;modificationDate=1774947258519&amp;cacheVersion=1&amp;api=v2&amp;width=2308&amp;height=1280 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1816592386/image-20260331-085417.png?version=1&amp;modificationDate=1774947258519&amp;cacheVersion=1&amp;api=v2&amp;width=1282&amp;height=710 1x\"></span><p local-id=\"af397aa291cb\" /><h3 local-id=\"a0387c6714ec\" id=\"GettingStartedwithAI-GitHub\">GitHub</h3><ul local-id=\"6e448a64bcc0\"><li local-id=\"980fcf046f34\"><p local-id=\"2c5684a9622b\">Connect under <strong>Settings \u2192 Integrations \u2192 GitHub</strong></p></li><li local-id=\"ab3b1fab8bed\"><p local-id=\"0e17bd247795\">Authorize with your GitHub account linked to the Humanoid org</p></li><li local-id=\"428e2c775484\"><p local-id=\"e3fa367e545d\">Once connected, Claude Code can read repos, suggest PRs, and assist with code reviews directly</p></li></ul><h3 local-id=\"953342151d2b\" id=\"GettingStartedwithAI-Slack\">Slack</h3><ul local-id=\"f0df9e9cfeec\"><li local-id=\"1e19a0013344\"><p local-id=\"8930ca5ef229\">Connect under <strong>Settings \u2192 Integrations \u2192 Slack</strong></p></li><li local-id=\"3379747a24cc\"><p local-id=\"8ca7a0d9c818\">Authorize for the <code>thehumanoid</code> Slack workspace</p></li><li local-id=\"f1b26df6b6c0\"><p local-id=\"fb0bac440c8a\">Claude can search message history, draft messages, and summarize threads</p></li></ul><h3 local-id=\"f5747a9622ea\" id=\"GettingStartedwithAI-Atlassian(Jira+Confluence)\">Atlassian (Jira + Confluence)</h3><ul local-id=\"9b702c06e008\"><li local-id=\"12c86e406946\"><p local-id=\"ea5e490d7bb8\">Connect under <strong>Settings \u2192 Integrations \u2192 Atlassian</strong></p></li><li local-id=\"a2405c3afddd\"><p local-id=\"41dfd6e66a72\">Authorize with your <code>@thehumanoid.ai</code> Google SSO on Atlassian \u2014 this should match your <code>sklvc.atlassian.net</code> login</p></li><li local-id=\"6a4d1dfe6804\"><p local-id=\"c3b6270e183e\">Claude can search pages, create Jira issues, update tickets, and draft documentation</p></li></ul><h3 local-id=\"9d05951000e6\" id=\"GettingStartedwithAI-GoogleWorkspace\">Google Workspace</h3><ul local-id=\"442cc3d3e54d\"><li local-id=\"061c79079051\"><p local-id=\"c59936277934\">Connect under <strong>Settings \u2192 Integrations \u2192 Google Drive / Gmail / Calendar</strong></p></li><li local-id=\"badb076eeec6\"><p local-id=\"bbc754f34a7c\">Use your <code>@thehumanoid.ai</code> account \u2014 again, type it manually rather than relying on auto-fill</p></li><li local-id=\"9cdbd228d8e9\"><p local-id=\"cf68686b9a55\">Claude can search Drive, summarize docs, draft emails, and check your calendar</p></li></ul><h3 local-id=\"5526422f8767\" id=\"GettingStartedwithAI-Ashby(TODO-noexistingremoteMCPbutwecanhostsomethingpossibly)\">Ashby (TODO - no existing remote MCP but we can host something possibly)</h3><ul local-id=\"4bdf3182-3810-419d-a2ea-01fc4c8e4be7\"><li local-id=\"b3a419b9-9728-45c8-9cdb-f2d2a06432c4\"><p local-id=\"72e871fd1052\"><span class=\"inline-comment-marker\" data-ref=\"152cf730-3b55-4e72-bc3c-5cafddf6c574\">Connect applicants, etc</span></p></li></ul><h2 local-id=\"68af94e89321\" id=\"GettingStartedwithAI-GettingtheMostOutofClaude\">Getting the Most Out of Claude</h2><ul local-id=\"92781d5b8869\"><li local-id=\"984b42e3e8fd\"><p local-id=\"6b85291ed5aa\"><strong>Be specific</strong>: The more context you give Claude, the better the output. Include the &quot;why&quot;, not just the &quot;what&quot;.</p></li><li local-id=\"b3499ec6b5ca\"><p local-id=\"ce359a9d822e\"><strong>Use Projects for ongoing work</strong>: Set a project up with background context once, and every conversation in that project benefits from it automatically.</p></li><li local-id=\"44d85c6c84bb\"><p local-id=\"70b684b17b50\"><strong>Iterate, don't redo</strong>: If Claude's first response isn't quite right, ask it to refine \u2014 it's faster than starting over.</p></li><li local-id=\"4d2b0407f76a\"><p local-id=\"1a7e87e977ae\"><strong>Claude can use your tools</strong>: With integrations connected, you can ask Claude to &quot;find the Jira ticket about X&quot;, &quot;summarize last week's #engineering Slack messages&quot;, or &quot;draft a doc based on this meeting note&quot; and it will actually do it.</p></li><li local-id=\"39d22f623840\"><p local-id=\"3558a163694e\"><strong>Check Artifacts</strong>: Any document, table, or code Claude generates can be saved as an Artifact \u2014 look for the side panel.</p></li></ul><h2 local-id=\"9c859fea4898\" id=\"GettingStartedwithAI-Cautions&amp;GoodPractices\">Cautions &amp; Good Practices</h2><blockquote local-id=\"53068e1ae83f\"><p local-id=\"4b5726d6c148\"><strong>Don't paste sensitive data carelessly.</strong> While Claude conversations in the team workspace are covered by Anthropic's enterprise data handling agreements, treat anything truly confidential (<span class=\"inline-comment-marker\" data-ref=\"4ba00b3e-b536-4bd7-bb49-2ae4f2300b42\">customer PII</span>, unreleased financials, private keys) with care. When in doubt, describe the situation rather than pasting raw data.</p></blockquote><blockquote local-id=\"a2b77b342ae0\"><p local-id=\"50e61a5d3b48\"><strong>Claude can be wrong.</strong> Claude is a powerful reasoning tool but it hallucinates. Always verify important facts, code, or decisions \u2014 especially in production contexts.</p></blockquote><blockquote local-id=\"68757f46e56b\"><p local-id=\"f6cd29e24793\"><strong>Agentic actions are real.</strong> When Claude is connected to Slack, Jira, GitHub, etc., it can take real actions. Review before confirming any write operations (creating issues, sending messages, committing code).</p></blockquote><blockquote local-id=\"640149a9bd5e\"><p local-id=\"3ca19791954b\"><strong>Account confusion is real.</strong> If something looks off \u2014 missing integrations, wrong workspace, free-tier limits \u2014 the first thing to check is whether you're signed in with <code>@thehumanoid.ai</code> vs another account.</p></blockquote><h2 local-id=\"c4f4cf461330\" id=\"GettingStartedwithAI-GettingHelp\">Getting Help</h2><ul local-id=\"e798dd1b519e\"><li local-id=\"61438f5b2498\"><p local-id=\"7228f91078d7\">Internal questions \u2192 <a href=\"https://app.slack.com/client/T078M0VH3C6/C0AH0DKCGM7?cdn_fallback=2\" local-id=\"cec358080073\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://app.slack.com/client/T078M0VH3C6/C0AH0DKCGM7?cdn_fallback=2</a> or <a href=\"https://app.slack.com/client/T078M0VH3C6/C0813SXPKGF?cdn_fallback=2\" local-id=\"2437d4bcdf45\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://app.slack.com/client/T078M0VH3C6/C0813SXPKGF?cdn_fallback=2</a> on Slack</p></li><li local-id=\"68296b056f3d\"><p local-id=\"fcf35c540ce0\">Anthropic documentation \u2192 <a href=\"https://docs.anthropic.com\" class=\"external-link\" rel=\"nofollow\">docs.anthropic.com</a></p></li><li local-id=\"f6b7e0070cd4\"><p local-id=\"ad7e7f45de29\">Claude support \u2192 <a href=\"https://support.claude.ai\" class=\"external-link\" rel=\"nofollow\">support.claude.ai</a></p></li></ul>"
        },
        {
          "id": "1670709288",
          "title": "Robot Software Architecture (Current State)",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1670709288",
          "last_modified": "2026-04-30T22:30:39.255Z",
          "created_at": "2026-02-24T14:48:20.428Z",
          "body_html": "<p local-id=\"3804cd38fd78\"><em>Drafted 2026-02-24. This is a \u201chere\u2019s what exists today\u201d map of the system (Alpha-era RTPC + Orin split). It is intentionally <strong>descriptive</strong>, not prescriptive.</em></p><h2 local-id=\"41c4299b7206\" id=\"RobotSoftwareArchitecture(CurrentState)-0)Bigpicture\">0) Big picture</h2><p local-id=\"168e0cb4bc48\">The robot currently runs as a <strong>distributed ROS2 system</strong> split across two computers:</p><ul local-id=\"ecb135d314cc\"><li local-id=\"2676240d30d5\"><p local-id=\"7731e29f4aa7\"><strong>RTPC</strong>: real-time(ish) control stacks + nav/localization + hardware drivers + visualization bridge.</p></li><li local-id=\"0785acec604f\"><p local-id=\"5c2c7fc8bd6e\"><strong>Orin</strong>: cameras/vision + policy inference + app runtime (teleop, workflows, fleet).</p></li></ul><p local-id=\"ee9a049efc2c\">The guiding mental model for \u201cwhat talks to what\u201d today:</p><p local-id=\"7f4594284ddf\" /><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"683c4331-d454-47be-bb23-d68861db7bab\" data-local-id=\"1f0091dc4af0\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">graph TB\n  subgraph ORIN[&quot;Orin (application + perception + policy)&quot;]\n    SP[sockpuppet\nteleop + data collection]\n    RV[reverb_node\nworkflow agent]\n    BROKER[wbc_broker\ncommand arbitration + action proxy]\n    PAS[hmnd_policy_execution\npolicy_action_server]\n    VIS[hmnd_vision\nvision pipeline]\n  end\n\n  subgraph RTPC[&quot;RTPC (control + nav + hardware)&quot;]\n    NAV[&quot;hmnd_navigation\n(nav2 + action servers)&quot;]\n    LOC[&quot;hmnd_localization\n(map_server + neo_localization + slamtoolbox_service)&quot;]\n    WBC[whole_body_controller_interface\nWBC adapter + IK]\n    CTRL[&quot;ros2_control_node + controllers\n(alpha_*_description)&quot;]\n    HW[EtherCAT + IO + sensors]\n    FOX[foxglove_bridge]\n  end\n\n  %% Actions\n  RV &lt;--&gt;|ROS action| NAV\n  RV &lt;--&gt;|ROS action| BROKER\n\n  %% Policy path\n  RV --&gt;|&quot;/policy_execution (action)&quot;| BROKER\n  BROKER --&gt;|&quot;/policy_execution_internal (action)&quot;| PAS\n  PAS --&gt;|&quot;/wbc_broker/policy_commands (topic)&quot;| BROKER\n\n  %% Teleop path\n  SP --&gt;|&quot;/wbc_broker/teleop_commands (topic)&quot;| BROKER\n  SP --&gt;|&quot;/teleoperation_server/* (topics)&quot;| BROKER\n\n  %% Command output\n  BROKER --&gt;|&quot;/whole_body_controller_interface/robot_commands (topic)&quot;| WBC\n\n  %% Control + hardware\n  WBC --&gt;|controller interfaces| CTRL\n  CTRL --&gt; HW\n\n  %% Perception\n  VIS --&gt; SP\n  VIS --&gt; PAS\n\n  %% State/vis\n  RTPC --&gt; FOX</pre>\n</div></div><p local-id=\"68f56193682c\">Notes:</p><ul local-id=\"5f37344c5d6d\"><li local-id=\"df6935a849d4\"><p local-id=\"b86cac427919\">The diagram shows the <em>dominant</em> paths; there are many additional topics (TF, joint states, diagnostics, etc.).</p></li><li local-id=\"3b4881761705\"><p local-id=\"983ffc2819a1\">The Bosch demo launch files are good \u201cproxies\u201d for today\u2019s two partial-monolith bringups.</p></li></ul><h2 local-id=\"695c3f46dc36\" id=\"RobotSoftwareArchitecture(CurrentState)-1)Primarybringupentrypoints(Pixi)\">1) Primary bringup entrypoints (Pixi)</h2><h3 local-id=\"1ea98722fe43\" id=\"RobotSoftwareArchitecture(CurrentState)-RTPC-side\u201cstack\u201d\">RTPC-side \u201cstack\u201d</h3><ul local-id=\"12c150ae90cb\"><li local-id=\"0c4af9fff54f\"><p local-id=\"9cbbeaef3e74\"><code>pixi run reverb_rtpc_alpha_wheelbase</code> (controllers + WBC + nav stack + helper nodes)</p></li><li local-id=\"40be18eb9d0f\"><p local-id=\"5bab98e4b366\">Bosch proxy monolith: <code>pixi run reverb_bosch_rtpc_alpha_ft</code></p></li></ul><h3 local-id=\"c45860403b0f\" id=\"RobotSoftwareArchitecture(CurrentState)-Orin-side\u201cstack\u201d\">Orin-side \u201cstack\u201d</h3><ul local-id=\"19335b759577\"><li local-id=\"b9b2fedc9d98\"><p local-id=\"1c3f1fb5344d\"><code>pixi run reverb_alpha_wheelbase</code> (reverb + sockpuppet + vision + policy + broker when enabled)</p></li><li local-id=\"8fd9c0efba78\"><p local-id=\"4477701ec99d\">Bosch proxy monolith: <code>pixi run reverb_bosch_orin_alpha</code></p></li></ul><h2 local-id=\"b99b90b21c10\" id=\"RobotSoftwareArchitecture(CurrentState)-2)Package/modulemap(wherethemaincodelives)\">2) Package / module map (where the main code lives)</h2><h3 local-id=\"71a5d7b68abb\" id=\"RobotSoftwareArchitecture(CurrentState)-\u201cApps\u201d(top-levelruntimes)\">\u201cApps\u201d (top-level runtimes)</h3><ul local-id=\"a6681385ee52\"><li local-id=\"611ad78145f4\"><p local-id=\"4efee9ce1a17\"><code>hmnd_robot/apps/reverb</code> \u2014 workflow agent + orchestration launch files (<code>reverb.launch.py</code>, <code>reverb_mock.launch.py</code>).</p></li><li local-id=\"fd725ffd77f5\"><p local-id=\"4a367d8ad8a8\"><code>hmnd_robot/apps/sockpuppet</code> \u2014 browser-based teleop + data collection; launches Quest teleop server and optionally vision/policy.</p></li><li local-id=\"08d60e435e01\"><p local-id=\"bfdcae9d5768\"><code>hmnd_robot/apps/wbc_broker</code> \u2014 arbitration between teleop and policy WBC commands; proxies the policy action.</p></li><li local-id=\"59c5df245c67\"><p local-id=\"0a7e01c4af85\"><code>hmnd_robot/apps/alpha_bringup</code> \u2014 RTPC bringup launch files (controllers + nav + helpers).</p></li></ul><h3 local-id=\"c7fec0788ff9\" id=\"RobotSoftwareArchitecture(CurrentState)-Control\">Control</h3><ul local-id=\"78eb8f7e017b\"><li local-id=\"787994068efb\"><p local-id=\"d94c4d7f4026\"><code>hmnd_robot/ros/control/whole_body_controller</code> \u2014 <code>whole_body_controller_interface</code> (ROS-facing adapter around WBC/IK and controller forwarding).</p></li><li local-id=\"8bfc34b0bcf1\"><p local-id=\"47336d7efa51\"><code>hmnd_robot/ros/platforms/*_description</code> \u2014 ros2_control + platform description + controller bringup.</p></li><li local-id=\"d0ff88228d2d\"><p local-id=\"b68fa908c73b\"><code>hmnd_robot/ros/platforms/alpha_wheelbase_description/launch/controllers_bringup.launch.py</code> \u2014 launches <code>ros2_control_node</code>, controller spawners, state publisher, joint-state merger, kinematics node, plus some real-hardware helpers.</p></li></ul><h3 local-id=\"d08848e555f1\" id=\"RobotSoftwareArchitecture(CurrentState)-Navigation+localization\">Navigation + localization</h3><ul local-id=\"ce803b1dec15\"><li local-id=\"f22c748e5fe7\"><p local-id=\"00da3cb8aad2\"><code>hmnd_robot/ros/perception/hmnd_navigation</code> \u2014 nav2 stack wrapper + action servers (<code>navigate_to_pose</code>, <code>navigate_to_tag</code>, etc.).</p></li><li local-id=\"daf1eeaa52e3\"><p local-id=\"eb91ceba5152\"><code>hmnd_robot/ros/perception/hmnd_localization</code> \u2014 map server + localization + slam_toolbox lifecycle wrapper.</p></li></ul><h3 local-id=\"a1e2a31bd492\" id=\"RobotSoftwareArchitecture(CurrentState)-Perception\">Perception</h3><ul local-id=\"8d3914160e3e\"><li local-id=\"f265cea6520e\"><p local-id=\"1d17683a5051\"><code>hmnd_robot/ros/perception/hmnd_vision</code> \u2014 camera pipeline (<code>hmnd_vision</code> node) configured via YAML + intrinsics folder.</p></li></ul><h3 local-id=\"d3885c2004f3\" id=\"RobotSoftwareArchitecture(CurrentState)-Policyexecution\">Policy execution</h3><ul local-id=\"3151c3cc9ad9\"><li local-id=\"652288d91339\"><p local-id=\"f521032624ea\"><code>hmnd_robot/ros/robot_learning/hmnd_policy_execution</code> \u2014 <code>policy_action_server</code> (default action name <code>policy_execution</code>).</p></li></ul><h2 local-id=\"559d18794ef4\" id=\"RobotSoftwareArchitecture(CurrentState)-3)Keyinterfaces(topics,actions,services)\">3) Key interfaces (topics, actions, services)</h2><p local-id=\"7263c68f805d\">This is not exhaustive; it\u2019s the set that tends to matter for reasoning about the system.</p><h3 local-id=\"294a112cbf21\" id=\"RobotSoftwareArchitecture(CurrentState)-3.1Actions\">3.1 Actions</h3><h4 local-id=\"6c61988e59e7\" id=\"RobotSoftwareArchitecture(CurrentState)-Navigation(RTPC)\">Navigation (RTPC)</h4><p local-id=\"fb70a9de2e0c\">Provided by <code>hmnd_navigation</code> (via composed nodes + nav2):</p><ul local-id=\"9b2f2a12caaa\"><li local-id=\"75250859c24a\"><p local-id=\"7f0d7ee65baa\"><code>/navigate_to_pose</code> (hmnd_msgs/action/NavigateToPose)</p></li><li local-id=\"02eda6e45a10\"><p local-id=\"f035ea03114e\"><code>/navigate_through_poses</code> (hmnd_msgs/action/NavigateThroughPoses)</p></li><li local-id=\"e5ec7aee4774\"><p local-id=\"bb5330225909\"><code>/navigate_to_tag</code> (hmnd_msgs/action/NavigateToTag)</p></li><li local-id=\"3da81e62554a\"><p local-id=\"ff35bb169048\"><code>/navigate_path</code> (hmnd_msgs/action/NavigatePath)</p></li></ul><p local-id=\"19b6420511c3\">Notes:</p><ul local-id=\"049782e59ebc\"><li local-id=\"a2be4dbc5fcd\"><p local-id=\"aeef0792f8a5\">These actions internally call nav2 actions like <code>compute_path_to_pose</code>, <code>compute_path_through_poses</code>, and <code>follow_path</code>.</p></li></ul><h4 local-id=\"4ee335c695b7\" id=\"RobotSoftwareArchitecture(CurrentState)-Policy(Orin)\">Policy (Orin)</h4><ul local-id=\"e84968c6d36e\"><li local-id=\"dec29832faac\"><p local-id=\"c3189fbe5e8e\"><code>/policy_execution</code> (hmnd_msgs/action/ManipulationPolicy)</p></li></ul><p local-id=\"673a52d966cf\">When the broker is enabled, the public action is typically provided by the broker:</p><ul local-id=\"a79bdb96fdc3\"><li local-id=\"4c9daab153c9\"><p local-id=\"e18a8c727787\">Broker serves: <code>/policy_execution</code></p></li><li local-id=\"2cfddb6b925c\"><p local-id=\"4ec26769ac4f\">Broker forwards to: <code>/policy_execution_internal</code></p></li></ul><h3 local-id=\"59b8581c2c20\" id=\"RobotSoftwareArchitecture(CurrentState)-3.2Topics\">3.2 Topics</h3><h4 local-id=\"d0f85078a26b\" id=\"RobotSoftwareArchitecture(CurrentState)-WBCcommandarbitration+control\">WBC command arbitration + control</h4><ul local-id=\"18dc30f020c2\"><li local-id=\"2565d7536b31\"><p local-id=\"0204b9529786\"><code>/wbc_broker/teleop_commands</code> \u2014 teleop-origin WBC commands (source: sockpuppet)</p></li><li local-id=\"0fec11f0b58b\"><p local-id=\"9c49446f520e\"><code>/wbc_broker/policy_commands</code> \u2014 policy-origin WBC commands (source: policy_action_server)</p></li><li local-id=\"ce065ec49039\"><p local-id=\"34366fb347f0\"><code>/teleoperation_server/teleop_active</code> (Bool)</p></li><li local-id=\"52ca313443fd\"><p local-id=\"cf8414eaeeb0\"><code>/teleoperation_server/teleop_commanding</code> (Bool)</p></li><li local-id=\"c04e1e9ceefd\"><p local-id=\"4f005d559b11\"><code>/whole_body_controller_interface/robot_commands</code> \u2014 final WBC command stream consumed by RTPC WBC interface</p></li></ul><h4 local-id=\"ffeee9b81ad0\" id=\"RobotSoftwareArchitecture(CurrentState)-WBCinterfaceoutputs/status(RTPC)\">WBC interface outputs / status (RTPC)</h4><ul local-id=\"0cbf4578487d\"><li local-id=\"1aef77be8807\"><p local-id=\"d176f197d1d5\"><code>/whole_body_controller_interface/wbc_solution_is_valid</code> (Bool)</p></li><li local-id=\"455d02ddb461\"><p local-id=\"d562e0f5029b\"><code>/whole_body_controller_interface/wbc_loaded_configuration</code> (String)</p></li><li local-id=\"c44f05db85be\"><p local-id=\"b86519c53a85\"><code>/whole_body_controller_interface/diagnostics</code> (DiagnosticArray)</p></li><li local-id=\"a0c0abc470fa\"><p local-id=\"8a0adb6edae7\"><code>/whole_body_controller_interface/pose_broadcaster/*/pose</code> (PoseStamped)</p></li></ul><h4 local-id=\"c903ff7a8d28\" id=\"RobotSoftwareArchitecture(CurrentState)-Navigation+localization(RTPC)\">Navigation + localization (RTPC)</h4><ul local-id=\"c141b8f0976e\"><li local-id=\"f75cedf9ccda\"><p local-id=\"a77a9976386a\"><code>/tf</code>, <code>/tf_static</code></p></li><li local-id=\"7d4580c2e39c\"><p local-id=\"c9712a500c1b\"><code>/plan</code> (nav2), and <code>hmnd_navigation/nav_plan_publisher</code> re-publishes as <code>/plan_viz</code></p></li><li local-id=\"d763b4c74e47\"><p local-id=\"5d545f6baa78\">lidar driver topics (as currently wired in RTPC bringup):</p><ul local-id=\"690335d6da66\"><li local-id=\"15c915997863\"><p local-id=\"0103fd2304d1\"><code>/lidar_1/scan_filtered</code>, <code>/lidar_2/scan_filtered</code></p></li><li local-id=\"f65c20a465ef\"><p local-id=\"ebb5e33dd349\"><code>scan_merged</code>, <code>cloud_merged</code> (from <code>dual_laser_merger_node</code>)</p></li></ul></li><li local-id=\"23a81e2c825b\"><p local-id=\"83bfcfc3d222\">localization commonly publishes pose on <code>/amcl_pose</code> (see hmnd_localization config)</p></li></ul><h4 local-id=\"ea1376adacbe\" id=\"RobotSoftwareArchitecture(CurrentState)-Robotstate(RTPC)\">Robot state (RTPC)</h4><ul local-id=\"20fdfa1e8d9a\"><li local-id=\"8ed8095e4a76\"><p local-id=\"4c7a8a9d12c5\"><code>/merged/joint_states</code> (due to <code>robot_state_publisher</code> remap)</p></li></ul><h3 local-id=\"3f146c00f50f\" id=\"RobotSoftwareArchitecture(CurrentState)-3.3Services\">3.3 Services</h3><h4 local-id=\"f6adc00bf8ab\" id=\"RobotSoftwareArchitecture(CurrentState)-WholeBodyControllerinterface(RTPC)\">Whole Body Controller interface (RTPC)</h4><p local-id=\"c6780a68335e\">Provided by <code>whole_body_controller_interface</code>:</p><ul local-id=\"5cb09b9c0d07\"><li local-id=\"df5bcea1d4d2\"><p local-id=\"e619177cd6f3\"><code>/whole_body_controller_interface/reset_wbc_tasks</code></p></li><li local-id=\"3a301b329707\"><p local-id=\"893b05924f19\"><code>/whole_body_controller_interface/reset_wbc_targets</code></p></li><li local-id=\"b2dee578561b\"><p local-id=\"c7fbf3187f56\"><code>/whole_body_controller_interface/reset_joint_configuration</code></p></li><li local-id=\"e67dcc614198\"><p local-id=\"7a93d4b022c2\"><code>/whole_body_controller_interface/toggle_wbc_target_distance_check</code></p></li><li local-id=\"cbd293a30da7\"><p local-id=\"09e59a5087c7\"><code>/whole_body_controller_interface/get_last_grasp_primitive_command</code></p></li></ul><h4 local-id=\"877cfa0e2f16\" id=\"RobotSoftwareArchitecture(CurrentState)-Localization(RTPC)\">Localization (RTPC)</h4><ul local-id=\"cd537a6728b8\"><li local-id=\"0b375ca34df5\"><p local-id=\"b3c9a2ea8f42\">Map server (nav2_map_server) provides map-serving services.</p></li><li local-id=\"d92ea15caa47\"><p local-id=\"e347c39bcf61\"><code>slamtoolbox_service.py</code> owns starting/stopping the <code>slam_toolbox</code> mapping process and checks readiness via <code>/slam_toolbox/serialize_map</code>.</p></li></ul><h2 local-id=\"61b3faf2de7a\" id=\"RobotSoftwareArchitecture(CurrentState)-4)Roughdataflownarratives\">4) Rough data flow narratives</h2><h3 local-id=\"7b2c7135b5f2\" id=\"RobotSoftwareArchitecture(CurrentState)-Teleop\u2192motion\">Teleop \u2192 motion</h3><ol start=\"1\" local-id=\"0cf3190a3772\"><li local-id=\"f97711cdae89\"><p local-id=\"1ec2178f4e5e\">Operator uses sockpuppet UI (Orin) \u2192 Quest teleop server publishes WBC teleop commands.</p></li><li local-id=\"1bffa825c4fe\"><p local-id=\"21880ab4fc8f\"><code>wbc_broker</code> arbitrates based on <code>/teleoperation_server/teleop_active</code> and <code>/teleoperation_server/teleop_commanding</code>.</p></li><li local-id=\"a9f14bddf408\"><p local-id=\"9628268f590b\"><code>wbc_broker</code> publishes to <code>/whole_body_controller_interface/robot_commands</code>.</p></li><li local-id=\"de6310ba7695\"><p local-id=\"236e1fb9843e\">RTPC <code>whole_body_controller_interface</code> consumes commands, solves IK / checks safety-ish constraints, forwards to low-level controllers.</p></li><li local-id=\"3d18c32cb77a\"><p local-id=\"b229fcfa01f6\"><code>ros2_control_node</code> + platform controllers drive hardware.</p></li></ol><h3 local-id=\"992bfeddd6f4\" id=\"RobotSoftwareArchitecture(CurrentState)-Policy\u2192motion(withbroker)\">Policy \u2192 motion (with broker)</h3><ol start=\"1\" local-id=\"004f00c64816\"><li local-id=\"a44788602425\"><p local-id=\"4f90d5bf102e\">Client (often Reverb) sends action goal to <code>/policy_execution</code>.</p></li><li local-id=\"3aa471d90248\"><p local-id=\"3e4c60dba287\"><code>wbc_broker</code> proxies the action to <code>/policy_execution_internal</code> on <code>policy_action_server</code>.</p></li><li local-id=\"e3df98e95d78\"><p local-id=\"a884109f443d\">Policy publishes WBC commands to <code>/wbc_broker/policy_commands</code>.</p></li><li local-id=\"9b3d0af311ab\"><p local-id=\"6494d11690f2\">Broker forwards to <code>/whole_body_controller_interface/robot_commands</code> when teleop is not active.</p></li></ol><h3 local-id=\"70df38c63d8c\" id=\"RobotSoftwareArchitecture(CurrentState)-Nav\u2192motion\">Nav \u2192 motion</h3><ol start=\"1\" local-id=\"3cc1e5f153bb\"><li local-id=\"419b322d36ba\"><p local-id=\"acecf9fed45c\">Client (often Reverb) sends navigation action goal (e.g., <code>/navigate_to_tag</code>).</p></li><li local-id=\"f0962521e462\"><p local-id=\"29259ab01cfd\"><code>hmnd_navigation</code> computes path \u2192 follows path (nav2).</p></li><li local-id=\"c9dc31718255\"><p local-id=\"e0a9e29d3cd6\">Nav stack outputs base motion commands to the base controller path (exact topic wiring depends on platform; wheelbase vs biped differs).</p></li></ol><h2 local-id=\"24f5f70c97b4\" id=\"RobotSoftwareArchitecture(CurrentState)-5)Observability(whatwedotoday)\">5) Observability (what we do today)</h2><ul local-id=\"33fa55138b6d\"><li local-id=\"2f79dcbf89a4\"><p local-id=\"d6c9ee80a61f\">RTPC bringup typically includes <code>foxglove_bridge</code> (topic whitelist to reduce bandwidth).</p></li><li local-id=\"93c97fd18a3b\"><p local-id=\"0acb18ca362c\">Many nodes publish diagnostics; WBC interface publishes <code>DiagnosticArray</code> and internal metrics.</p></li></ul><h2 local-id=\"83178c2e4fd4\" id=\"RobotSoftwareArchitecture(CurrentState)-6)Knownsharpedges(currentstate)\">6) Known sharp edges (current state)</h2><ul local-id=\"78a2477a8113\"><li local-id=\"f438d08a985d\"><p local-id=\"c7267db685c0\">TF/joint-state churn: many consumers reconstruct state outside the control process.</p></li><li local-id=\"1a51be856006\"><p local-id=\"49b4e6f0f118\">Multi-process nav stack composition is mixed: some components are composed, others intentionally not (performance degradation was observed for composing nav2 <code>controller_server</code>).</p></li><li local-id=\"902bf15e08b5\"><p local-id=\"13617ea84187\">Cross-machine ROS graph can become \u201caccidental coupling\u201d (ad-hoc topics leak across RTPC\u2194Orin).</p></li></ul><h2 local-id=\"d8e7ae35c47b\" id=\"RobotSoftwareArchitecture(CurrentState)-7)Next:makethispageactionable\">7) Next: make this page actionable</h2><p local-id=\"713fd7018f9f\">If we want, the next iteration of this doc can include:</p><ul local-id=\"8879a0aa61a1\"><li local-id=\"aceee3813b8a\"><p local-id=\"bbb55647e434\">a Phase 0 \u201ccontract v0\u201d section: the exact RTPC\u2194Orin interface list + rate/size budgets</p></li><li local-id=\"e565d1852fc3\"><p local-id=\"68a3f3df8d11\">a per-monolith \u201cinternal vs external topic\u201d rubric (what is allowed to cross machines)</p></li><li local-id=\"029cc038c5a9\"><p local-id=\"f774e622885b\">a single canonical \u201cbringup matrix\u201d (Alpha wheelbase vs biped; real vs mock vs isaacsim)</p></li></ul>"
        },
        {
          "id": "1931476998",
          "title": "System 2 vs System 3",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1931476998",
          "last_modified": "2026-04-30T15:13:27.867Z",
          "created_at": "2026-04-30T13:53:36.992Z",
          "body_html": "<p local-id=\"9a5f50d828e0\"><span class=\"inline-comment-marker\" data-ref=\"76625972-711b-413e-aed6-1200cac23829\">There is some confusion</span> perhaps around System 2 (agent-on-robot) and System 3 (agent-for-fleet) terminology.  I think some of this stems from the public terminology found in <a href=\"https://thehumanoid.ai/ai/\" local-id=\"c0c0ddf90471\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://thehumanoid.ai/ai/</a>, or that our product team uses internally.  In reality during implementation, we will typically need to be more precise.</p><h2 local-id=\"314df8f17503\" id=\"System2vsSystem3-Whatis\u201cSystem-3\u201d\">What is \u201cSystem-3\u201d</h2><p local-id=\"292309572101\">Consider a service like <a href=\"http://Claude.ai\" class=\"external-link\" rel=\"nofollow\">Claude.ai</a>.  Clearly there is a model.  And there is a product where users can chat with that model.  But under the hood, there are going to be enormous amounts of bits and pieces to provide this product.  KV caches, routing/batching, databases, authz, connectors/integrations, memory.  Probably literally hundreds more.</p><p local-id=\"2c6896223370\">Similarly, we should consider System-3 to be the broad term for how users interface with our fleet as a whole.  This is where we talk about work, assign tasks, reason about overall efficiency.  Its also where we\u2019ll edit workflows,  re-assign robots and run analysis to improve performance over time.  Similar to <a href=\"http://claude.ai\" class=\"external-link\" rel=\"nofollow\">claude.ai</a> there are many different pieces involve<span class=\"inline-comment-marker\" data-ref=\"94406020-be12-4532-9674-e36cf1f5330e\">d.</span></p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"918\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1931476998/Untitled%20Diagram-1777560109616.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1931476998/Untitled%20Diagram-1777560109616.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p local-id=\"7ebb8d52c96c\"><strong>Switchboard</strong></p><p local-id=\"6f02b2bd41ee\">Switchboard specifically functions as a strongly consistent database where many services/agents can safely coordinate on some shared understanding of the world.  Because we need to ensure only one robot at a time attempts to pick from some given tote stack or navigate through some specific passage, we need strong consistency guarantees so that everyone can agree on the both the current state of the world, and the recent history.  The current implementation of Switchboard is primitive.  It only recently gained the ability to persist its data to disk.  But its role/function within the broader context of \u201csystem-3\u201d is basically as a shared database that other parts of system-3 can use to coordinate effectively.</p><p local-id=\"c7f5481985cd\">Like most databases, Switchboard is dumb.  It doesn\u2019t \u201cdo\u201d anything.  It responds to queries, and doesn\u2019t generally take action on its own.</p><p local-id=\"d80b71f62ab4\"><strong>System-3 Agents and Services</strong></p><p local-id=\"b80a79ae6f6d\">In the same way that an authorization service like IAM may be used by hundreds of other services to gate access to resources in the cloud, Switchboard can provide coordination services to many other services within System-3, with some of these services being more \u201cagentic\u201d than others.  Generally if we want the fleet as a whole to do anything, this functionality would be implemented within some System-3 agent or service which would in turn make queries to Switchboard to drive the workflow forward.</p><p local-id=\"488e751e9d54\">For example, Workflow Authoring is currently implemented as a System-3 agent.  What makes it a System-3 agent?  It has no body and it operates at a more abstract fleet-level.  It can modify workflows and facts within Switchboard.  This is analogous to having a conversation with Claude and stashing artifacts in a database.</p><p local-id=\"3d22360bd3f8\">A non-agentic System-3 service would be something like the SAP integration service (the non-A2A version), or a potential VDA5050 gateway to interop with some other fleet mgmt solution.  These services bridge something on the outside world to the fleet as a whole.</p><p local-id=\"dfb3e0ee8e13\">We also have a non-agentic \u201cmap\u201d service where we can store maps/tags to be shared with other clients.  Robots obviously need this data, but its not a big leap to imagine that some other system-3 service or agent may benefit from accessing this map data.  The map service is probably more like switchboard (more foundational/data-basey), but its still fleet-wide and not specific to any robot.  The map service is likely to become extremely sophisticated as we transition to large 3D maps - these maps may be so large as to be streamed in pieces to robots, with a bunch of additional indexing and spatial queries being supported.  This starts to look increasingly like a spatial database, which complements switchboard which functions more as a coordination database.</p><h2 local-id=\"883f29842059\" id=\"System2vsSystem3-Whatis\u201cSystem-2\u201d\">What is \u201cSystem-2\u201d</h2><p local-id=\"351a44db2e31\">Technically, robots talk to Switchboard in a way that\u2019s no different than any of the other System-3 agents that may exist.  What makes System-2 special is that it controls a robot and can have <em>direct</em> action in the real world via the available tools.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"892\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1931476998/Untitled%20Diagram-1777560744026.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1931476998/Untitled%20Diagram-1777560744026.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p local-id=\"daaf808233d4\">System-2 is where the robot has agency.  Switchboard is just another tool which can be used to query information about the current workflow, available workflows, the current assignments, etc.  Switchboard is a relatively sparse, abstract and inaccurate view of the world.  The robot has MUCH more context about what\u2019s happening, and so System-2 should ultimately be responsible for what the robot does.  This of course can exist on a sliding scale.  At one extreme, the system is fixed to ONLY execute assignments from Switchboard as they arrive.  This has largely been how we\u2019ve operated through the robostore demo.  It\u2019s predictable and simple.  At the other extreme, the robot can choose to consider the assignments from switchboard as a suggestion.  Maybe it decides to do something else because its closer.  Or improvise in some other way.  It\u2019s flexible and adaptable, but could be problematic.  The value of the System-3 / System-2 split is that we can control this tradeoff directly.  For example, a reasonable middle ground is that we follow assignments in the happy path, but if something goes wrong, the robot can \u201cskip\u201d the rest of the workflow and return home to await another task and resume the current one later. </p><h2 local-id=\"522eeab249bd\" id=\"System2vsSystem3-CouplingandInteraction\">Coupling and Interaction</h2><p local-id=\"4b69c78768b1\">Generally, we should minimize the coupling between the different parts of our system.  Most interactions should be able to take place via Switchboard.  This is simple and easy to scale.  Having robots directly communicating with specific System-3 agents greatly increases the coupling in the system.  Remember that we will need to apply software updates to all these pieces - and its unlikely that we can update things simultaneously, and its unlikely that we can tolerate downtime.  This means rolling updates.  Switchboard\u2019s API is designed to be simple enough that compatibility isn\u2019t a big challenge, and it isolates the individual components of the system to a degree that makes rolling updates relatively simple.</p><p local-id=\"20d58974e700\">If individual robots start to integrate with OTHER System-3 services or agents directly, this can quickly become a very tight knot that is impossible to untie without significant pain.  Similarly, robots generally shouldn\u2019t communicate peer-to-peer.  1st, there are generally n<sup>2</sup> different pairs where this communication could happen, which is far more than the n channels needed to communicate with Switchboard as a hub/spoke model.  2nd, these \u201csidebar\u201d conversations would be invisible to the rest of the fleet which could cause some challenges with coordination.</p><p local-id=\"794095284c2a\"><strong>Agent to Agent</strong></p><p local-id=\"cf85fc0b6186\">One of the massive benefits of A2A comms is that it sorta bypasses the nitty gritty of API compatibility trivially, but it replaces it with a lot of non-determinism and unpredictability.  We should be very mindful about how and where we use this.</p><p local-id=\"d7a30d2e29c9\">Generally, the happy path of the system should go via Switchboard.  Robots should be leasing/firing transitions, updating tokens and facts along the way.  Other robots and system-3 agents see these updates reflected immediately and can take their own actions.  Everything moves forward, its easy to audit and trace.</p><p local-id=\"c1971dda1800\">But what if something goes wrong?  In these cases, it may make sense to open an A2A escalation path to a dedicated System-3 agent.  For example, perhaps the robot is stuck in some complicated traffic jam.  It can escalate as much context as possible via an unstructured A2A protocol and this agent can manipulate switchboard in such a way or give the Robot\u2019s System-2 agent additional info necessary to resolve the issue.  These exceptional cases are the best usage of A2A protocols.</p><h1 local-id=\"fdc68041f157\" id=\"System2vsSystem3-Conclusion\">Conclusion</h1><p local-id=\"44abf7ea1d9d\">Switchboard is a dumb database, and doesn\u2019t \u201cdrive\u201d anything.  Because its dumb, we can put it in the middle of the system to help with coordination challenges at fleet scale.  At the fleet level, we may have a number of \u201csystem 3\u201d services which interface with switchboard, dispatching orders, adjusting priorities, resolving issues, authoring changes.  At the robot level, Reverb is the system-2 agent which has autonomy and can use its tools to perceive the world, retrieve assignments from switchboard and take action via manipulation or navigation.</p><p local-id=\"9034e6fb407f\" />"
        },
        {
          "id": "1929904147",
          "title": "hmnd-cloud -> hmnd",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1929904147",
          "last_modified": "2026-04-30T10:43:22.229Z",
          "created_at": "2026-04-30T10:37:58.285Z",
          "body_html": "<h1 id=\"hmnd-cloud-&gt;hmnd-hmnd-cloud-&gt;hmnd/hmnd_cloud\">hmnd-cloud -&gt; hmnd/hmnd_cloud</h1><p>This should be a boring lift/shift. Keep the <code>hmnd-cloud</code> repo intact under <code>hmnd/hmnd_cloud</code>, preserve history with <code>git subtree</code>, then wire the old pipelines into the root <code>hmnd_ci</code> workflow behind normal <code>detect-changes</code> gates.</p><p>The important rule: do not reorganise Terraform during the migration. Run Terraform from the same module roots, just with the new monorepo prefix:</p><ul><li><p><code>hmnd_cloud/infrastructure</code></p></li><li><p><code>hmnd_cloud/ml-infrastructure</code></p></li><li><p><code>hmnd_cloud/deployables</code></p></li><li><p><code>hmnd_cloud/hmnd_deployment</code></p></li><li><p><code>hmnd_cloud/onprem-infrastructure</code></p></li></ul><p>Terraform state tracks resource addresses, module names, provider config, backend config, and variables. It does not care that the Git checkout path changed, as long as the module internals and backend keys stay the same.</p><h2 id=\"hmnd-cloud-&gt;hmnd-Proposedmigration\">Proposed migration</h2><ol start=\"1\"><li><p>Create the monorepo branch.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"7d90ec6b-32fa-4efa-b5ac-ad4959f76172\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">cd hmnd\ngit checkout -b migrate/hmnd-cloud</pre>\n</div></div></li><li><p>Import <code>hmnd-cloud</code> with history.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"5b2b5987-6076-443b-97a2-aea2bc52d546\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">git subtree add \\\n  --prefix=hmnd_cloud \\\n  git@github.com:HumanoidTeam/hmnd-cloud.git \\\n  main</pre>\n</div></div><p>This keeps the old commits reachable in <code>hmnd</code> history while putting the old repo under one directory. Avoid <code>--squash</code>.</p></li><li><p>Do the minimum mechanical path fixes.</p><p>Move or copy the old GitHub workflows into root <code>.github/workflows</code> with new names, then prefix repo-local paths with <code>hmnd_cloud/</code>. Examples:</p><ul><li><p><code>infrastructure</code> -&gt; <code>hmnd_cloud/infrastructure</code></p></li><li><p><code>ml-infrastructure</code> -&gt; <code>hmnd_cloud/ml-infrastructure</code></p></li><li><p><code>deployables/...</code> -&gt; <code>hmnd_cloud/deployables/...</code></p></li><li><p><code>hmnd_deployment/...</code> -&gt; <code>hmnd_cloud/hmnd_deployment/...</code></p></li><li><p><code>deployables/common.pkrvars.hcl</code> -&gt; <code>hmnd_cloud/deployables/common.pkrvars.hcl</code></p></li></ul></li><li><p>Add <code>hmnd_cloud</code> to <code>hmnd_ci</code> change detection.</p><p>Add one detector output, for example <code>hmnd_cloud_changed</code>, watching:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"412ce22d-ac3f-434c-8c58-fe9236c85680\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">hmnd_cloud:\n  - hmnd_cloud/**</pre>\n</div></div><p>Then roll it into <code>plan</code> exactly like the other areas. The old standalone <code>on.pull_request.paths</code> filters are no longer the primary guard; <code>hmnd_ci.detect-changes</code> should decide whether the migrated cloud jobs run.</p></li><li><p>Add reusable cloud workflows under <code>hmnd_ci</code>.</p><p>Keep the old jobs mostly intact, but make them <code>workflow_call</code> workflows and call them from <code>hmnd_ci</code> only when <code>hmnd_cloud_changed</code>, workflow files changed, or the run is forced.</p><p>Suggested split:</p><ul><li><p><code>test_hmnd_cloud_infrastructure.yaml</code>: fmt, lint, security, validate, plan for <code>hmnd_cloud/infrastructure</code>.</p></li><li><p><code>test_hmnd_cloud_ml_infrastructure.yaml</code>: matrix, fmt, lint, security, validate, plan for <code>hmnd_cloud/ml-infrastructure</code>.</p></li><li><p><code>build_hmnd_cloud_amis.yaml</code>: wraps the existing Packer jobs, still manually runnable if wanted.</p></li><li><p><code><span class=\"inline-comment-marker\" data-ref=\"fe96bb8a-cad4-4752-940e-78824aa3d779\">deploy_hmnd_cloud_robots</span>.yaml</code>: keep manual only unless there is a strong reason to run from CI.</p></li></ul></li><li><p>Open a PR with only the subtree import and CI/path wiring.</p><p>Do not rename Terraform resources, modules, backend keys, buckets, tags, or project names as part of this PR. Those can be follow-up cleanups after the plan proves stable.</p></li></ol><h2 id=\"hmnd-cloud-&gt;hmnd-Terraformproof\">Terraform proof</h2><p>Expected local proof after the subtree import and path-only CI changes:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"12066c3a-27de-43a1-b54a-a071a170b8f0\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">cd hmnd/hmnd_cloud/infrastructure\nterraform init -input=false -no-color\nterraform plan -input=false -no-color -lock=false</pre>\n</div></div><p>Expected result: no repository-path-driven changes. A clean run should end with:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"1b69080d-471f-49e3-99ef-e3b55cfa02dd\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: text; gutter: false; theme: Confluence\" data-theme=\"Confluence\">No changes. Your infrastructure matches the configuration.</pre>\n</div></div><p>For ML infrastructure, run the same plan per backend:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"7f1a3af4-1415-4fe6-a916-15699ca3bb7b\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">cd hmnd/hmnd_cloud/ml-infrastructure\nterraform init -input=false -no-color -reconfigure \\\n  -backend-config=backends/backend-dev-eu-west-2.hcl\nterraform plan -input=false -no-color -lock=false \\\n  -var='environment=dev' \\\n  -var='region=eu-west-2'</pre>\n</div></div><p>Repeat for:</p><ul><li><p><code>backend-dev-eu-west-2.hcl</code></p></li><li><p><code>backend-dev-us-west-1.hcl</code></p></li><li><p><code>backend-prod-eu-west-2.hcl</code></p></li></ul><p>CI proof should be a deliberately harmless PR change, for example a small README edit under <code>hmnd_cloud/README.md</code>. That should trigger <code>hmnd_ci.detect-changes</code>, run only the hmnd-cloud workflows, and show the same clean Terraform plans in CI.</p><h2 id=\"hmnd-cloud-&gt;hmnd-Thingstowatch\">Things to watch</h2><p>I scanned the current <code>hmnd-cloud</code> checkout on 2026-04-30. These are the likely hiccups.</p><p>Hard-coded workflow paths need prefixing. The old workflows assume they live at repo root:</p><ul><li><p><code>.github/workflows/deploy-infrastructure.yml</code>: <code>working-directory: infrastructure</code>, <code>scan-ref: infrastructure</code>, cache keys, artifact paths.</p></li><li><p><code>.github/workflows/deploy-ml-infrastructure.yml</code>: <code>working-directory: ml-infrastructure</code>, backend discovery with <code>find ml-infrastructure/backends</code>, cache keys, artifact paths.</p></li><li><p><code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">.github/workflows/shared-ami-build.yml</span></code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">: </span><code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">deployables/common.pkrvars.hcl</span></code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\"> and Packer directories.</span></p></li><li><p><code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">.github/workflows/build-base-gpu-ami.yml</span></code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">, </span><code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">build-github-runner-ami.yml</span></code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">, </span><code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">build-simulation-ami.yml</span></code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">: </span><code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">packer_dir</span></code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\"> values under </span><code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">deployables/...</span></code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">.</span></p></li><li><p><code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">.github/workflows/deploy-to-robots.yml</span></code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">: checkout path and script paths explicitly use </span><code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">hmnd-cloud</span></code><span class=\"inline-comment-marker\" data-ref=\"cda9b78e-8d9a-4c46-b702-55579331ea86\">.</span></p></li></ul><p>Repo-name references exist and should be reviewed, but most should not block the first lift/shift:</p><ul><li><p><code>ml-infrastructure/config.yaml</code> allows ARC runners for both <code>HumanoidTeam/hmnd-cloud</code> and <code>HumanoidTeam/hmnd</code>. After migration, keep <code>hmnd</code> and remove <code>hmnd-cloud</code> only after old repo CI is retired.</p></li><li><p><code>infrastructure/domains/shared-between-teams/github-runners/main.tf</code> defaults <code>GITHUB_RUNNERS_REPO</code> to <code>HumanoidTeam/hmnd-cloud</code>. This is probably overridden by <code>TF_VAR_GITHUB_RUNNERS_REPO</code>; confirm in repo variables before changing it.</p></li><li><p><code>infrastructure/variables.tf</code>, <code>deployables/common.pkrvars.hcl</code>, <code>infrastructure/domains/simulation/coder/templates/simulation-workspace/main.tf</code>, and <code>infrastructure/domains/shared-between-teams/skypilot/skypilot-config.yaml</code> contain <code>hmnd-cloud</code> as project/tag/bucket naming. Do not rename these during the migration unless the plan explicitly proves it is harmless.</p></li><li><p><code>infrastructure/domains/shared-between-teams/skypilot/skypilot-config.yaml</code> uses <code>s3://hmnd-cloud-skypilot-jobs2</code>. Treat that as infrastructure naming, not a repo path.</p></li></ul><p>Path-sensitive Terraform appears okay if the subtree root is stable:</p><ul><li><p>Terraform module sources are relative inside the repo, for example <code>source = &quot;./domains&quot;</code>, <code>source = &quot;./modules/...&quot;</code>, and <code>source = &quot;../../../modules/...&quot;</code>. These continue to work when running from <code>hmnd_cloud/infrastructure</code> or <code>hmnd_cloud/ml-infrastructure</code>.</p></li><li><p>One path crosses from <code>infrastructure</code> to sibling <code>ssh-keys</code>: <code>infrastructure/domains/reasoning/eu-west-2/main.tf</code> uses <code>${path.root}/../ssh-keys</code>. This still resolves correctly if <code>ssh-keys</code> remains at <code>hmnd_cloud/ssh-keys</code>.</p></li><li><p>Cross-region training modules reference <code>../../../../../infrastructure/modules/...</code>; this remains valid as long as the internal <code>hmnd_cloud/infrastructure</code> tree is not rearranged.</p></li></ul><p>Commit/hash usage does not look like a blocker:</p><ul><li><p>CI artifact names use <code>${{ github.sha }}</code>. In the monorepo this becomes the hmnd commit SHA, which is fine for artifacts and PR comments.</p></li><li><p><code>hmnd_deployment/pre_alpha/deployment-scripts/deploy_to_robots.py</code> has a default <code>commit='main'</code>, but I did not find a hard dependency on old <code>hmnd-cloud</code> commit SHAs.</p></li></ul><p>Existing local plan evidence is not clean yet, but the failures are credential/access related, not repo path related. The checked-in <code>infrastructure/plan.log</code> shows a previous plan ending with <code>Plan: 173 to add, 26 to change, 2 to destroy</code>, followed by missing Coder token and Kubernetes <code>Unauthorized</code> errors. The migrated CI proof should therefore be treated as the source of truth for the clean plan.</p><h2 id=\"hmnd-cloud-&gt;hmnd-Donemeans\">Done means</h2><ul><li><p><code>hmnd_cloud</code> exists in <code>hmnd</code> with <code>hmnd-cloud</code> history preserved.</p></li><li><p><code>hmnd_ci</code> detects <code>hmnd_cloud/**</code> changes.</p></li><li><p>The migrated Terraform and Packer workflows are called through <code>hmnd_ci</code>, not standalone root path filters.</p></li><li><p>A README-only PR under <code>hmnd_cloud/</code> triggers the cloud workflows and no unrelated monorepo jobs.</p></li><li><p>CI Terraform plans for <code>infrastructure</code> and all active <code>ml-infrastructure</code> backends are clean, or any non-clean output is explained as pre-existing drift/access rather than migration fallout.</p></li></ul>"
        },
        {
          "id": "1793425450",
          "title": "The Problem With Central Planning",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1793425450",
          "last_modified": "2026-04-29T15:48:20.739Z",
          "created_at": "2026-03-25T10:48:02.965Z",
          "body_html": "<h2 local-id=\"eba8f37e0afc\" id=\"TheProblemWithCentralPlanning-Summary\">Summary</h2><p local-id=\"718c60636143\"><strong>A fleet of loosely coordinated, autonomous humanoids will beat a rigid, centrally planned scheduler - not by being \u201csmarter\u201d, but by staying in motion and constantly making progress.</strong></p><p local-id=\"2153ce580aca\">Centrally planning the paths and tasks of a fleet of humanoids will result in a very brittle and fragile system.  There is no graceful failure.  With autonomous agents, individual agents may fail and degrade performance, but the fleet as a whole can continue making progress.  We are already betting these robots on local autonomy.  We are already assuming that AI will work.  We should double-down on this and also assume that we can make our robots sufficiently intelligent such that global coordination (rather than planning) is viable.</p><p local-id=\"3937d8872497\">This is aligned with how technology as a whole has been evolving for decades at this point.  Expensive vertically scaled databases have been horizontally scaled across cheap commodity devices.  Routers and application servers too.  More recently, even satellites have been hit with this trend as billion dollar geostationary satellites are replaced with fleets of cheap low-earth-orbit satellites (Starlink being the best-known with more coming).  The first reason for this is that you can get unit costs down (this is aligned with us scaling a large fleet).  The second reason is that failures become more gradual rather than abrupt - this is the point that\u2019s relevant here.</p><h2 local-id=\"74f36c3fb172\" id=\"TheProblemWithCentralPlanning-Optimal==Fragile\">Optimal == Fragile</h2><p local-id=\"da4fbb37fd11\">There\u2019s a seductive idea underneath central planning: if you can just see everything, you can assign perfectly.  Your agents can plan around other agents, predict where they will be in the future, minimize congestion and generally execute tasks at maximum throughput. <strong> It\u2019s a lie</strong>.  Not because optimization is hard or impossible (heuristics are good enough that being NP hard isn\u2019t really a meaningful problem these days), but because the thing you\u2019re optimizing against doesn\u2019t really exist. The world you model centrally is always:</p><ul local-id=\"dc1bee514b75\"><li local-id=\"e3416d4853aa\"><p local-id=\"398d2eddc740\">slightly out of date (latency is non-zero)</p></li><li local-id=\"1b2858f7027e\"><p local-id=\"58e642d0faf3\">slightly incomplete (you aren\u2019t seeing everything)</p></li><li local-id=\"0461f6912f5f\"><p local-id=\"92265dc6383f\">slightly wrong (its an abstraction of an abstraction, not reality)</p></li></ul><p local-id=\"b437d5e65d99\">This is fundamental.  For a large fleet of humanoid robots, the data exists at each robot.  Each robot is moving, sensing and reacting to its local environment.  It makes much more sense to push decision making to where the data lives, rather than trying to pull the data from multiple robots into a single \u201cbrain\u201d.</p><h2 local-id=\"5d8ab054741e\" id=\"TheProblemWithCentralPlanning-Humanoids==Hard\">Humanoids == Hard</h2><p local-id=\"a3bfd0f63e5b\">Central planning works (kind of) for AMRs because the world could be simplified:</p><ul local-id=\"8da6e049a2c0\"><li local-id=\"cf03358d80a7\"><p local-id=\"b85e5f22a69d\">flat floors and static routes</p></li><li local-id=\"e3b3bd066f6a\"><p local-id=\"cc5f5c013332\">limited actions &amp; predictable outcomes</p></li></ul><p local-id=\"fc86288093ef\">You can reduce everything to nodes and edges and call it a day.  Humanoids won\u2019t live in a graph, because the range of actions they can take in the world are far greater than an AMR.  AMRs can accept a payload and take it somewhere.  Humanoids can actually manipulate payloads end-to-end, with a number of complex failure and recovery behaviors along the way.  The actions that an AMR can take are pretty predictable.  Maybe it takes longer to load/unload - but there aren\u2019t many other possibilities.  A humanoid may have a lot of variance around the tasks it may need to perform.  Who knows how many items are in the bin, or how many times it may need to retry grasps\u2026</p><p local-id=\"8663833982e6\">The important information isn\u2019t just hard to centralize - it\u2019s not even representable in a clean way without drastically over-simplifying things.  So the planner makes a \u201cgood\u201d decision based on bad abstractions, and the robot fixes it locally anyway.</p><h2 local-id=\"62e076514c6c\" id=\"TheProblemWithCentralPlanning-Progress&gt;Perfection\">Progress &gt; Perfection</h2><p local-id=\"3b2055d0bf22\">The real goal isn\u2019t picking the \u201cbest\u201d task for any robot at any time.  It\u2019s just keeping the system moving.  A centrally planned system looks efficient only when nothing goes wrong.  But the moment anything deviates (and it always will) it stalls:</p><ul local-id=\"2d68ac4a6b5d\"><li local-id=\"cdc37021d3e3\"><p local-id=\"76501e3e70d5\">robots wait for reassignment</p></li><li local-id=\"5358c545257b\"><p local-id=\"14c2cba8de6c\">plans are repeatedly invalidated</p></li><li local-id=\"3a3df5859350\"><p local-id=\"2bc96d6c2aa3\">no guarantee that replanning results in continuous changes - lots of thrashing and inefficiency</p></li></ul><p local-id=\"d0c4606c819e\">Throughput and efficiency collapses not because robots are dumb, but because they\u2019ve given up local autonomy.  A decentralized system ensures robots can continue to make progress, even if other robots have unexpected issues.</p><ul local-id=\"69b75087e733\"><li local-id=\"0f31d66f7666\"><p local-id=\"23ae1f8d97dd\">a robot hits friction \u2192 it retries, escalates or abandons the task</p></li><li local-id=\"bfa78885cce9\"><p local-id=\"70754de49a53\">a task becomes weird \u2192 someone else picks it up later</p></li><li local-id=\"c598a0c90d63\"><p local-id=\"c9c070d1755b\">state is slightly off \u2192 it gets corrected in-line</p></li></ul><p local-id=\"409ef171d54d\">You trade perfect coordination for continuous progress, because reliability is traditionally the bigger barrier to throughput than \u2018optimality\u2019 with robotics (especially something like humanoids).  </p><h2 local-id=\"4a4bfc00da82\" id=\"TheProblemWithCentralPlanning-Robotsarethesourceoftruth\">Robots are the source of truth</h2><p local-id=\"e01e7438081b\">A core mistake is treating the center as the source of truth.  It isn\u2019t and it can\u2019t be.</p><p local-id=\"d0fc06c793e9\">Truth lives at the edge:</p><ul local-id=\"f50a3b83c4d1\"><li local-id=\"b038dbfa1d45\"><p local-id=\"2a456ba12bd8\">in the camera frame</p></li><li local-id=\"657f0d2baf9f\"><p local-id=\"4ed033ef8d2e\">in the gripper</p></li><li local-id=\"043be0c46eae\"><p local-id=\"77ffa3b25529\">in the blocked aisle</p></li><li local-id=\"5554dcb48936\"><p local-id=\"26494b60b85b\">in the thing that <em>just</em> changed</p></li></ul><p local-id=\"5948e85a32d1\">You can stream summaries of that upstream, but you can\u2019t centralize the experience of it (at least not without somehow fixing wireless networks: <a href=\"/wiki/spaces/ROBOT/pages/1052508214/Wireless+Networking+Sucks\" data-linked-resource-id=\"1052508214\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Wireless Networking Sucks</a> )</p><p local-id=\"3b0c8c6ba3cb\">So every centralized decision is made on a compressed, approximated, delayed abstraction of reality.  But local decision is made on the thing itself.</p><h2 local-id=\"c218cb771b6a\" id=\"TheProblemWithCentralPlanning-Centralplanningdoesn\u2019tsolvedeadlocks\">Central planning doesn\u2019t solve deadlocks</h2><p local-id=\"3f55ddfb7cc5\">Central planners love to claim they prevent deadlocks.  You can plan optimal route for many agents through the same map, ensuring robots never collide, congest or otherwise impede one another.  Great, right?</p><p local-id=\"9a9fb21bcfc3\">What they actually do is <strong>synchronize failure</strong>.  When the central system hesitates, everything hesitates.  When it\u2019s wrong, everything is wrong together.  One robot\u2019s pose being off (perhaps delayed due to faulty wireless) can result in the whole plan unwinding.</p><p local-id=\"42b95c8091cc\">In a decentralized system, conflicts still happen - but they stay small:</p><ul local-id=\"e1feb3215c28\"><li local-id=\"02be8531ca83\"><p local-id=\"5f8d00d96a9c\">two robots contend \u2192 one backs off</p></li><li local-id=\"f260edd6be96\"><p local-id=\"ac9760829fb0\">a path blocks \u2192 local re-route</p></li><li local-id=\"bf2d3f464c2a\"><p local-id=\"339b52e8ac37\">a resource is busy \u2192 retry later</p></li></ul><p local-id=\"f41b14c12d3d\">This friction may reduce the efficiency of one robot, but the rest of the robots can continue to make progress.</p><h2 local-id=\"208f6e182700\" id=\"TheProblemWithCentralPlanning-MotivatingExample\">Motivating Example</h2><p local-id=\"462f13b04933\">Let\u2019s consider an example where we have items that need to be moved across a warehouse.  In a traditional centrally-planned scheme, the central planner knows the battery level and the locations of all the robots and can identify the best robot for the job.  In a decentralized scheme, the coordinator doesn\u2019t \u201cassign\u201d work to individual robots - it advertises assignments on a billboard and robots are free to take these assignments.</p><p local-id=\"d4251ff7db12\">As a general rule, robots that are \u201cbetter\u201d for the assignment (closer to the source, higher charge-levels, better health) will respond more eagerly.  Robots that are \u201cworse\u201d will back-off and respond after some amount of time.  On average, this will result in the best robots being assigned the work - but unlike a central coordinator, it is much more robust to the chaos of real-world operations.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20260429-152958.png\" width=\"790\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1793425450/image-20260429-152958.png?version=1&amp;modificationDate=1777476600416&amp;cacheVersion=1&amp;api=v2&amp;width=790&amp;height=526\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1793425450/image-20260429-152958.png?version=1&amp;modificationDate=1777476600416&amp;cacheVersion=1&amp;api=v2\" data-height=\"1024\" data-width=\"1536\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1924988963\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20260429-152958.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1793425450\" data-linked-resource-container-version=\"3\" data-media-id=\"ff1b928a-60be-4c44-9c7a-b31df00588ed\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1793425450/image-20260429-152958.png?version=1&amp;modificationDate=1777476600416&amp;cacheVersion=1&amp;api=v2&amp;width=1536&amp;height=1024 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1793425450/image-20260429-152958.png?version=1&amp;modificationDate=1777476600416&amp;cacheVersion=1&amp;api=v2&amp;width=790&amp;height=526 1x\"></span><p local-id=\"ccea91c9f88d\" /><p local-id=\"a70d1c755198\">Let\u2019s re-consider the centrally-planned scheme.  The central task scheduler has the robot locations and their paths, so naturally it can find the optimal assignment to maximize throughput.  But what if the scheduler chooses a robot that\u2019s just failed or maybe was manually re-assigned concurrently?  The system will experience some sort of the thrashing as that plan times out (the robot fails to acknowledge the assignment perhaps), another choice is made, and the plan needs to be adjusted again.</p><p local-id=\"bedd8bf15b1e\">In the decentralized approach, the assumption is that eventually SOME robot will respond.  The coordinator can advertise priorities and operators can tune the eagerness depending on what factors they may care about (power, distance, priority).  The key thing is that a robot will be assigned, and other robots don\u2019t need to worry about it.  The coordinators strong consistency semantics will ensure that only the first robot to respond will actually successfully take the task.</p><p local-id=\"16c2d11336a8\">Of course, the system SHOULD allow manual assignment.  There are all sorts of reasons that someone may want to assign a specific task to a specific robot - this can be handled by roles/affinities in the advertised task (meaning only the matching robot would respond - regardless of any other facts).</p><p local-id=\"7467ad40b6a4\">In addition to this assignment problem, there are a number of other coordination challenges that can be solved similarly.  Some simple schemes can be used to break symmetry to allow multiple robots to navigate around one another or establish right-of-way.</p><h2 local-id=\"8120af074a9c\" id=\"TheProblemWithCentralPlanning-Conclusion\">Conclusion</h2><p local-id=\"0e21fb432ee0\">We are making smart robots.  We should avoid the temptation to remove autonomy from robots.  This is trading local intelligence for networking and coordination overhead - which is probably a bad trade given what I know about wireless networks.  This doesn\u2019t mean that robots don\u2019t have some level of awareness of their peers though.  Its relatively cheap to broadcast to each robot any peers within a 10m radius for example and see some historical navigation data.  The key thing is that this data would be used by the robot itself to do planning, with the robot having the ability to modify these plans on the fly as it learns new information.</p><p local-id=\"cc7dd454e4bc\">Maybe in the future the pendulum will swing the other way.   We will train a mega-VLA that takes 100s of cameras and outputs 1000s of task-space trajectories to control 100s of robots.  But for now let\u2019s build robots, not networks.</p><p local-id=\"07088153804f\" />"
        },
        {
          "id": "1619853323",
          "title": "Spec: Switchboard Coordinator",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1619853323",
          "last_modified": "2026-04-24T10:33:50.748Z",
          "created_at": "2026-02-08T13:04:14.704Z",
          "body_html": "<p local-id=\"eb6c685ed4e1\"><strong>Summary</strong>: System-3 Coordination</p><p local-id=\"282b2a8c0321\"><strong>Owner</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a></p><p local-id=\"24b2feba1503\"><strong>Date</strong>: <time datetime=\"2026-02-10\" class=\"date-past\">10 Feb 2026</time></p><p local-id=\"8c20b97f80db\"><strong>Approvers</strong>:</p><p local-id=\"3782ed10fa72\"><strong>Informed</strong>: </p><p local-id=\"9cad2bc69a65\"><strong>Related</strong>: <a href=\"/wiki/spaces/ROBOT/pages/1170341889/Spec+HMND+Fleet+Control+Plane\" data-linked-resource-id=\"1170341889\" data-linked-resource-version=\"16\" data-linked-resource-type=\"page\">Spec: HMND Fleet Control Plane</a> </p><h2 local-id=\"3110d78f0885\" id=\"Spec:SwitchboardCoordinator-ProblemDefinition\">Problem Definition</h2><p local-id=\"3d97a607e4a0\">Enabling robots, agents, operators and 3rd party systems like ERP, WMS or POS to coordinate requires some shared understanding of the world.  This model can be used to ensure only one robot attempts to fulfill a given order at a time, or that robots use shared resources like chargers efficiently.  A consistent, transactional database ensures that all agents (human or otherwise) agree on the state of the world while allowing each one to act independently.</p><p local-id=\"eebbb340f813\">Imperative models like Behavior Trees or State Machines allow for individual robots to be controlled precisely - even scripted to follow exact instructions.  At the fleet level though, these representations begin to fall apart due to the partial observability of the world and the concurrency of many robots and other simultaneous processes.</p><h2 local-id=\"a1f69776a1f9\" id=\"Spec:SwitchboardCoordinator-WhatisSwitchboard?\">What is Switchboard?</h2><p local-id=\"eee256e9151c\">Switchboard is a database that stores the state of the fleet\u2019s workflow.  It forms the backbone of <strong>System 3</strong> - where agents can coordinate about who is doing what at any point in time.  Switchboard is not a workflow optimizer, scheduler or planner.  It simply tracks workflow execution.  A perfectly conformant agent could simply execute assignments one at a time to progress perfectly through any defined workflow, but we should also expect reality to differ considerably and for events to deviate entirely from any current workflow definition.</p><h2 local-id=\"a75a9988265e\" id=\"Spec:SwitchboardCoordinator-DesignGoals\">Design Goals</h2><ul local-id=\"aead6abe7041\"><li local-id=\"0b9cab0c5f5a\"><p local-id=\"a913b64d4912\">Authoritative - changes should be serialized, recorded and audited.</p></li><li local-id=\"f1ee706bdd7b\"><p local-id=\"44234b5face6\">Consistent - because agents have side-effects, we need to prevent double-execution</p></li><li local-id=\"f3024fa81552\"><p local-id=\"a8fb8d86a1cc\">Flexible - \u201cillegal\u201d transitions should be logged regardless so that we can make workflows more complete over time</p></li><li local-id=\"8959581c6fe5\"><p local-id=\"22599141c3f4\">Simple - limited scope to workflow state</p></li><li local-id=\"21d6f2a1a2d5\"><p local-id=\"a657c8dde17f\">Scalable - should scale to hundreds or thousands of agents coordinating simultaneously across dozens of tenancies</p></li></ul><h3 local-id=\"0e0d4b2ab519\" id=\"Spec:SwitchboardCoordinator-Non-Goals\">Non-Goals</h3><ul local-id=\"d13564ccd50f\"><li local-id=\"136a32b18e0d\"><p local-id=\"d2bef03b3e72\">Inference or optimizing - leave this to operators or external agents</p></li><li local-id=\"3f316b24c57d\"><p local-id=\"4027cefb12da\">Scheduling - done externally</p></li></ul><h2 local-id=\"5da2d5744a35\" id=\"Spec:SwitchboardCoordinator-High-LevelArchitecture\">High-Level Architecture</h2><p local-id=\"88e9ed4789a7\">The Switchboard API is used by authorized agents to fire transitions, which the are recorded to the event log and used to update the marking of the current workflow state.  This workflow is encoded as a Petri net, with each row being a particular token at some place.  By breaking a Petri net into tokens as rows in a SQL database, we can transactionally update the workflow state, while enabling different agents to update different tokens concurrently, ensuring our workflow execution can scale to 10s or even 100s of thousands of tokens.  </p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"560\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1619853323/Untitled%20Diagram-1770558123165.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1619853323/Untitled%20Diagram-1770558123165.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p local-id=\"0273bae1d1bb\">The robots' system 2 agents can use Switchboard as a tool to enroll robots or determine which tasks should be executed to progress the workflow.  System 3 agents like WMS integrations (think SAP\u2019s Joule or similar) can fire transitions which create work items representing orders.  Other system 3 agents may be responsible for updating priorities (scheduling) or handling escalations.  Human operators can also use switchboard to re-task robots or recover from failure.</p><h3 local-id=\"cb2952cd5e51\" id=\"Spec:SwitchboardCoordinator-CoreModel\">Core Model</h3><p local-id=\"4b246d3d6326\">We have a few core components to manage within Switchboard:</p><ul local-id=\"4d47b408f6f4\"><li local-id=\"8d591ebf2153\"><p local-id=\"a0463f6a6e51\"><strong><span class=\"inline-comment-marker\" data-ref=\"0a7f3668-3491-42fb-aeb0-82c9ee453a50\">Tenants</span></strong> - top-level accounting used to isolate specific customers.  Ideally this is implemented with Postgres RLS as an extra layer of protection.  The assumption here is that many customers will coexist within the same Switchboard instance, but we should also expect that some customers may want their own infrastructure entirely (a good reason to use something standard like Postgres).</p></li><li local-id=\"bba34af727c6\"><p local-id=\"c5a5539ea06c\"><strong>Principles </strong>- authorization bounds within a tenancy (ensuring multiple robots or operators within a tenancy don\u2019t interfere)</p></li><li local-id=\"50ceb65b2339\"><p local-id=\"582c8ae471c6\"><strong>Definitions</strong> - immutable descriptions of workflows: states, valid tasks, work items.  New versions are appended.</p></li><li local-id=\"b5f9b2f7540c\"><p local-id=\"ea4477a04309\"><strong>Instance</strong> - logs and materialized state for a given instantiation of a particular workflow definition.  Note that any given workflow instance could include illegal events which may not adhere strictly to the current definition.</p><ul local-id=\"e670ef3f3a14\"><li local-id=\"20939e150e63\"><p local-id=\"d1a6f72e3bae\"><strong>Events</strong> - log of how the workflow has evolved over time.  Should be replay-able, though order isn\u2019t strictly serialized (concurrent events at independent places should be tolerated)</p></li><li local-id=\"8b70e6c08926\"><p local-id=\"8028c34e72fb\"><strong>Items</strong> - used to encode the materialized state of the workflow as tokens</p></li></ul></li><li local-id=\"c6bbeb8cc5db\"><p local-id=\"20aff140f248\"><strong>Leases</strong> - exclusive claims to execute tasks which may have real-world side-effects.</p></li><li local-id=\"724665194197\"><p local-id=\"78ab5d0ee52b\"><strong>Facts</strong> - mutable KV storage which allows agents to coordinate about the state of the world.  Facts have a TTL - meaning they need to be re-asserted to remain valid.</p></li></ul><h3 local-id=\"5cf28823101a\" id=\"Spec:SwitchboardCoordinator-AuthorizationModel\">Authorization Model</h3><p local-id=\"455b4c66f04b\">Switchboard clients need to be authenticated principals.  Robots may use mTLS, operators some sort of OIDC or we may start with simple pre-shared tokens.  Each principal needs to be authorized to allow some specific transitions within the workflow, including various \u201cbuilt-in\u201d transitions to support internal mechanisms like re-prioritization.</p><p local-id=\"6e818c5138fa\">Our workflow definitions can include which roles are permitted and which capabilities should be granted.  Clients do not directly manipulate events or token states: they must interact through the workflow\u2019s transitions.  In some cases, clients may be permitted to make arbitrary \u201cillegal\u201d transitions which don\u2019t fit the workflow description.</p><p local-id=\"40d015956a71\"><span class=\"inline-comment-marker\" data-ref=\"8965d57e-fa87-4ee8-88eb-0eb4e1a7fc13\">For example, some system 3 agent may be permitted to fire a \u201csource transition\u201d which introduces new order tokens into the workflow.  This agent isn\u2019t permitted to do do anything else.  A system 2 robot agent may be permitted to enroll itself, and to fire any transition involving that specific robot token (but no others).  Each token is associated with some principal (who created it), and this create_by can be used to ensure that different agents don\u2019t interfere.</span></p><h3 local-id=\"f97c584323a2\" id=\"Spec:SwitchboardCoordinator-InteractionModel\">Interaction Model</h3><p local-id=\"dd57fa9a4ae0\">Agents can fire transitions which inject new tokens marked with their created_by into the workflow.  Some agents may be able to move those tokens through the workflow (like a robot performing different actions).  These agents needs to acquire leases to actually fire those transitions with any coordination.  Robots for example should call Switchboard periodically to update the status of previous claims and to see which assignments are available.</p><p local-id=\"91a62f9bb70a\">Leases are used to track which tasks are supposedly being executed to ensure that multiple robots do not attempt to do conflicting work.  Each workflow state also has a capacity to prevent multiple robots from colliding.  So the workflow knows that if robot A is in state S1, which has a capacity 1, it cannot fire any more transitions into that state and thus will not advertise those transitions to other robots.  Even after robot A starts transitioning out of the state, we don\u2019t complete until robot A updates about the status of the lease (a claim).  There is a lot of intricacy around \u201creversing\u201d transitions here if we want to make robust workflows.</p><p local-id=\"6c386b9314ea\">When agents make claims that transitions have been executed, Switchboard will log the event, clear the lease and update the materialized state of the workflow instance.  In cases where the logged event is illegal, the marking may involve transitioning tokens to special \u201cquarantine\u201d states.</p><h3 local-id=\"88dd5e6eee2c\" id=\"Spec:SwitchboardCoordinator-PriorityandReprioritization\">Priority and Reprioritization</h3><p local-id=\"7da457163a08\">Sometimes there may be multiple transitions that are valid for any agent.  How do they determine which ones to prioritize?  A simple priority value on the tokens can help order things, and some agents may have permissions to call built-in \u201creprioritize\u201d transitions on specific states.  For example, a system 3 optimizing agent could decide to expedite a pending order (allowing some PendingOrder.Reprioritize transition) without allowing in-flight orders to be touched.  Another agent or human operator may have permission to cancel or undo in-flight orders.</p><p local-id=\"652395bce2b1\">Some tasks can be canceled (reversed) if we know the inverse.  For example, navigating from A to B is easy to reverse (navigate to A).  Picking up a tote can be reversed by placing the tote back.  Some tasks can\u2019t reasonably be canceled though (like dumping the contents of a tote into a hopper or placing a tote on a conveyor).  </p><h3 local-id=\"8e5ec72e4e87\" id=\"Spec:SwitchboardCoordinator-ConformanceandDeviation\">Conformance and Deviation</h3><p local-id=\"39783bab1579\">At any time, we can run events through a workflow definition and keep track of how many follow legal transitions vs illegal transitions.  We can use the ratio here as a simple conformance metric.  If workflow conformance falls too low, we can trigger some external agent to look at the event log to propose a new workflow definition.</p><p local-id=\"8cd5b575b70a\">New workflow definitions are published as new versions. Instances migrate explicitly via recorded actions. When structure changes invalidate existing state, unmapped tokens move to quarantine rather than disappearing. Workflow regeneration is advisory: inference proposes, humans approve, and new definitions are published.</p><p local-id=\"19962bd66b9d\">Human operators (or some system 3 agent) can move quarantined tokens to the correct states after the migration.</p><h2 local-id=\"d2abed4a845f\" id=\"Spec:SwitchboardCoordinator-Summary\">Summary</h2><p local-id=\"d46593897c22\">Switchboard is a single authority that records what agents do, prevents them from stepping on each other, and preserves execution reality so workflows can evolve without forgetting what actually happened.</p><h2 local-id=\"52fbe465e1a3\" id=\"Spec:SwitchboardCoordinator-Milestones\">Milestones</h2><p local-id=\"724503a2fe46\">M0. In-memory POC (what we have for MF/Bosch/Robotstore)</p><p local-id=\"2804a498ed92\">M1. SQL database + stateless API</p><p local-id=\"c4404d1c5810\">M2. Simple authz model and multi-tenancy </p><p local-id=\"465efe6662fe\">M3. Conformance</p><h1 local-id=\"636e2df40ce2\" id=\"Spec:SwitchboardCoordinator-Appendix\">Appendix</h1><h2 local-id=\"f8147ec8765d\" id=\"Spec:SwitchboardCoordinator-AppendixA:APIsurfaceandactionschemas\">Appendix A: API surface and action schemas</h2><p local-id=\"5632b08a13be\">For the Switchboard API, we\u2019ll do a simple REST interface.  The big benefit of something like REST is that we can easily cache, load balance, etc - but also its just much simpler for 3rd parties to integrate (in comparison to gRPC or something like that).</p><p local-id=\"f838a7b9ed0f\"><strong>Managing Definitions</strong></p><p local-id=\"4828c97bf8b9\">One of the simpler interactions with switchboard should be to POST new workflow definitions, and to PUT new versions of workflows.  Some care needed at the API to make sure versions increment safely.  For example, PUT should include the old version so that if something has changed in the meantime we get a conflict.</p><p local-id=\"cda07034035e\">The workflow definition is a YAML document (for now) describing the various types of workflow items, states, transitions and even principals that may attempt to access the workflow.  We should assume that the API layer will validate these definitions before writing them to the database.</p><p local-id=\"3c963c35a59b\">So a simple CRUD, with some additional complexity around the versioning to ensure things are consistent.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"92014ede-a07e-4f02-99cb-5358cd969e7d\" data-local-id=\"e3f7285dcd51\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">POST /v1/tenants/$tenant/workflows\nPUT /v1/tenants/$tenant/workflows/$id?from=$old_version\nGET /v1/tenants/$tenant/workflows/$id?version=$version\nDELETE /v1/tenants/$tenant/workflows/$id?version=$version</pre>\n</div></div><p local-id=\"36e38107f451\">The WorkflowDefinition resource:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"75d339fb-7b22-458f-8ce8-142d48a7fa2a\" data-local-id=\"f19944909a28\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">tenant_id: str\nworkflow_id: uuidv7\nversion: int\nname: str\ndescription: str\ndefinition: str        # a blob\n\ncreated_at: datetime\ndeleted_at: datetime   # tombstone\ncreated_by: str        # how much authz do we do here?\nmetadata: JSON blob</pre>\n</div></div><p local-id=\"8565491524b8\" /><p local-id=\"b05555c3b9e3\"><strong>Managing Instances</strong></p><p local-id=\"46000f9a2eb8\">In addition to workflow definitions, we also have specific INSTANCES of those workflows.  For any workflow definition, we may have a number of independent instances (think testing, simulation, or physical twins).  While versioning of the workflow definitions is relatively simple, versioning a running instance is much more challenging its a living thing.</p><p local-id=\"d2e7aa03efbe\">To simplify the API, we won\u2019t nest the workflow instances under the workflows above. </p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"fee5c8f4-adca-49b5-84c6-bae431513ed7\" data-local-id=\"7019170547ae\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">POST /v1/tenants/$tenant/instances\nGET /v1/tenants/$tenant/instances/$id?...\nDELETE /v1/tenants/$tenant/instances/$id</pre>\n</div></div><p local-id=\"1bbae37fd0d6\">We can create a new instance of a workflow (given some definition/version) easily enough.  We can also retrieve the workflow state.  This effectively returns the current marking (all the tokens) of the workflow.   This can be filtered down a bit.  The workflow can also be deleted.</p><p local-id=\"5f5afc27aa95\">Unlike definitions, workflow instances are sharded over many rows, which enables many robots to update concurrently without stressing our database out (even a relatively small fleet could cause issues with a SQL database if there are lots of conflicting rows).  This isn\u2019t what\u2019s exposed via the API though.   To update a workflow, we must fire a transition - and to accommodate real-world side effects we must do this using leases and claims:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"339cb9eb-5608-4aea-aa2e-11f9293e88e7\" data-local-id=\"365a207cf84c\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">POST /v1/tenants/$tenant/instances/$id/work</pre>\n</div></div><p local-id=\"a21e3a6afd96\">This is a more complicated API, and not strictly very RESTful.  The reasoning is we want to keep things effortless transactional for the clients.  So when we update Switchboard, we\u2019ll provide facts, leases or and/or claims:</p><p local-id=\"babe3b2e04e2\"><strong>Facts</strong> - mutable facts about the world.  These are things that evolve faster than our workflow, and can be used to guard transitions.  For example, we may not want to allow a robot to attempt to pickup a tote unless its nearby (pose) or we may want a robot to navigate to a battery swap if its battery is too low.</p><p local-id=\"b166906de420\"><strong>Leases </strong>- exclusive rights to perform a transition with side-effects.  This is how we avoid sending multiple robots down the same corridor or to pick up the same tote or trigger the same async business process via some baroque ERP system.</p><p local-id=\"fc24da840526\"><strong>Claims </strong>- status of any tasks performed.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"7b41ce34-2908-4545-9099-698f81f5b18b\" data-local-id=\"9a2787f2d85c\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">facts:\n  pose: {x: 0, y: 12}\n  battery: 0.3\nleases: \n  - task: PickTote\n    id: &lt;leasing id&gt;\n    result: success\n    ... more context about our lease\nclaims: \n  - task: PickTote\n    id: &lt;leasing id&gt;\n    result: success\n    ... more context about completed task</pre>\n</div></div><p local-id=\"c0a097ced65e\">So a robot for example may update its pose or battery state periodically, and when executing long-running tasks (like policy or navigation) it may need to update the lease to keep it alive so that Switchboard doesn\u2019t hand it out to someone else.</p><p local-id=\"151f7e3d5b22\">When Switchboard sees something like the above, it will log the event for the incoming facts, claims or lease extension and then fire any claimed transitions (in this case, firing the PickTote transition).  Switchboard can then evaluate what transitions could fire next (eligible) and hand out leases.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"adfd57ea-69e8-4ccb-ab93-0779789ab5e8\" data-local-id=\"5a3d2732cf9a\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">leases:\n  - task: NavigateToTable\n    id: &lt;leasing id&gt;\n    ... additional context\n... other leases </pre>\n</div></div><p local-id=\"273d77c8e530\">The robot\u2019s system 2 agent in this case can evaluate the options (or use some sort of priority scheme) to decide which lease to hold.  Leases have a time-to-live (TTL) that\u2019s relatively short, and so expire quickly.  In this case, let\u2019s assume that the robot is going to navigate to the table, which takes longer than the TTL.  The robot should simply call the work endpoint repeatedly (with new facts) refreshing this lease.  Its possible that we could estimate how long it should take and extend the TTL more precisely but this isn\u2019t strictly necessary.</p><p local-id=\"485c67537d0f\">At some point the task is completed, in which case we also make a claim that will any transitions within Switchboard and move to the next task.  Note that its possible that a robot could claim success for ANY tasks - not necessarily those leased (think exceptional cases or human intervention).  </p><p local-id=\"31ff47de305d\"><strong>Other Work</strong></p><p local-id=\"6a1c21efd64c\">In addition to robot\u2019s leasing/completing work and updating facts, we should expect other services or agents in system 3 to participate here.  A WMS for example may need to add orders to the queue for fulfillment.  In this case, the WMS can immediately claim a task completed (\u201cNewOrder\u201d for example), without worrying about leasing semantics since everything is instantaneous.</p><p local-id=\"8b8f85f953e3\">More advanced workflows may require some long-running asynchronous work at System 3 though - such as handling interventions.  In this case, some agent capable of handling interventions (or a human operator) will poll the work and see new leases show up which can then be acted on, much the same way as robots operate.</p><h2 local-id=\"dbffa5f60f44\" id=\"Spec:SwitchboardCoordinator-AppendixB:Authorizationmechanicsandcapabilitymodel\">Appendix B: Authorization mechanics and capability model</h2><p local-id=\"37f972a7d173\">Any incoming requests to Switchboard need to be authenticated (who is accessing) and authorized (what can they do).  We\u2019ll consider two possible schemes to start: mTLS (for robots/service-to-service) and JWT (for humans/external systems).  mTLS will be terminated at some load balancer and the various claims within the certificate will be lifted into the header, and so we will look here at a more abstract authorization model where we assume that incoming requests have some sort of subject_id (who is the principal making the request) along with what capabilities they have.</p><p local-id=\"64e8c59edb85\"><strong>Principals and Tokens</strong></p><p local-id=\"c9ea8e7d5090\">Some principals actually are represented by tokens in the Petri net, like a robot for example.  Other principals (like human operators) have no such representation internally.  Both of these scenarios are relevant for authorization.</p><p local-id=\"4de99284afeb\">We define roles in our workflow definition - so we know for example what a robot is or what a WMS is and which transitions can be fired.  </p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"23a57df5-3822-47f7-b8c3-22324d3dcd7b\" data-local-id=\"507e6333b136\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">roles:\n- name: robot\n  capabilities: [*, EnrollRobot]\n  subject_binding: self\n- name: wms\n  capabilities: [NewOrder]\n  subject_binding: none\n\n... rest of definition</pre>\n</div></div><p local-id=\"777b660523b4\">In this simple example, we define a robot role, which can fire any robot-involved transition (meaning only tokens bound to that subject), along with a wms role which is only permitted to fire the NewOrder transition (though it has no binding).</p><p local-id=\"879b4ffddd82\">To support this, our token schema needs to track some sort of (optional) principal/subject_id.  In the above example, a new robot should be able to fire the EnrollRobot on startup to \u201cinject\u201d a token containing the robot\u2019s subject_id into some idle state, after which the robot is authorized to transition freely as long as it involves that token. </p><p local-id=\"b3cf7628c296\"><strong>Workflow Definitions</strong></p><p local-id=\"51adb867da37\">For completeness, we have another layer of authorization outside of the workflow at the tenancy level.  Operators or system 3 agents may have access here to modify workflow definitions over time.</p><h2 local-id=\"7130c56bf4fa\" id=\"Spec:SwitchboardCoordinator-AppendixC:Datamodelandstoragelayout\">Appendix C: Data model and storage layout</h2><p local-id=\"06897396049d\">Our core SQL schema involves three tables: definitions, events and markings.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"587\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1619853323/Untitled%20Diagram-1770639976528.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1619853323/Untitled%20Diagram-1770639976528.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p local-id=\"f790160455c6\"><strong>Definitions</strong></p><p local-id=\"a202bef4e0e4\">Workflow definitions are written as immutable blobs (YAML-formatted right now), with versioning so that workflows can evolve over time.  Creating a new workflow inserts a new row with a new workflow ID at version 0.  Updating a workflow keeps the same ID and increments the version.</p><p local-id=\"c2d389e001cc\">Its not expected that the schema needs to see \u201cinside\u201d the definition itself (like JSONB) since we won\u2019t be strictly validating that events or markings adhere to the definition.</p><p local-id=\"933610aa5c04\"><strong>Events</strong></p><p local-id=\"a4fcbf0599ed\">As clients fire transitions via the Switchboard API, events are appended to the table - referencing the current version of the workflow.  This ensures that over time we can replay the events (and any workflow definition updates) to test for conformance or to simulate the workflow.</p><p local-id=\"086a8fdb663d\">Events will include information about the source and destination states, the action taken and any tokens involved.</p><p local-id=\"4c6b359d4b59\"><strong>Marking</strong></p><p local-id=\"dbae54ec28e2\">As the events are written, we can update the current state of the workflow in the marking table.  This is almost a materialized view of a given workflow instance.  It should be possible to recreate the marking table at any time by replaying the events.</p><p local-id=\"77ce5eabe009\">Markings ought to be indexed so that we can quickly locate a token.  The expectation is that our API will load the marking and the workflow definition into RAM when needed and compute any Petri updates there - rather than trying to do this work directly in SQL.</p><p local-id=\"db19e8c33143\"><strong>Leases</strong></p><p local-id=\"6d0ce477963e\">New table?  Or is this just in the marking?  We could \u201cacquire\u201d the lease in the marking table for some input token?  Probably cleaner to have a small table tracking outstanding leases - assume explicit for now.</p><p local-id=\"d8d6fb0c0678\"><strong>Facts</strong></p><p local-id=\"9fd86fe951ce\">Just KV storage in SQL.  Easy.</p><h2 local-id=\"01274f9237c0\" id=\"Spec:SwitchboardCoordinator-AppendixD:Examplerobotenrollmentandacquire-workloop\"><br/>Appendix D: Example robot enrollment and acquire-work loop</h2><h2 local-id=\"6fff46e482c2\" id=\"Spec:SwitchboardCoordinator-AppendixE:Examplereprioritizationandpreemptionflows\"><br/>Appendix E: Example reprioritization and preemption flows</h2><p local-id=\"433a98d008fc\">Here we can show:</p><ul local-id=\"ae3e8fed82c3\"><li local-id=\"abe5211c54a0\"><p local-id=\"2f6d7bff35af\">using built-in transitions to re-prioritize work on the petri net</p></li><li local-id=\"efa1e228f9e6\"><p local-id=\"aa7aa92ebd41\">canceling work</p></li><li local-id=\"571124034d14\"><p local-id=\"b6c4f35aef98\">reversing tasks (if its reversible)</p></li></ul><p local-id=\"aff8eddd3345\" />"
        },
        {
          "id": "1636827169",
          "title": "SSH Bastion",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1636827169",
          "last_modified": "2026-04-14T13:07:12.123Z",
          "created_at": "2026-02-12T13:58:33.980Z",
          "body_html": "<h2 id=\"SSHBastion-Status\">Status</h2><p>This page replaces the earlier Teleport-based proposal.</p><p>We did not proceed with Teleport because the required OIDC-based human login flow is gated behind Teleport Enterprise. The current MVP architecture keeps human identity in Cognito/OIDC through Backbone and uses a simple bastion transport proxy instead.</p><h2 id=\"SSHBastion-Purpose\">Purpose</h2><p>This document describes the current SSH access design for HMND.</p><p>The goals are:</p><ul><li><p>Device identity is anchored in Backbone mTLS.</p></li><li><p>Human identity is anchored in Cognito/OIDC through Backbone.</p></li><li><p>Bastion acts as a transport and policy enforcement point, not as a human IdP.</p></li><li><p>Human operators use normal <code>ssh</code> ergonomics.</p></li><li><p>The client-side helper is portable across macOS and Linux.</p></li><li><p>The robot side is handled by the existing <code>hmnd-backboned</code> package.</p></li></ul><p>This is the current MVP architecture. It intentionally prefers a simple, reliable path over a fully general SSH access platform.</p><h2 id=\"SSHBastion-High-LevelModel\">High-Level Model</h2><p>There are three planes:</p><ol start=\"1\"><li><p>Control plane: Backbone</p></li><li><p>Data plane: bastion proxy + device tunnel</p></li><li><p>Endpoint auth: robot <code>sshd</code></p></li></ol><p>Backbone is responsible for authenticating and authorizing both sides:</p><ul><li><p>devices authenticate to Backbone with mTLS</p></li><li><p>humans authenticate to Backbone with Cognito/OIDC</p></li></ul><p>Backbone does not terminate the final SSH session.</p><p>Instead, the bastion exposes a byte-stream proxy over WSS on <code>443</code>, and the client uses that path as an OpenSSH <code>ProxyCommand</code>. This makes the human side feel like native SSH.</p><h2 id=\"SSHBastion-End-to-EndFlow\">End-to-End Flow</h2><h3 id=\"SSHBastion-DeviceSide\">Device Side</h3><ol start=\"1\"><li><p>The robot is enrolled into Backbone.</p></li><li><p><code>hmnd-backboned</code> authenticates to Backbone using its device certificate.</p></li><li><p><code>hmnd-backboned</code> fetches <code>ssh.bootstrap.json</code> from:</p><ul><li><p><code>GET /v1/devices/{device_id}/ssh/bootstrap</code></p></li></ul></li><li><p>The bootstrap payload contains the information needed for the device tunnel:</p><ul><li><p>device tunnel WSS URL</p></li><li><p>device tunnel session endpoint</p></li><li><p>bastion proxy TLS cert for pinning</p></li><li><p>robot login name</p></li></ul></li><li><p><code>hmnd-bastion-tunneld</code> calls:</p><ul><li><p><code>POST /v1/devices/{device_id}/ssh/tunnel-session</code></p></li></ul></li><li><p>Backbone issues a short-lived device tunnel token bound to that device.</p></li><li><p><code>hmnd-bastion-tunneld</code> uses that token to keep a WSS device tunnel up to the bastion.</p></li><li><p>When a human attaches, the tunnel daemon connects locally to <code>127.0.0.1:22</code> and bridges raw SSH bytes.</p></li><li><p><code>hmnd-backboned</code> reports SSH readiness and host key metadata in its session heartbeat.</p></li></ol><h3 id=\"SSHBastion-HumanSide\">Human Side</h3><ol start=\"1\"><li><p>The human runs either:</p><ul><li><p><code>ssh aw8-orin</code> with <code>ProxyCommand</code> configured, or</p></li><li><p>the helper directly: <code>hmnd-ssh aw8-orin</code></p></li></ul></li><li><p><code>hmnd-ssh</code> checks for a cached Cognito ID token.</p></li><li><p>If needed, <code>hmnd-ssh</code> opens the Cognito Hosted UI in the browser and captures the callback locally.</p></li><li><p><code>hmnd-ssh</code> calls Backbone:</p><ul><li><p><code>POST /v1/ssh/session/{device_id}</code></p></li></ul></li><li><p>Backbone verifies:</p><ul><li><p>valid human identity</p></li><li><p>operator/admin authorization</p></li><li><p>device exists</p></li><li><p>device heartbeat is fresh</p></li><li><p>device SSH metadata is internally consistent</p></li><li><p>device tunnel is ready</p></li></ul></li><li><p>Backbone returns:</p><ul><li><p>a short-lived bastion proxy session token</p></li><li><p>the bastion WSS URL</p></li><li><p>the host alias for the target device</p></li><li><p>a known_hosts line for the robot host key</p></li><li><p>the bastion proxy TLS certificate for pinning</p></li></ul></li><li><p><code>hmnd-ssh</code> writes the known_hosts line into the local cache.</p></li><li><p><code>hmnd-ssh</code> opens a WSS connection to the bastion and bridges stdin/stdout.</p></li><li><p>Local OpenSSH talks end-to-end to the robot <code>sshd</code> over that stream.</p></li><li><p>The robot handles box-local SSH auth.</p></li></ol><p>For MVP, the robot may still use its existing password or public key auth policy.</p><h2 id=\"SSHBastion-TrustBoundaries\">Trust Boundaries</h2><h3 id=\"SSHBastion-DeviceIdentity\">Device Identity</h3><p>Device identity is real and anchored in Backbone mTLS.</p><p>The robot must present a valid Backbone-issued device certificate to call device-scoped endpoints.</p><p>This is the mechanism that allows the device to retrieve SSH bootstrap data and short-lived device tunnel sessions.</p><h3 id=\"SSHBastion-HumanIdentity\">Human Identity</h3><p>Human identity is real and anchored in Cognito/OIDC.</p><p>The bastion does not talk to Cognito directly.</p><p>Backbone is the policy engine for humans. It converts a valid Cognito-authenticated human request into a short-lived, device-scoped session token for the bastion proxy.</p><h3 id=\"SSHBastion-BastionTrust\">Bastion Trust</h3><p>The bastion trusts only Backbone-issued short-lived session tokens.</p><p>It does not independently decide who a human or device is. It only validates that Backbone already authorized the session.</p><h3 id=\"SSHBastion-RobotSSHAuth\">Robot SSH Auth</h3><p>The robot remains the final SSH server.</p><p>That means:</p><ul><li><p>host key verification is against the robot host key, not the bastion host key</p></li><li><p>SSH auth methods offered by the robot are the ones the client sees</p></li><li><p>if the robot only offers <code>publickey</code>, the client will see <code>publickey</code></p></li><li><p>if the robot allows password auth, the user will get a password prompt from the robot</p></li></ul><p>This is why the design behaves like native SSH rather than like a remote shell product.</p><h2 id=\"SSHBastion-WhyTheBastionIsATransportProxy\">Why The Bastion Is A Transport Proxy</h2><p>The bastion is not the SSH server the human authenticates to.</p><p>Instead, the bastion proxies raw SSH bytes between:</p><ul><li><p>the human client on one side</p></li><li><p>the robot's reverse-tunneled socket on the other side</p></li></ul><p>That gives three concrete benefits:</p><ol start=\"1\"><li><p>Native OpenSSH ergonomics</p><ul><li><p><code>ssh</code>, <code>scp</code>, <code>rsync</code>, <code>sftp</code> can use the same transport model later</p></li></ul></li><li><p>Human auth stays centralized in Backbone</p></li><li><p>The bastion remains simple and policy-limited</p></li></ol><h2 id=\"SSHBastion-Components\">Components</h2><h2 id=\"SSHBastion-BackboneService\">Backbone Service</h2><p>Backbone owns:</p><ul><li><p>device bootstrap endpoint</p></li><li><p>device tunnel session endpoint</p></li><li><p>human session endpoint</p></li><li><p>human authorization</p></li><li><p>SSH readiness evaluation</p></li><li><p>robot host key publication</p></li></ul><p>Relevant runtime settings include:</p><ul><li><p><code>BACKBONE_SSH_BASTION_HOST</code></p></li><li><p><code>BACKBONE_SSH_ROBOT_LOGIN</code></p></li><li><p><code>BACKBONE_SSH_PROXY_PUBLIC_URL</code></p></li><li><p><code>BACKBONE_SSH_PROXY_TLS_CERT_PEM</code></p></li><li><p><code>BACKBONE_SSH_PROXY_SHARED_SECRET</code></p></li><li><p><code>BACKBONE_SSH_PROXY_AUDIENCE</code></p></li><li><p><code>BACKBONE_SSH_DEVICE_TUNNEL_AUDIENCE</code></p></li><li><p><code>BACKBONE_SSH_PROXY_ISSUER</code></p></li><li><p><code>BACKBONE_SSH_PROXY_SESSION_TTL_SECONDS</code></p></li><li><p><code>BACKBONE_SSH_DEVICE_TUNNEL_SESSION_TTL_SECONDS</code></p></li><li><p><code>BACKBONE_SSH_HOST_ALIAS_PREFIX</code></p></li></ul><h2 id=\"SSHBastion-hmnd-backboned\">hmnd-backboned</h2><p><code>hmnd-backboned</code> is the robot-facing Backbone daemon.</p><p>It now owns the robot-side SSH flow at the package/install level.</p><p>Responsibilities:</p><ul><li><p>load enrollment artifacts</p></li><li><p>authenticate to Backbone using device mTLS</p></li><li><p>heartbeat session data to Backbone</p></li><li><p>fetch <code>ssh.bootstrap.json</code></p></li><li><p>inspect local SSH service state</p></li><li><p>publish host key metadata</p></li><li><p>ensure the reverse tunnel helper is installed/enabled via packaging</p></li><li><p>read tunnel status emitted by <code>hmnd-bastion-tunneld</code></p></li></ul><p>The installed package also enables/restarts <code>hmnd-bastion-tunneld.service</code>.</p><h2 id=\"SSHBastion-hmnd-bastion-tunneld\">hmnd-bastion-tunneld</h2><p><code>hmnd-bastion-tunneld</code> keeps the device tunnel alive.</p><p>Responsibilities:</p><ul><li><p>read <code>ssh.bootstrap.json</code></p></li><li><p>prepare tunnel runtime assets</p></li><li><p>fetch short-lived device tunnel sessions from Backbone using device mTLS</p></li><li><p>establish the WSS device tunnel to the bastion</p></li><li><p>bridge bastion traffic to local robot <code>sshd</code></p></li></ul><p>This helper is still a separate service/process, but it is part of the robot-side SSH behavior managed by the <code>hmnd-backboned</code> package path.</p><h2 id=\"SSHBastion-BastionStack\">Bastion Stack</h2><p>The bastion stack provisions:</p><ul><li><p>an EC2 host</p></li><li><p>an Elastic IP</p></li><li><p>Route53 DNS</p></li><li><p>a WSS proxy daemon on <code>443</code></p></li><li><p>a pinned TLS certificate for the proxy</p></li><li><p>a shared secret used to validate Backbone-issued session tokens</p></li></ul><p>The bastion proxy daemon:</p><ul><li><p>accepts WSS connections</p></li><li><p>validates Backbone-issued bearer tokens for both humans and devices</p></li><li><p>maintains the live registry of connected device tunnels</p></li><li><p>attaches a human proxy session to the authorized <code>device_id</code></p></li><li><p>relays bytes between the human websocket and the device tunnel</p></li></ul><h2 id=\"SSHBastion-hmnd-ssh\">hmnd-ssh</h2><p><code>hmnd-ssh</code> is the portable human-side helper.</p><p>It is a standalone uv script with an executable shebang:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"41786f7c-5a3a-4eda-8010-9765910fe8bb\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: text; gutter: false; theme: Confluence\" data-theme=\"Confluence\">#!/usr/bin/env -S uv run --script</pre>\n</div></div><p>That means either of these are valid:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"c4842058-4823-4090-995f-fdc62ab85755\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">/abs/path/to/hmnd_services/backbone/scripts/hmnd-ssh aw8-orin</pre>\n</div></div><p>or</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"a1faa389-bc25-4138-9900-8f4a626bcb30\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">uv run --script hmnd_services/backbone/scripts/hmnd-ssh aw8-orin</pre>\n</div></div><p>Current modes:</p><ul><li><p><code>hmnd-ssh &lt;ssh-alias&gt;</code></p></li><li><p><code>hmnd-ssh login</code></p></li><li><p><code>hmnd-ssh logout</code></p></li><li><p><code>hmnd-ssh proxy %h %p</code></p></li></ul><p>Responsibilities:</p><ul><li><p>browser OIDC login if needed</p></li><li><p>local token caching</p></li><li><p>request a short-lived session from Backbone</p></li><li><p>write robot host key entries into local known_hosts cache</p></li><li><p>open the WSS proxy session</p></li><li><p>act as <code>ProxyCommand</code> transport for OpenSSH</p></li></ul><h2 id=\"SSHBastion-CurrentUserExperience\">Current User Experience</h2><h3 id=\"SSHBastion-RecommendedNativeSSHFlow\">Recommended Native SSH Flow</h3><p>Run the one-time setup:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"53b2c146-edb6-474d-807d-37ba9025ad63\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">cd hmnd_robot\npixi run setup_ssh</pre>\n</div></div><p>or from the repo root:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"0c9afc77-1f86-498b-83cc-d9e6f45083af\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">pixi run -e ssh setup_ssh</pre>\n</div></div><p>That:</p><ul><li><p>installs <code>hmnd-ssh</code> to <code>~/.local/bin/hmnd-ssh</code></p></li><li><p>creates or updates a managed block in <code>~/.ssh/config</code></p></li><li><p>makes reruns idempotent by replacing only the HMND-managed block</p></li></ul><p>The installed SSH stanza looks like:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"2e686bad-b487-45e0-8487-83955ccbdd64\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">Host aw* ab* sp* ot*\n  User hmnd\n  ProxyCommand ~/.local/bin/hmnd-ssh proxy %h %p\n  UserKnownHostsFile ~/.cache/hmnd/ssh/known_hosts\n  StrictHostKeyChecking yes\n  ServerAliveInterval 240</pre>\n</div></div><p>Then connect with:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"082383b5-16e0-49ec-ade5-d7092bbdb4d3\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">ssh aw8-orin</pre>\n</div></div><h3 id=\"SSHBastion-DirectHelperFlow\">Direct Helper Flow</h3><p>If the SSH config is not installed yet:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"32824931-ba79-4eb3-a3b2-ab031643c72d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">/ABS/PATH/TO/hmnd_services/backbone/scripts/hmnd-ssh aw8-orin</pre>\n</div></div><p>For local testing where the target login user is not <code>hmnd</code>:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"f5e32c27-1ec2-4010-b11e-425cb21196d2\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">/ABS/PATH/TO/hmnd_services/backbone/scripts/hmnd-ssh aw8-orin --ssh-user &lt;local-user&gt;</pre>\n</div></div><h2 id=\"SSHBastion-CurrentMVPLimits\">Current MVP Limits</h2><p>These are intentional for now:</p><ul><li><p>the robot may still use legacy password auth or manually-managed public keys</p></li><li><p>the bastion proxy TLS cert is pinned and self-signed, not ACM-integrated product polish</p></li><li><p><code>ssh://</code> launch links are best-effort and depend on local terminal / OS URL-handler support</p></li><li><p>terminal fidelity depends on client/server TERM support</p></li><li><p>audit is strongest at Backbone/bastion level; robot-local shell identity may still be a shared local account depending on the box configuration</p></li></ul><h2 id=\"SSHBastion-HostKeyVerification\">Host Key Verification</h2><p>The host key the human client verifies is the robot host key.</p><p>This is critical.</p><p>Because the bastion is only transporting bytes, the client should not pin the bastion SSH host key for the final shell session.</p><p>Instead:</p><ol start=\"1\"><li><p><code>hmnd-backboned</code> reads the robot host public key</p></li><li><p>Backbone publishes that key through the SSH session API</p></li><li><p><code>hmnd-ssh</code> writes that line into <code>~/.cache/hmnd/ssh/known_hosts</code></p></li><li><p>local OpenSSH verifies the robot host key normally</p></li></ol><p>This is why debug logs show the target alias host key coming from the cache populated by <code>hmnd-ssh</code>.</p><h2 id=\"SSHBastion-TestingModel\">Testing Model</h2><h3 id=\"SSHBastion-Local/ProofVM\">Local / Proof VM</h3><p>A proof VM is sufficient if:</p><ul><li><p>it is enrolled into Backbone</p></li><li><p><code>hmnd-backboned</code> is running</p></li><li><p><code>hmnd-bastion-tunneld</code> is running</p></li><li><p>the VM can maintain the device tunnel</p></li><li><p>the VM runs <code>sshd</code></p></li></ul><p>If the proof VM does not use the real robot login name, override the SSH user locally.</p><h3 id=\"SSHBastion-TypicalTestSequence\">Typical Test Sequence</h3><ol start=\"1\"><li><p>Build and install the updated <code>hmnd-backboned</code> package on the VM.</p></li><li><p>Restart <code>hmnd-backboned.service</code> and <code>hmnd-bastion-tunneld.service</code>.</p></li><li><p>Confirm <code>ssh.bootstrap.json</code> exists.</p></li><li><p>Publish and deploy the updated Backbone container.</p></li><li><p>Apply Terraform for the bastion/backbone changes.</p></li><li><p>Add the <code>~/.ssh/config</code> stanza locally.</p></li><li><p>Run:</p></li></ol><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"233f39bb-ce45-4e59-9a8f-96c0bc77b064\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">ssh aw8-orin</pre>\n</div></div><p>Expected result:</p><ul><li><p>browser OIDC login if no cached token exists</p></li><li><p>successful host key verification</p></li><li><p>shell prompt from the robot VM</p></li></ul><h3 id=\"SSHBastion-DebuggingExpectations\">Debugging Expectations</h3><p>If SSH reaches the robot, debug logs will show:</p><ul><li><p>the robot OpenSSH banner, not the bastion</p></li><li><p>the robot OpenSSH banner, not the bastion</p></li><li><p>the robot host key matching the cached alias</p></li><li><p>the robot's offered auth methods</p></li></ul><p>If the auth methods say only <code>publickey</code>, that is a robot-side SSH policy issue, not a bastion issue.</p><h2 id=\"SSHBastion-WhyThisDesignWasChosen\">Why This Design Was Chosen</h2><p>This design intentionally avoids pushing human OIDC auth into the bastion and avoids requiring Teleport or paid SSO features.</p><p>It gives:</p><ul><li><p>strong device identity via mTLS</p></li><li><p>strong human identity via Cognito/OIDC</p></li><li><p>native SSH ergonomics</p></li><li><p>minimal operator-side dependencies</p></li><li><p>simple bastion responsibilities</p></li></ul><p>It also keeps the architecture evolvable.</p><p>Later improvements could include:</p><ul><li><p>automatic SSH config installation</p></li><li><p>better terminal capability handling</p></li><li><p>stronger robot-local per-user SSH identity</p></li><li><p>session recording or richer audit</p></li><li><p>more productized packaging for operator machines</p></li></ul><h2 id=\"SSHBastion-Summary\">Summary</h2><p>The current SSH system works like this:</p><ul><li><p>Backbone authenticates devices with mTLS</p></li><li><p>robots fetch device tunnel bootstrap data from Backbone</p></li><li><p>robots fetch short-lived device tunnel session tokens from Backbone</p></li><li><p>robots maintain WSS device tunnels to the bastion</p></li><li><p>humans authenticate to Backbone via Cognito/OIDC</p></li><li><p>Backbone mints short-lived human proxy session tokens</p></li><li><p><code>hmnd-ssh</code> uses that session to act as an OpenSSH <code>ProxyCommand</code></p></li><li><p>local OpenSSH talks end-to-end to the robot <code>sshd</code></p></li><li><p>the robot remains the final SSH server</p></li></ul><p>There is no shared device bastion key in this design.</p><ul><li><p>no bastion SSH listener required for robot tunnels</p></li></ul><h2 id=\"SSHBastion-WhyThisIsBetterThanDevice-SideSSHTunnelCerts\">Why This Is Better Than Device-Side SSH Tunnel Certs</h2><p>A device-side SSH user cert would be a big improvement over the current shared key, but it still leaves an awkward server-side authorization problem:</p><ul><li><p>the device would still be using OpenSSH remote forwarding</p></li><li><p>the client chooses the remote unix socket path</p></li><li><p>we would still need a strong way to guarantee that a device can only bind its own socket path and not another device's path</p></li></ul><p>That can be solved, but it pushes us into extra bastion-side complexity such as per-device users, per-device filesystem isolation, or awkward sshd policy tricks.</p><p>Since nothing is deployed yet, the cleaner move is to remove that entire class of problem instead of hardening around it.</p><p>A custom device tunnel over WSS lets the bastion bind:</p><ul><li><p>device identity</p></li><li><p>active tunnel connection</p></li><li><p>target device socket/stream registration</p></li></ul><p>all in one place, with no shared private key and no remote-forward path ambiguity.</p><h2 id=\"SSHBastion-ImplementationNotes\">Implementation Notes</h2><p>The current implementation matches the design above:</p><ul><li><p>Backbone exposes:</p><ul><li><p><code>GET /v1/devices/{device_id}/ssh/bootstrap</code></p></li><li><p><code>POST /v1/devices/{device_id}/ssh/tunnel-session</code></p></li><li><p><code>POST /v1/ssh/session/{device_id}</code></p></li></ul></li><li><p><code>hmnd-backboned</code> fetches the bootstrap payload and publishes host key plus tunnel readiness metadata.</p></li><li><p><code>hmnd-bastion-tunneld</code> fetches a short-lived device tunnel token using device mTLS, then keeps a WSS device tunnel alive with reconnect/backoff.</p></li><li><p>The bastion runs one TLS/WSS daemon on <code>443</code> that accepts:</p><ul><li><p>human proxy sessions at <code>/v1/proxy</code></p></li><li><p>device tunnels at <code>/v1/device-tunnel</code></p></li></ul></li><li><p>The bastion tracks the active device tunnel by <code>device_id</code> and attaches the human byte stream to that live tunnel.</p></li><li><p>No shared device bastion private key is distributed to robots.</p></li></ul><h2 id=\"SSHBastion-VerificationFocus\">Verification Focus</h2><p>The most important validation points are:</p><ol start=\"1\"><li><p>Device bootstrap no longer contains private key material.</p></li><li><p>Device tunnel sessions are short-lived and device-scoped.</p></li><li><p>Human proxy sessions are short-lived and human/device-scoped.</p></li><li><p>Bastion <code>443</code> is sufficient for both human and device traffic.</p></li><li><p>Native <code>ssh aw8-orin</code> still works through <code>ProxyCommand</code>.</p></li></ol><ul><li><p>it can proxy bytes to local <code>127.0.0.1:22</code></p></li></ul><h4 id=\"SSHBastion-Bastion-side\">Bastion-side</h4><ul><li><p>device websocket registration by <code>device_id</code></p></li><li><p>human websocket rejected if device tunnel absent</p></li><li><p>channel bridging between human proxy and device tunnel</p></li><li><p>duplicate/replayed device session tokens rejected</p></li></ul><h4 id=\"SSHBastion-End-to-End\">End-to-End</h4><ol start=\"1\"><li><p>enroll proof VM</p></li><li><p>start <code>hmnd-backboned</code></p></li><li><p>confirm device tunnel is registered on bastion</p></li><li><p>run <code>ssh aw8-orin</code></p></li><li><p>complete OIDC if needed</p></li><li><p>verify host key</p></li><li><p>land on the proof VM shell</p></li></ol><h3 id=\"SSHBastion-11.ExplicitCutoverDecision\">11. Explicit Cutover Decision</h3><p>Because the current shared device tunnel key is not in production use, do this as a single cut:</p><ul><li><p>remove the shared device key path entirely</p></li><li><p>replace device-side OpenSSH reverse tunneling with the new device tunnel websocket path</p></li><li><p>keep the human-side <code>hmnd-ssh</code> UX stable</p></li></ul><p>Do not spend time building migration shims for a path we do not intend to keep.</p><h2 id=\"SSHBastion-DecisionSummary\">Decision Summary</h2><p>The current shared device bastion key is only acceptable as a temporary proof-of-concept shortcut.</p><p>The next implementation should not harden around that key. It should remove it.</p><p>The selected next design is:</p><ul><li><p>human side remains <code>hmnd-ssh</code> + OIDC + short-lived Backbone proxy token</p></li><li><p>device side moves from shared-key OpenSSH reverse tunnel to a Backbone-authenticated WSS device tunnel</p></li><li><p>bastion becomes a single transport service on <code>443</code></p></li><li><p>no shared device private key remains in the system</p></li></ul>"
        },
        {
          "id": "1846870017",
          "title": "Backbone OTA",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1846870017",
          "last_modified": "2026-04-09T14:31:31.716Z",
          "created_at": "2026-04-09T14:17:07.372Z",
          "body_html": "<p><strong>Summary</strong>: Add OTA release publishing, channel-based desired state, per-device channel assignment, and live deployment status to Backbone.</p><p><strong>Owner</strong>: Cody Griffin</p><p><strong>Date</strong>: 04/09/2026</p><p><strong>Status</strong>: Draft</p><h2 id=\"BackboneOTA-ProblemStatement\">Problem Statement</h2><p>Backbone currently solves device enrollment, device identity, certificate renewal, and basic presence via the <code>devices</code> and <code>sessions</code> tables. It does not yet solve OTA. We can see that a device exists and when it was last seen, but we cannot publish release artifacts, assign desired versions, resolve what a device should be running, or observe an update in flight.</p><p>The first OTA design needs to stay honest to the current Backbone model rather than pretending we already have a richer fleet registry than we do. In this codebase, devices are the deployable targets. <code>robot_id</code> is primarily a grouping key over those devices rather than a separately managed object. For Alpha this means a single robot group contains two OTA targets today: one <code>RTPC</code> device and one <code>ORIN</code> device. That is awkward, but it is workable.</p><p>The main mistake to avoid is turning OTA into a giant <code>updates</code> join table with one row per device per release. That model creates write amplification, stale rows, awkward rollbacks, and the wrong ownership boundary between desired state and observed state. The control plane should store intent and let devices report observation. It should not precompute every possible deployment.</p><p>Backbone OTA should therefore add three missing control-plane layers on top of the existing identity service:</p><ol start=\"1\"><li><p>A release catalog and artifact storage path.</p></li><li><p>A desired-state model based on channels and assignments.</p></li><li><p>A live status and execution-history model that makes in-flight OTA behavior visible.</p></li></ol><h2 id=\"BackboneOTA-Scope(Phase1)\">Scope (Phase 1)</h2><p>Phase 1 is deliberately narrow. It should be good enough for the current fleet and the current Alpha topology without locking us into a bad long-term model.</p><h3 id=\"BackboneOTA-InScope\">In Scope</h3><ul><li><p>Publishing release artifacts via the Backbone API, either from bearer-token clients or from the OIDC/Cognito-protected dashboard.</p></li><li><p>Storing release bytes in S3 and release metadata in Postgres.</p></li><li><p>Defining immutable releases per <code>(robot_type, device_type)</code> compatibility pair.</p></li><li><p>Defining channels and assigning one desired release per <code>(robot_type, device_type)</code> within each channel.</p></li><li><p>Assigning individual devices to channels.</p></li><li><p>Resolving desired state for a device over the existing mTLS devices entrypoint.</p></li><li><p>Extending presence/status so operators can see current version, current OTA state, download progress, throughput, and estimated time remaining.</p></li><li><p>Recording deployment attempts and outcomes as execution history.</p></li><li><p>Updating the dashboard so devices are still grouped by <code>robot_id</code>, but each device row shows its current and desired OTA state.</p></li></ul><h3 id=\"BackboneOTA-OutofScope\">Out of Scope</h3><ul><li><p>Rollout percentages, canary waves, or staged rollouts.</p></li><li><p>Robot-level memberships as a first-class data model.</p></li><li><p>Release bundles or trains that coordinate multiple targets atomically.</p></li><li><p>Peer-to-peer artifact distribution, torrent-style fanout, or CDN edge distribution.</p></li><li><p>Delta updates or binary patching.</p></li><li><p>Device-side install policy beyond a simple reconcile/apply/report loop.</p></li><li><p>Replacing the existing enrollment or certificate-renewal flows.</p></li></ul><h2 id=\"BackboneOTA-DesignOverview\">Design Overview</h2><p>Backbone OTA extends the existing registry with a simple desired-state loop.</p><p>Operators publish immutable releases, map those releases into channels, and assign devices to channels. Devices ask Backbone what they should be running, download the artifact, verify it locally, apply it, and report progress back through the existing devices plane. Backbone stores the desired state and the observed state separately, which keeps the model tractable.</p><h3 id=\"BackboneOTA-RelationshiptotheCurrentBackboneRegistry\">Relationship to the Current Backbone Registry</h3><p>Backbone already has the right foundational split for Phase 1:</p><ul><li><p><code>devices</code> is the durable identity inventory.</p></li><li><p><code>sessions</code> is the current observed-state heartbeat.</p></li><li><p>the devices entrypoint is already protected by mTLS.</p></li><li><p>the public and api entrypoints are already protected for human operators.</p></li></ul><p>That means OTA does not need a second identity system. Devices remain the OTA targets.</p><p>Compatibility in Phase 1 should be expressed directly by the existing registry dimensions:</p><ul><li><p><code>robot_type</code></p></li><li><p><code>device_type</code></p></li></ul><p>That is enough for the current fleet and is cleaner than introducing a synthetic compatibility key such as <code>alpha_wheelbase:ORIN</code>. A release is compatible with a concrete <code>(robot_type, device_type)</code> pair, and channels point at releases for those same pairs.</p><h3 id=\"BackboneOTA-CoreConcepts\">Core Concepts</h3><p><strong>Release compatibility pair</strong></p><p>The pair <code>(robot_type, device_type)</code> defines which devices a release is intended for. In Phase 1, that pair is the compatibility class used for release resolution.</p><p><strong>Release</strong></p><p>An immutable artifact plus metadata for one <code>(robot_type, device_type)</code> pair. A release is never \u201cfor a device.\u201d It is for a compatibility class. Once finalized, the object bytes, digest, size, and metadata are immutable. If an image is bad, it is revoked or replaced by a new release, not mutated.</p><p><strong>Channel</strong></p><p>A named desired-state stream such as <code>prod</code>, <code>staging</code>, <code>canary</code>, or <code>field-test</code>. A channel answers the question: for each <code>(robot_type, device_type)</code> pair, what release should members converge to?</p><p><strong>Device channel membership</strong></p><p>A Phase 1 assignment from one device to one effective channel. This is intentionally device-level for now because the current fleet is small and the current registry treats devices as the primary managed objects.</p><p><strong>Desired-state resolution</strong></p><p>A pure lookup from device identity to desired release:</p><p><code>device -&gt; (robot_type, device_type) -&gt; assigned channel -&gt; channel mapping -&gt; desired release</code></p><p>This is the heart of the design. There is no materialized <code>device x release</code> update table.</p><p><strong>Deployment attempt</strong></p><p>An operational record for a concrete OTA attempt. This is where state transitions such as <code>downloading</code>, <code>awaiting_reboot</code>, <code>verifying</code>, <code>succeeded</code>, and <code>failed</code> belong.</p><p><strong>Observed OTA status</strong></p><p>The latest live heartbeat from the device, carried in <code>sessions.data</code>. This is the place for current version, progress counters, throughput, ETA, and the currently active attempt ID.</p><h3 id=\"BackboneOTA-DesiredState,ObservedState,andExecutionHistory\">Desired State, Observed State, and Execution History</h3><p>The design should make these three planes explicit.</p><p><strong>Desired state</strong> is channel membership and channel target mappings. It changes when an operator publishes a release, repoints a channel, or changes an assignment.</p><p><strong>Observed state</strong> is what the device reports right now: current version, current release ID if known, OTA state, progress, last error, and whether it is currently waiting for a reboot or verification.</p><p><strong>Execution history</strong> is the durable record of what happened when the device attempted an update. This is the source of truth for audit and troubleshooting. It should not be overloaded with every heartbeat tick.</p><p>This split matters because progress updates are frequent, while deployment history should capture meaningful lifecycle boundaries. A device may update its session heartbeat every few seconds during a download. That should not force a permanent row for every minor progress change.</p><h3 id=\"BackboneOTA-OperatorFlow\">Operator Flow</h3><p><strong>Release publishing</strong></p><p>An admin creates a draft release in Backbone, including metadata such as <code>robot_type</code>, <code>device_type</code>, version, expected digest, expected size, and optional notes. Backbone returns a presigned direct-upload path to S3. The operator dashboard uses this from the OIDC-protected browser flow; API clients use the same contract from the token-authenticated API host.</p><p>Backbone should not stream multi-gigabyte images through FastAPI. Release bytes should go directly from the browser or CLI to S3. Because Alpha images may be large, the upload path should support multipart uploads rather than assuming a small single PUT.</p><p>Once the upload is complete, the operator finalizes the release. Finalization verifies the object exists and that the expected size and checksum match. Only then does the release become eligible for channel mapping.</p><p><strong>Channel management</strong></p><p>Admins create channels and assign one release per <code>(robot_type, device_type)</code> pair. For Alpha that means a usable channel generally needs two mappings:</p><ul><li><p>one release for <code>(alpha_wheelbase, RTPC)</code></p></li><li><p>one release for <code>(alpha_wheelbase, ORIN)</code></p></li></ul><p>A release does not become active merely by existing. It becomes desired for devices only when a channel points at it.</p><p><strong>Assignment</strong></p><p>Phase 1 assignments are per device. That is a conscious compromise for the current fleet size. The dashboard should still present a robot-centric workflow, which means it should offer a convenience action to apply the same channel assignment to every device sharing a <code>robot_id</code>. Under the hood, that convenience action simply writes multiple device memberships.</p><p>The dashboard should also flag robot groups whose devices are on different channels. This reduces the chance of accidentally splitting a two-target Alpha robot across incompatible desired states.</p><h3 id=\"BackboneOTA-DeviceFlow\">Device Flow</h3><p>Each device should stay dumb.</p><ol start=\"1\"><li><p>It authenticates with the existing Backbone mTLS identity.</p></li><li><p>It calls a desired-state endpoint for itself.</p></li><li><p>It compares desired release versus current release.</p></li><li><p>If no update is needed, it continues heartbeating current status.</p></li><li><p>If an update is needed, it downloads the artifact, verifies digest and signature locally, applies it, reboots if needed, verifies success, and reports the outcome.</p></li></ol><p>Backbone should not tell the device how to install the image beyond the release metadata and basic rollout instructions. Device-side policy should remain simple: ask, validate, apply, report.</p><h3 id=\"BackboneOTA-StatusandProgressReporting\">Status and Progress Reporting</h3><p>Operators need to see more than \u201conline\u201d or \u201coffline.\u201d They should be able to tell whether a device is idle, actively downloading, waiting to reboot, or stuck.</p><p>Phase 1 should therefore define a typed OTA status contract inside <code>sessions.data</code>. At minimum it should support:</p><ul><li><p>current version</p></li><li><p>current release ID if known</p></li><li><p>current OTA state</p></li><li><p>active deployment attempt ID</p></li><li><p>desired release ID being applied</p></li><li><p>artifact bytes total</p></li><li><p>artifact bytes downloaded</p></li><li><p>download bytes per second</p></li><li><p>estimated seconds remaining</p></li><li><p>whether a reboot is required or pending</p></li><li><p>last error code and detail</p></li><li><p>timestamp of the most recent OTA status update</p></li></ul><p>The recommended OTA lifecycle states are:</p><ul><li><p><code>idle</code></p></li><li><p><code>update_available</code></p></li><li><p><code>downloading</code></p></li><li><p><code>downloaded</code></p></li><li><p><code>installing</code></p></li><li><p><code>awaiting_reboot</code></p></li><li><p><code>rebooting</code></p></li><li><p><code>verifying</code></p></li><li><p><code>succeeded</code></p></li><li><p><code>failed</code></p></li><li><p><code>rolled_back</code></p></li><li><p><code>blocked</code></p></li><li><p><code>superseded</code></p></li></ul><p>The dashboard should derive freshness from the existing session heartbeat. If a device has not reported recently, OTA status should be shown as stale rather than assumed current. An offline device that last reported <code>downloading</code> should be rendered as something like \u201coffline; last known OTA state downloading.\u201d</p><h3 id=\"BackboneOTA-WhyThisModelIstheRightTrade\">Why This Model Is the Right Trade</h3><p>This design is intentionally modest.</p><p>It does not introduce robot bundles, staged rollout waves, or a full train system yet. It also does not collapse desired state, observed state, and history into one table. That is the right trade for the current service and the current fleet size.</p><p>It also leaves room for the obvious future upgrades:</p><ul><li><p>replace <code>device_channel_memberships</code> with <code>robot_channel_memberships</code></p></li><li><p>add release bundles once cross-target compatibility becomes harder</p></li><li><p>add rollout waves and canary percentages</p></li><li><p>move from direct S3 downloads to CloudFront or another distribution layer</p></li></ul><p>None of those changes require us to revisit the core concepts of releases, channels, assignments, and observed status.</p><h2 id=\"BackboneOTA-Phase1PolicyDecisions\">Phase 1 Policy Decisions</h2><p>Phase 1 should adopt the following policies explicitly.</p><ul><li><p>Releases are immutable once finalized.</p></li><li><p>A revoked release stays in the catalog but cannot be newly assigned.</p></li><li><p>Devices have one effective channel at a time.</p></li><li><p>Channels should be few; the dashboard should not encourage a channel zoo.</p></li><li><p>The service does not materialize <code>device x release</code> rows.</p></li><li><p>A channel mapping may be incomplete. In that case devices without a matching <code>(robot_type, device_type)</code> mapping simply have no desired release.</p></li><li><p>Rollback is implemented by repointing the channel to an older release.</p></li><li><p>The dashboard groups by <code>robot_id</code>, but desired state is still resolved per device.</p></li><li><p>The current Backbone uniqueness assumption of one <code>(robot_id, device_type)</code> pair remains valid in Phase 1.</p></li></ul><h2 id=\"BackboneOTA-AppendixA:DataModel\">Appendix A: Data Model</h2><p>Phase 1 should reuse the existing <code>devices</code> and <code>sessions</code> tables and add a small set of OTA-specific tables.</p><h3 id=\"BackboneOTA-ExistingTablesReused\">Existing Tables Reused</h3><p><code>devices</code></p><p>Backbone should continue using <code>devices</code> as the durable identity table. No synthetic OTA compatibility column is required in Phase 1. Release compatibility is derived directly from the existing registry fields:</p><ul><li><p><code>robot_type</code></p></li><li><p><code>device_type</code></p></li></ul><p>The current uniqueness assumption remains:</p><ul><li><p>one device per <code>(robot_id, device_type)</code></p></li></ul><p>That is acceptable for Alpha because the two targets are already distinct device types.</p><p><code>sessions</code></p><p>Backbone should continue using <code>sessions</code> as the current-status heartbeat table. The shape of <code>data</code> should become an explicit contract for OTA reporting rather than an unstructured blob.</p><h3 id=\"BackboneOTA-NewTables\">New Tables</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Table</p></th><th class=\"confluenceTh\"><p>Purpose</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p><code>releases</code></p></td><td class=\"confluenceTd\"><p>Immutable release catalog</p></td><td class=\"confluenceTd\"><p>One row per artifact version for one <code>(robot_type, device_type)</code> pair</p></td></tr><tr><td class=\"confluenceTd\"><p><code>channels</code></p></td><td class=\"confluenceTd\"><p>Named desired-state streams</p></td><td class=\"confluenceTd\"><p>Human-facing names like <code>prod</code>, <code>staging</code>, <code>alpha-canary</code></p></td></tr><tr><td class=\"confluenceTd\"><p><code>channel_target_releases</code></p></td><td class=\"confluenceTd\"><p>Desired release pointer per channel and compatibility pair</p></td><td class=\"confluenceTd\"><p>One row per <code>(channel_id, robot_type, device_type)</code></p></td></tr><tr><td class=\"confluenceTd\"><p><code>device_channel_memberships</code></p></td><td class=\"confluenceTd\"><p>Effective channel assignment per device</p></td><td class=\"confluenceTd\"><p>One row per device in Phase 1</p></td></tr><tr><td class=\"confluenceTd\"><p><code><span class=\"inline-comment-marker\" data-ref=\"6236b5a2-46f1-447c-98b3-6e2e8a857749\">deployment_attempts</span></code></p></td><td class=\"confluenceTd\"><p>Execution history for OTA attempts</p></td><td class=\"confluenceTd\"><p>One row per attempt, updated on major state transitions</p></td></tr></tbody></table></div><h3 id=\"BackboneOTA-ProposedSchemaShape\">Proposed Schema Shape</h3><p><code>releases</code></p><ul><li><p><code>id uuid primary key</code></p></li><li><p><code>robot_type text not null</code></p></li><li><p><code>device_type text not null</code></p></li><li><p><code>version text not null</code></p></li><li><p><code>status text not null</code> (<code>draft</code>, <code>uploading</code>, <code>available</code>, <code>revoked</code>)</p></li><li><p><code>artifact_bucket text not null</code></p></li><li><p><code>artifact_key text not null</code></p></li><li><p><code>artifact_size_bytes bigint</code></p></li><li><p><code>artifact_sha256 text</code></p></li><li><p><code>artifact_signature text null</code></p></li><li><p><code>artifact_mime_type text null</code></p></li><li><p><code>upload_session_id text null</code></p></li><li><p><code>metadata jsonb not null default '{}'::jsonb</code></p></li><li><p><code>release_notes text null</code></p></li><li><p><code>created_by_iss text not null</code></p></li><li><p><code>created_by_sub text not null</code></p></li><li><p><code>created_at timestamptz not null</code></p></li><li><p><code>updated_at timestamptz not null</code></p></li><li><p>unique <code>(robot_type, device_type, version)</code></p></li></ul><p><code>channels</code></p><ul><li><p><code>id uuid primary key</code></p></li><li><p><code>name text not null unique</code></p></li><li><p><code>description text null</code></p></li><li><p><code>status text not null</code> (<code>active</code>, <code>paused</code>)</p></li><li><p><code>created_by_iss text not null</code></p></li><li><p><code>created_by_sub text not null</code></p></li><li><p><code>created_at timestamptz not null</code></p></li><li><p><code>updated_at timestamptz not null</code></p></li></ul><p><code>channel_target_releases</code></p><ul><li><p><code>channel_id uuid not null references channels(id)</code></p></li><li><p><code>robot_type text not null</code></p></li><li><p><code>device_type text not null</code></p></li><li><p><code>release_id uuid not null references releases(id)</code></p></li><li><p><code>updated_by_iss text not null</code></p></li><li><p><code>updated_by_sub text not null</code></p></li><li><p><code>updated_at timestamptz not null</code></p></li><li><p>primary key <code>(channel_id, robot_type, device_type)</code></p></li></ul><p><code>device_channel_memberships</code></p><ul><li><p><code>device_id uuid primary key references devices(device_id)</code></p></li><li><p><code>channel_id uuid not null references channels(id)</code></p></li><li><p><code>assigned_by_iss text not null</code></p></li><li><p><code>assigned_by_sub text not null</code></p></li><li><p><code>assigned_at timestamptz not null</code></p></li></ul><p>This table is intentionally separate from <code>devices</code> even though Phase 1 only supports one channel per device. Identity data and rollout policy should not be collapsed into one row unless there is a strong reason.</p><p><code>deployment_attempts</code></p><ul><li><p><code>id uuid primary key</code></p></li><li><p><code>device_id uuid not null references devices(device_id)</code></p></li><li><p><code>channel_id uuid null references channels(id)</code></p></li><li><p><code>release_id uuid not null references releases(id)</code></p></li><li><p><code>from_release_id uuid null references releases(id)</code></p></li><li><p><code>trigger_reason text not null</code> (<code>channel_change</code>, <code>manual</code>, <code>repair</code>, <code>rollback</code>)</p></li><li><p><code>state text not null</code></p></li><li><p><code>current_version text null</code></p></li><li><p><code>target_version text null</code></p></li><li><p><code>bytes_total bigint null</code></p></li><li><p><code>bytes_downloaded bigint null</code></p></li><li><p><code>download_bps bigint null</code></p></li><li><p><code>estimated_seconds_remaining integer null</code></p></li><li><p><code>requires_reboot boolean not null default false</code></p></li><li><p><code>last_error_code text null</code></p></li><li><p><code>last_error_detail text null</code></p></li><li><p><code>started_at timestamptz not null</code></p></li><li><p><code>updated_at timestamptz not null</code></p></li><li><p><code>finished_at timestamptz null</code></p></li></ul><p>This table should capture coarse transitions and final outcomes. It should not be written on every heartbeat tick unless we later decide we need that history.</p><h3 id=\"BackboneOTA-OTAStatusContractinsessions.data\">OTA Status Contract in <code>sessions.data</code></h3><p>The existing <code>sessions</code> table should carry the current observed OTA state. A representative payload is:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"10bbd154-b38e-4d8a-bc67-30507dd308c8\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">{\n  &quot;software&quot;: {\n    &quot;current_version&quot;: &quot;2026.04.1&quot;,\n    &quot;current_release_id&quot;: &quot;6a706e58-8f12-4c43-9f30-2ebc63f7a2aa&quot;\n  },\n  &quot;ota&quot;: {\n    &quot;attempt_id&quot;: &quot;67cc7b27-7e5d-4ff7-b7dc-cce258ba1d55&quot;,\n    &quot;desired_release_id&quot;: &quot;e738bd7b-010f-4b47-b6cb-2a33ad0b4b2b&quot;,\n    &quot;state&quot;: &quot;downloading&quot;,\n    &quot;bytes_total&quot;: 4294967296,\n    &quot;bytes_downloaded&quot;: 2147483648,\n    &quot;download_bps&quot;: 15728640,\n    &quot;estimated_seconds_remaining&quot;: 137,\n    &quot;requires_reboot&quot;: true,\n    &quot;last_error_code&quot;: null,\n    &quot;last_error_detail&quot;: null,\n    &quot;updated_at&quot;: &quot;2026-04-09T10:15:12Z&quot;\n  }\n}</pre>\n</div></div><p>This keeps current-state rendering fast and simple for the dashboard while leaving durable attempt history in <code>deployment_attempts</code>.</p><h2 id=\"BackboneOTA-AppendixB:API,Entrypoints,andAuth\">Appendix B: API, Entrypoints, and Auth</h2><p>Backbone should continue using the existing three entrypoints:</p><ul><li><p><code>public</code>: browser-facing/OIDC path and any anonymous public endpoints</p></li><li><p><code>api</code>: bearer-token human API</p></li><li><p><code>devices</code>: mTLS device API</p></li></ul><p>The existing auth split should remain:</p><ul><li><p><code>operators</code> and <code>admins</code> have read access</p></li><li><p>only <code>admins</code> have write access</p></li><li><p>devices can act only as themselves over the devices entrypoint</p></li></ul><h3 id=\"BackboneOTA-Operator-FacingEndpoints\">Operator-Facing Endpoints</h3><p>These endpoints should be available on the <code>public</code> and <code>api</code> entrypoints. The browser dashboard will typically use <code>public</code>; automation and CLI tooling will typically use <code>api</code>.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Endpoint</p></th><th class=\"confluenceTh\"><p>Entrypoint(s)</p></th><th class=\"confluenceTh\"><p>Auth</p></th><th class=\"confluenceTh\"><p>Purpose</p></th></tr><tr><td class=\"confluenceTd\"><p><code>GET /v1/dashboard</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>operator/admin</p></td><td class=\"confluenceTd\"><p>Render grouped robot/device status including OTA fields</p></td></tr><tr><td class=\"confluenceTd\"><p><code>POST /v1/releases</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>admin</p></td><td class=\"confluenceTd\"><p>Create a draft release row</p></td></tr><tr><td class=\"confluenceTd\"><p><code>POST /v1/releases/{release_id}/upload:init</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>admin</p></td><td class=\"confluenceTd\"><p>Create S3 multipart upload session and presigned part URLs</p></td></tr><tr><td class=\"confluenceTd\"><p><code>POST /v1/releases/{release_id}/upload:complete</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>admin</p></td><td class=\"confluenceTd\"><p>Complete multipart upload</p></td></tr><tr><td class=\"confluenceTd\"><p><code>POST /v1/releases/{release_id}/finalize</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>admin</p></td><td class=\"confluenceTd\"><p>Validate artifact and mark release available</p></td></tr><tr><td class=\"confluenceTd\"><p><code>GET /v1/releases</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>operator/admin</p></td><td class=\"confluenceTd\"><p>List releases</p></td></tr><tr><td class=\"confluenceTd\"><p><code>GET /v1/releases/{release_id}</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>operator/admin</p></td><td class=\"confluenceTd\"><p>Get release details</p></td></tr><tr><td class=\"confluenceTd\"><p><code>POST /v1/channels</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>admin</p></td><td class=\"confluenceTd\"><p>Create channel</p></td></tr><tr><td class=\"confluenceTd\"><p><code>GET /v1/channels</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>operator/admin</p></td><td class=\"confluenceTd\"><p>List channels</p></td></tr><tr><td class=\"confluenceTd\"><p><code>GET /v1/channels/{channel_id}</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>operator/admin</p></td><td class=\"confluenceTd\"><p>Get channel details including compatibility-pair mappings</p></td></tr><tr><td class=\"confluenceTd\"><p><code>PUT /v1/channels/{channel_id}/targets/{robot_type}/{device_type}</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>admin</p></td><td class=\"confluenceTd\"><p>Point a channel mapping at a release</p></td></tr><tr><td class=\"confluenceTd\"><p><code>PUT /v1/devices/{device_id}/channel</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>admin</p></td><td class=\"confluenceTd\"><p>Assign or replace the effective channel for a device</p></td></tr><tr><td class=\"confluenceTd\"><p><code>DELETE /v1/devices/{device_id}/channel</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>admin</p></td><td class=\"confluenceTd\"><p>Remove assignment so the device has no desired release</p></td></tr><tr><td class=\"confluenceTd\"><p><code>GET /v1/admin/sessions</code></p></td><td class=\"confluenceTd\"><p><code>public</code>, <code>api</code></p></td><td class=\"confluenceTd\"><p>operator/admin</p></td><td class=\"confluenceTd\"><p>Raw current status feed, now including OTA status in <code>data</code></p></td></tr></tbody></table></div><p>The dashboard may offer a robot-level \u201cassign all devices in this robot group to channel X\u201d action, but that should be implemented as multiple per-device writes in Phase 1 rather than a separate first-class robot membership API.</p><h3 id=\"BackboneOTA-Device-FacingEndpoints\">Device-Facing Endpoints</h3><p>These endpoints should only be exposed on the <code>devices</code> entrypoint and require the existing mTLS device identity.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Endpoint</p></th><th class=\"confluenceTh\"><p>Entrypoint(s)</p></th><th class=\"confluenceTh\"><p>Auth</p></th><th class=\"confluenceTh\"><p>Purpose</p></th></tr><tr><td class=\"confluenceTd\"><p><code>GET /v1/ota/desired</code></p></td><td class=\"confluenceTd\"><p><code>devices</code></p></td><td class=\"confluenceTd\"><p>device mTLS</p></td><td class=\"confluenceTd\"><p>Resolve desired release for the authenticated device</p></td></tr><tr><td class=\"confluenceTd\"><p><code>POST /v1/ota/releases/{release_id}/download-url</code></p></td><td class=\"confluenceTd\"><p><code>devices</code></p></td><td class=\"confluenceTd\"><p>device mTLS</p></td><td class=\"confluenceTd\"><p>Mint a fresh presigned download URL for retries or resume</p></td></tr><tr><td class=\"confluenceTd\"><p><code>POST /v1/ota/attempts</code></p></td><td class=\"confluenceTd\"><p><code>devices</code></p></td><td class=\"confluenceTd\"><p>device mTLS</p></td><td class=\"confluenceTd\"><p>Start a deployment attempt</p></td></tr><tr><td class=\"confluenceTd\"><p><code><span class=\"inline-comment-marker\" data-ref=\"761b4762-24e4-4f62-9211-2fd6ce42f882\">PATCH /v1/ota/attempts/{attempt_id}</span></code></p></td><td class=\"confluenceTd\"><p><code>devices</code></p></td><td class=\"confluenceTd\"><p>device mTLS</p></td><td class=\"confluenceTd\"><p>Transition state or publish coarse attempt progress</p></td></tr><tr><td class=\"confluenceTd\"><p><code>POST /v1/sessions</code></p></td><td class=\"confluenceTd\"><p><code>devices</code></p></td><td class=\"confluenceTd\"><p>device mTLS</p></td><td class=\"confluenceTd\"><p>Heartbeat current version and live OTA status</p></td></tr></tbody></table></div><h3 id=\"BackboneOTA-Desired-StateResponseShape\">Desired-State Response Shape</h3><p><code>GET /v1/ota/desired</code> should return enough information for a device to decide whether it needs to act.</p><p>Representative shape:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"0bfa97bd-c0fc-44cd-bc19-fb90ff2c4b9c\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">{\n  &quot;device_id&quot;: &quot;...&quot;,\n  &quot;robot_id&quot;: &quot;123&quot;,\n  &quot;channel&quot;: {\n    &quot;id&quot;: &quot;...&quot;,\n    &quot;name&quot;: &quot;staging&quot;\n  },\n  &quot;desired_release&quot;: {\n    &quot;id&quot;: &quot;...&quot;,\n    &quot;robot_type&quot;: &quot;alpha_wheelbase&quot;,\n    &quot;device_type&quot;: &quot;ORIN&quot;,\n    &quot;version&quot;: &quot;2026.04.1&quot;,\n    &quot;artifact_size_bytes&quot;: 4294967296,\n    &quot;artifact_sha256&quot;: &quot;...&quot;,\n    &quot;artifact_signature&quot;: &quot;...&quot;,\n    &quot;download_url&quot;: &quot;https://...&quot;,\n    &quot;download_url_expires_at&quot;: &quot;2026-04-09T10:30:00Z&quot;\n  }\n}</pre>\n</div></div><p>If a device has no channel assignment or if its channel has no release for its <code>(robot_type, device_type)</code> pair, <code>desired_release</code> should be <code>null</code> rather than forcing an error.</p><h3 id=\"BackboneOTA-SessionHeartbeatRequirements\">Session Heartbeat Requirements</h3><p><code>POST /v1/sessions</code> remains the primary current-state heartbeat. OTA-capable devices should send:</p><ul><li><p>current software version</p></li><li><p>current release ID if known</p></li><li><p>live OTA state and progress if an update is in flight</p></li><li><p>last error fields if the most recent attempt failed</p></li></ul><p>During large downloads, devices should heartbeat frequently enough that the dashboard can render meaningful progress and freshness. A heartbeat every 10 to 30 seconds during active OTA is sufficient for Phase 1.</p><h2 id=\"BackboneOTA-AppendixC:AWSInfrastructureAdditions\">Appendix C: AWS Infrastructure Additions</h2><p><code>hmnd_infra/modules/backbone_stack</code> already provisions ECS, Aurora, ALBs, Cognito, PCA, Secrets Manager, and a small S3 bucket for the ALB trust store. OTA requires real artifact storage. That should be added to the existing module rather than created ad hoc elsewhere.</p><h3 id=\"BackboneOTA-RequiredAdditions\">Required Additions</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Resource</p></th><th class=\"confluenceTh\"><p>Purpose</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>Private S3 bucket for OTA artifacts</p></td><td class=\"confluenceTd\"><p>Store uploaded release bytes</p></td><td class=\"confluenceTd\"><p>Separate from the existing trust-store bucket</p></td></tr><tr><td class=\"confluenceTd\"><p>S3 bucket versioning</p></td><td class=\"confluenceTd\"><p>Preserve immutable artifacts and support recovery</p></td><td class=\"confluenceTd\"><p>Enabled by default</p></td></tr><tr><td class=\"confluenceTd\"><p>S3 public-access block</p></td><td class=\"confluenceTd\"><p>Keep artifacts private</p></td><td class=\"confluenceTd\"><p>Required</p></td></tr><tr><td class=\"confluenceTd\"><p>Server-side encryption</p></td><td class=\"confluenceTd\"><p>Encrypt artifact bytes at rest</p></td><td class=\"confluenceTd\"><p>SSE-KMS preferred</p></td></tr><tr><td class=\"confluenceTd\"><p>Lifecycle rules</p></td><td class=\"confluenceTd\"><p>Abort incomplete multipart uploads and optionally clean up abandoned drafts</p></td><td class=\"confluenceTd\"><p>Required</p></td></tr><tr><td class=\"confluenceTd\"><p>Bucket CORS</p></td><td class=\"confluenceTd\"><p>Allow direct browser uploads from the OIDC dashboard origin</p></td><td class=\"confluenceTd\"><p>Include dev localhost origin as needed</p></td></tr><tr><td class=\"confluenceTd\"><p>IAM policy additions on Backbone ECS task role</p></td><td class=\"confluenceTd\"><p>Allow multipart upload orchestration, object metadata reads, and presigned GET/PUT generation</p></td><td class=\"confluenceTd\"><p>Minimal least-privilege scope to the OTA bucket</p></td></tr><tr><td class=\"confluenceTd\"><p>Configuration outputs/secret values</p></td><td class=\"confluenceTd\"><p>Bucket name, region, upload TTLs, download TTLs, allowed origins</p></td><td class=\"confluenceTd\"><p>Passed to Backbone service via config secret or env</p></td></tr></tbody></table></div><h3 id=\"BackboneOTA-SuggestedArtifactLayout\">Suggested Artifact Layout</h3><p>A simple immutable object layout is sufficient:</p><ul><li><p><code>releases/&lt;release_id&gt;/artifact</code></p></li><li><p><code>releases/&lt;release_id&gt;/manifest.json</code></p></li></ul><p>The database remains the source of truth for metadata. S3 stores bytes and optional manifest copies.</p><h3 id=\"BackboneOTA-SuggestedIAMScopefortheBackboneTaskRole\">Suggested IAM Scope for the Backbone Task Role</h3><p>Backbone needs enough S3 permission to orchestrate direct uploads and signed downloads, but nothing broader.</p><p>Representative permissions:</p><ul><li><p><code>s3:PutObject</code></p></li><li><p><code>s3:GetObject</code></p></li><li><p><code>s3:AbortMultipartUpload</code></p></li><li><p><code>s3:ListBucketMultipartUploads</code></p></li><li><p><code>s3:ListMultipartUploadParts</code></p></li><li><p><code>s3:GetObjectAttributes</code></p></li></ul><p>If the bucket uses a customer-managed KMS key, the task role also needs the corresponding <code>kms:Encrypt</code>, <code>kms:Decrypt</code>, and <code>kms:GenerateDataKey</code> grants scoped to that key.</p><h3 id=\"BackboneOTA-WhatDoesNotNeedtoChangeinPhase1\">What Does Not Need to Change in Phase 1</h3><ul><li><p>No new ALB or hostname is required. The existing <code>public</code>, <code>api</code>, and <code>devices</code> entrypoints are sufficient.</p></li><li><p>No new ECS service is required. OTA lives inside the existing Backbone service.</p></li><li><p>No CloudFront distribution is required yet. Direct S3 downloads are acceptable for the current fleet size.</p></li></ul><p>CloudFront may become desirable later if artifact egress grows materially or if we want a different download control layer, but it should not be a Phase 1 dependency.</p><h2 id=\"BackboneOTA-SuggestedDashboardAdditions\">Suggested Dashboard Additions</h2><p>The existing Backbone dashboard already groups device rows by <code>robot_id</code>. OTA should extend that view rather than replace it.</p><p>Each device row should show:</p><ul><li><p>device type</p></li><li><p>channel</p></li><li><p>desired version</p></li><li><p>current version</p></li><li><p>OTA state</p></li><li><p>progress percentage or bytes downloaded</p></li><li><p>download speed</p></li><li><p>estimated time remaining</p></li><li><p>last seen freshness</p></li><li><p>certificate status</p></li></ul><p>Each robot group should additionally show a warning if its devices are assigned to different channels. That is the main operator footgun in the Phase 1 per-device assignment model.</p><h2 id=\"BackboneOTA-FutureExtensions\">Future Extensions</h2><p>If Phase 1 works as expected, the next obvious upgrades are:</p><ul><li><p><code>robot_channel_memberships</code> instead of <code>device_channel_memberships</code></p></li><li><p>release bundles or trains so multi-target robots converge to a tested set</p></li><li><p>rollout waves and percentages</p></li><li><p>artifact distribution through CloudFront or another cache layer</p></li><li><p>typed <code>device_status</code> tables if <code>sessions.data</code> becomes too loose for reporting needs</p></li></ul><p>The important point is that none of those require revisiting the core split between release catalog, desired state, observed state, and execution history.</p><h2 id=\"BackboneOTA-BottomLine\">Bottom Line</h2><p>Backbone OTA should treat the existing <code>devices</code> rows as the OTA targets, treat <code>robot_id</code> as the grouping key, use <code>robot_type + device_type</code> as the compatibility key, store artifacts in S3, store desired state in channels and device memberships, and store live progress separately from deployment history.</p><p>That gives us a practical Phase 1 system for the current fleet:</p><ul><li><p>operators can upload and publish real images</p></li><li><p>channels express desired versions without a giant update table</p></li><li><p>devices can reconcile over the existing mTLS plane</p></li><li><p>the dashboard can show whether a device is downloading, waiting to reboot, verifying, or stuck</p></li></ul><p>It is small enough to build now, but it does not paint us into a corner when we later move from per-device assignments to robot-level policy and multi-target release bundles.</p>"
        },
        {
          "id": "1839235107",
          "title": "OSS Audit: hmnd_wholebody",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1839235107",
          "last_modified": "2026-04-08T10:22:33.997Z",
          "created_at": "2026-04-08T09:51:33.335Z",
          "body_html": "<h1 id=\"OSSAudit:hmnd_wholebody-hmnd_wholebody\u2014DependencyLicenseAudit\">hmnd_wholebody \u2014 Dependency License Audit</h1><p><strong>Risk Level: LOW (revised from HIGH)</strong>    <br/><strong>Key Concerns:</strong> PyQt5 (GPL-3.0) is declared but only used in a dev-only visualization script \u2014 not in any distributed package</p><hr/><h2 id=\"OSSAudit:hmnd_wholebody-Summary\">Summary</h2><p>hmnd_wholebody has a relatively small dependency footprint (21 packages). Initial analysis flagged this module as HIGH risk due to PyQt5 (GPL-3.0), but actual code tracing reveals that PyQt5 is <strong>only imported in a single developer visualization script</strong> and is not part of any installed package or production pipeline.</p><hr/><h2 id=\"OSSAudit:hmnd_wholebody-ActualCodeUsageAnalysis\">Actual Code Usage Analysis</h2><h3 id=\"OSSAudit:hmnd_wholebody-PyQt5\u2014NOTadistributionrisk\">PyQt5 \u2014 NOT a distribution risk</h3><p><strong>The only import of PyQt5/PyQtGraph in the entire module is:</strong></p><p><code>hmnd_wholebody/scripts/sys-id/presentation/simple_visualiser.py</code>:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"04271b5c-020b-43ef-b1c3-921b9cebec93\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">import pyqtgraph as pg\nfrom PyQt5 import QtCore, QtWidgets</pre>\n</div></div><p>This is a <strong>developer-only visualization tool</strong> used for system identification presentation/debugging. Key facts:</p><ul><li><p><strong>Not in any </strong><code>setup.py</code> \u2014 this script is not part of any installable Python package</p></li><li><p><strong>Not in any </strong><code>pyproject.toml</code> entry point \u2014 not registered as a console script or GUI script</p></li><li><p><strong>Located in </strong><code>scripts/</code> \u2014 a directory for ad-hoc developer tools, not production code</p></li><li><p><strong>Not imported by any other module</strong> \u2014 no other file in hmnd_wholebody imports this script</p></li><li><p><strong>Not in any CI/CD pipeline</strong> \u2014 no test or build step references this script</p></li></ul><p><strong>Verdict:</strong> PyQt5 is a dev-time convenience dependency with zero distribution risk. The GPL-3.0 obligation only triggers upon distribution of a derivative work, which does not happen here. Replacing with PySide6 (LGPL-3.0) is still recommended for cleanliness but is low priority.</p><hr/><h2 id=\"OSSAudit:hmnd_wholebody-RED\u2014GPLDependencies\">RED \u2014 GPL Dependencies</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Actual Usage</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi (pypi)</p></td><td class=\"confluenceTd\"><p><strong>pyqt5</strong></p></td><td class=\"confluenceTd\"><p>=5.15.11,&lt;6</p></td><td class=\"confluenceTd\"><p><strong>GPL-3.0</strong></p></td><td class=\"confluenceTd\"><p><strong>Dev-only script</strong> (<code>scripts/sys-id/presentation/simple_visualiser.py</code>)</p></td><td class=\"confluenceTd\"><p>Not in any <a href=\"http://setup.py\" class=\"external-link\" rel=\"nofollow\">setup.py</a> or distributed package. <strong>No distribution risk.</strong></p></td></tr><tr><td class=\"confluenceTd\"><p>pixi (conda)</p></td><td class=\"confluenceTd\"><p>libstdcxx-ng</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>GPL-3.0 (w/ Runtime Exception)</p></td><td class=\"confluenceTd\"><p>Runtime library</p></td><td class=\"confluenceTd\"><p>Exception permits proprietary linking \u2014 safe.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_wholebody-GREEN\u2014PermissiveDependencies\">GREEN \u2014 Permissive Dependencies</h2><h3 id=\"OSSAudit:hmnd_wholebody-PyPI(viapixi.toml)\">PyPI (via pixi.toml)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>seaborn</p></td><td class=\"confluenceTd\"><p>0.13.2</p></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Visualization</p></td></tr><tr><td class=\"confluenceTd\"><p>pandas</p></td><td class=\"confluenceTd\"><p>2.2.3</p></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>tqdm</p></td><td class=\"confluenceTd\"><p>4.67.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Progress</p></td></tr><tr><td class=\"confluenceTd\"><p>h5py</p></td><td class=\"confluenceTd\"><p>3.12.1</p></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>HDF5</p></td></tr><tr><td class=\"confluenceTd\"><p>wandb</p></td><td class=\"confluenceTd\"><p>0.19.11</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Experiment Tracking</p></td></tr><tr><td class=\"confluenceTd\"><p>plotly</p></td><td class=\"confluenceTd\"><p>=6.5.2,&lt;7</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Visualization</p></td></tr><tr><td class=\"confluenceTd\"><p>cmaes</p></td><td class=\"confluenceTd\"><p>=0.12.0,&lt;0.13</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Optimization</p></td></tr><tr><td class=\"confluenceTd\"><p>pyqtgraph</p></td><td class=\"confluenceTd\"><p>=0.14.0,&lt;0.15</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Plotting (note: MIT-licensed itself, but depends on PyQt5 which is GPL \u2014 however, only used in dev script)</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_wholebody-Conda(viapixi.toml)\">Conda (via pixi.toml)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>python</p></td><td class=\"confluenceTd\"><p>=3.11,&lt;3.12</p></td><td class=\"confluenceTd\"><p>PSF</p></td><td class=\"confluenceTd\"><p>Runtime</p></td></tr><tr><td class=\"confluenceTd\"><p>pip</p></td><td class=\"confluenceTd\"><p>=24.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Package Manager</p></td></tr><tr><td class=\"confluenceTd\"><p>setuptools</p></td><td class=\"confluenceTd\"><p>=68,&lt;81</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Build</p></td></tr><tr><td class=\"confluenceTd\"><p>wheel</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Build</p></td></tr><tr><td class=\"confluenceTd\"><p>numpy</p></td><td class=\"confluenceTd\"><p>1.26.4</p></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Numerical</p></td></tr><tr><td class=\"confluenceTd\"><p>prettytable</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Display</p></td></tr><tr><td class=\"confluenceTd\"><p>packaging</p></td><td class=\"confluenceTd\"><p>&lt;24</p></td><td class=\"confluenceTd\"><p>Apache-2.0/BSD</p></td><td class=\"confluenceTd\"><p>Packaging</p></td></tr><tr><td class=\"confluenceTd\"><p>msgpack-python</p></td><td class=\"confluenceTd\"><p>=1.0.0,&lt;2.0.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Serialization</p></td></tr><tr><td class=\"confluenceTd\"><p>platformdirs</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Paths</p></td></tr><tr><td class=\"confluenceTd\"><p>hdf5</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>cmake</p></td><td class=\"confluenceTd\"><p>=3.22.0,&lt;3.27</p></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Build</p></td></tr><tr><td class=\"confluenceTd\"><p>xorg-libsm</p></td><td class=\"confluenceTd\"><p>=1.2.6,&lt;2</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Display</p></td></tr><tr><td class=\"confluenceTd\"><p>xorg-libxt</p></td><td class=\"confluenceTd\"><p>=1.3.1,&lt;2</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Display</p></td></tr><tr><td class=\"confluenceTd\"><p>libglu</p></td><td class=\"confluenceTd\"><p>=9.0.3,&lt;10</p></td><td class=\"confluenceTd\"><p>SGI-B-2.0</p></td><td class=\"confluenceTd\"><p>Graphics</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_wholebody-RecommendedAction\">Recommended Action</h2><p><strong>Low priority:</strong> Replace PyQt5 with PySide6 in <code>pixi.toml</code> for cleanliness. PySide6 provides identical Qt Python bindings under LGPL-3.0 instead of GPL-3.0. This is a near-drop-in replacement. However, since this dependency is only used in a dev-only script that is never distributed, this is not urgent and carries no compliance risk as-is.</p>"
        },
        {
          "id": "1840807951",
          "title": "OSS Audit: hmnd_training",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1840807951",
          "last_modified": "2026-04-08T10:22:08.914Z",
          "created_at": "2026-04-08T09:50:02.671Z",
          "body_html": "<h1 id=\"OSSAudit:hmnd_training-hmnd_training\u2014DependencyLicenseAudit\">hmnd_training \u2014 Dependency License Audit</h1><p><strong>Risk Level: LOW (revised from HIGH)</strong>    <br/><strong>Key Concerns:</strong> ffmpeg/x264/x265 present but used safely (PyAV is training-only, CLI is subprocess). All other RED items are build tools with GCC Runtime Exception.</p><hr/><h2 id=\"OSSAudit:hmnd_training-Summary\">Summary</h2><p>hmnd_training has 571 total packages resolved in pixi.lock, plus bundled third-party code (lerobot, libero, robocasa, simplerenv, xdof_sdk). The training environment pulls in a large transitive closure of system libraries, many of which carry LGPL licenses. Initial analysis flagged this module as HIGH risk due to the GPL video codec chain, but actual code tracing reveals the risk is low because training code is not distributed externally.</p><hr/><h2 id=\"OSSAudit:hmnd_training-ActualCodeUsageAnalysis\">Actual Code Usage Analysis</h2><h3 id=\"OSSAudit:hmnd_training-FFmpeg/x264/x265\u2014UsageBreakdown\">FFmpeg / x264 / x265 \u2014 Usage Breakdown</h3><p><strong>1. PyAV in lerobot (linked, but training-only):</strong></p><p><code>hmnd_training/third_party/lerobot/src/lerobot/datasets/video_utils.py</code> contains:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"37eb40ec-af24-46e9-ae8d-ae672c595795\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">import av</pre>\n</div></div><p>PyAV is a Python wrapper that uses C bindings to <code>libavcodec</code>, <code>libavformat</code>, etc. This is a library linkage (not subprocess), which technically triggers GPL copyleft. However, this code runs only in training environments and is never distributed to customers or third parties. The GPL obligation only arises upon distribution.</p><p><strong>2. FFmpeg CLI in data conversion (safe \u2014 subprocess):</strong></p><p><code>hmnd_training/tools/data/agibot/scripts/agibot_hdf5_to_lerobot_v3.py</code> uses:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"79d656d5-df00-444e-8cb3-fe84c747a23a\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">subprocess.run([&quot;ffmpeg&quot;, ...])</pre>\n</div></div><p>This invokes ffmpeg as an external CLI process. Subprocess invocation does not create a derivative work under GPL. This usage is safe regardless of ffmpeg's license.</p><p><strong>3. pixi.toml declaration:</strong></p><p><code>ffmpeg = &quot;&gt;=5.1&quot;</code> is declared with the comment <code># Required by rerun-sdk for video decoding</code>. The rerun-sdk (MIT licensed) uses ffmpeg for visualization during training. Again, training-only.</p><h3 id=\"OSSAudit:hmnd_training-readline\u2014NOTarealrisk\">readline \u2014 NOT a real risk</h3><p>readline (GPL-3.0) appears in pixi.lock as a transitive dependency of IPython. However, <strong>readline is never directly imported</strong> in any hmnd_training code. It is only active when a developer uses the IPython REPL interactively. This is not a distribution concern.</p><h3 id=\"OSSAudit:hmnd_training-Buildtoolchain(gcc,gxx,make,binutils,etc.)\">Build toolchain (gcc, gxx, make, binutils, etc.)</h3><p>All build tools (gcc 14.3.0, gxx 14.3.0, make 4.4.1, binutils 2.45.1, etc.) are GPL-3.0 but are build-time only. The GCC Runtime Library Exception explicitly permits linking the resulting compiled code into proprietary software. The runtime libraries (libgcc, libstdc++, libgfortran, libgomp) all carry this exception.</p><hr/><h2 id=\"OSSAudit:hmnd_training-RED\u2014GPLDependencies(StrongCopyleft)\">RED \u2014 GPL Dependencies (Strong Copyleft)</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Actual Usage</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>ffmpeg</p></td><td class=\"confluenceTd\"><p>7.1.1</p></td><td class=\"confluenceTd\"><p>GPL-2.0+ / LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>PyAV (training-only) + subprocess (safe)</p></td><td class=\"confluenceTd\"><p><strong>Revised:</strong> Not distributed. Low risk.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libx264</p></td><td class=\"confluenceTd\"><p>3.0.2</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>Transitive via ffmpeg</p></td><td class=\"confluenceTd\"><p>Same \u2014 training-only.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libx265 / x265</p></td><td class=\"confluenceTd\"><p>3.5</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>Transitive via ffmpeg</p></td><td class=\"confluenceTd\"><p>Same \u2014 training-only.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>readline</p></td><td class=\"confluenceTd\"><p>8.3</p></td><td class=\"confluenceTd\"><p>GPL-3.0+</p></td><td class=\"confluenceTd\"><p><strong>Never imported</strong> \u2014 transitive via IPython</p></td><td class=\"confluenceTd\"><p>Not a distribution risk.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>dbus</p></td><td class=\"confluenceTd\"><p>1.16.2</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>System library</p></td><td class=\"confluenceTd\"><p>Inter-process communication.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>gdbm</p></td><td class=\"confluenceTd\"><p>1.18</p></td><td class=\"confluenceTd\"><p>GPL-3.0+</p></td><td class=\"confluenceTd\"><p>System library</p></td><td class=\"confluenceTd\"><p>Key-value database.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>elfutils</p></td><td class=\"confluenceTd\"><p>0.193</p></td><td class=\"confluenceTd\"><p>GPL-3.0+</p></td><td class=\"confluenceTd\"><p>Dev tool</p></td><td class=\"confluenceTd\"><p>ELF utilities.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>hicolor-icon-theme</p></td><td class=\"confluenceTd\"><p>0.17</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>Desktop theme</p></td><td class=\"confluenceTd\"><p>Icon theme data.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>lz4-c</p></td><td class=\"confluenceTd\"><p>1.10.0</p></td><td class=\"confluenceTd\"><p>GPL-2.0+ / BSD-2</p></td><td class=\"confluenceTd\"><p>Compression</p></td><td class=\"confluenceTd\"><p>Dual licensed \u2014 BSD option available.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>lzo</p></td><td class=\"confluenceTd\"><p>2.10</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>Compression</p></td><td class=\"confluenceTd\"><p>Lossless compression.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>zstd</p></td><td class=\"confluenceTd\"><p>1.5.7</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>Compression</p></td><td class=\"confluenceTd\"><p>Dual-licensed BSD in some distributions.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>xz-gpl-tools</p></td><td class=\"confluenceTd\"><p>5.8.2</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>CLI tool</p></td><td class=\"confluenceTd\"><p>XZ compression tools.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>shellcheck</p></td><td class=\"confluenceTd\"><p>0.10.0</p></td><td class=\"confluenceTd\"><p>GPL-3.0+</p></td><td class=\"confluenceTd\"><p>Dev tool only</p></td><td class=\"confluenceTd\"><p>Shell linter.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>gcc / gxx (14.3.0)</p></td><td class=\"confluenceTd\"><p>various</p></td><td class=\"confluenceTd\"><p>GPL-3.0+</p></td><td class=\"confluenceTd\"><p>Build-time only</p></td><td class=\"confluenceTd\"><p>GCC Runtime Exception applies.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>binutils / ld_impl</p></td><td class=\"confluenceTd\"><p>2.45.1</p></td><td class=\"confluenceTd\"><p>GPL-3.0+</p></td><td class=\"confluenceTd\"><p>Build-time only</p></td><td class=\"confluenceTd\"><p>Build tools.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>make</p></td><td class=\"confluenceTd\"><p>4.4.1</p></td><td class=\"confluenceTd\"><p>GPL-3.0+</p></td><td class=\"confluenceTd\"><p>Build-time only</p></td><td class=\"confluenceTd\"><p>Build system.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>kernel-headers</p></td><td class=\"confluenceTd\"><p>5.14.0</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>Build-time only</p></td><td class=\"confluenceTd\"><p>Linux headers.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>sysroot_linux_64</p></td><td class=\"confluenceTd\"><p>2.34</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>Build environment</p></td><td class=\"confluenceTd\"><p>System root.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libgcc / libgcc-ng</p></td><td class=\"confluenceTd\"><p>15.2.0</p></td><td class=\"confluenceTd\"><p>GPL-3.0+ w/ Runtime Exception</p></td><td class=\"confluenceTd\"><p>Runtime library</p></td><td class=\"confluenceTd\"><p>Exception permits proprietary linking \u2014 safe.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libstdcxx / libstdcxx-ng</p></td><td class=\"confluenceTd\"><p>15.2.0</p></td><td class=\"confluenceTd\"><p>GPL-3.0+ w/ Runtime Exception</p></td><td class=\"confluenceTd\"><p>Runtime library</p></td><td class=\"confluenceTd\"><p>Exception permits proprietary linking \u2014 safe.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libgfortran / libgfortran5 / libgfortran-ng</p></td><td class=\"confluenceTd\"><p>15.2.0</p></td><td class=\"confluenceTd\"><p>GPL-3.0+ w/ Runtime Exception</p></td><td class=\"confluenceTd\"><p>Runtime library</p></td><td class=\"confluenceTd\"><p>Used by numpy/scipy. Exception applies.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libgomp</p></td><td class=\"confluenceTd\"><p>15.2.0</p></td><td class=\"confluenceTd\"><p>GPL-3.0+ w/ Runtime Exception</p></td><td class=\"confluenceTd\"><p>Runtime library</p></td><td class=\"confluenceTd\"><p>OpenMP runtime. Exception applies.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libsanitizer</p></td><td class=\"confluenceTd\"><p>15.2.0</p></td><td class=\"confluenceTd\"><p>GPL-3.0+ w/ Runtime Exception</p></td><td class=\"confluenceTd\"><p>Dev tool</p></td><td class=\"confluenceTd\"><p>Address/Thread sanitizers.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libgettext / libgettextpo</p></td><td class=\"confluenceTd\"><p>0.25.1</p></td><td class=\"confluenceTd\"><p>GPL-3.0+</p></td><td class=\"confluenceTd\"><p>System library</p></td><td class=\"confluenceTd\"><p>GNU gettext.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libidn2</p></td><td class=\"confluenceTd\"><p>2.3.8</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>System library</p></td><td class=\"confluenceTd\"><p>Internationalized domain names.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libunwind</p></td><td class=\"confluenceTd\"><p>1.8.3</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>System library</p></td><td class=\"confluenceTd\"><p>Stack unwinding.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>liburing</p></td><td class=\"confluenceTd\"><p>2.12</p></td><td class=\"confluenceTd\"><p>GPL-2.0+</p></td><td class=\"confluenceTd\"><p>System library</p></td><td class=\"confluenceTd\"><p>io_uring interface.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>nettle</p></td><td class=\"confluenceTd\"><p>3.10.1</p></td><td class=\"confluenceTd\"><p>LGPL-3.0+ or GPL-2.0+</p></td><td class=\"confluenceTd\"><p>Crypto library</p></td><td class=\"confluenceTd\"><p>Check which license variant applies.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>freetype / libfreetype</p></td><td class=\"confluenceTd\"><p>2.14.1</p></td><td class=\"confluenceTd\"><p>GPL-2.0+ or FTL</p></td><td class=\"confluenceTd\"><p>Font library</p></td><td class=\"confluenceTd\"><p>FreeType License (FTL) is permissive option.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_training-YELLOW\u2014LGPL/MPLDependencies(WeakCopyleft)\">YELLOW \u2014 LGPL/MPL Dependencies (Weak Copyleft)</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>qt6-main</p></td><td class=\"confluenceTd\"><p>6.9.2</p></td><td class=\"confluenceTd\"><p>LGPL-3.0 or LGPL-2.0+</p></td><td class=\"confluenceTd\"><p>Qt GUI framework. Not linked into distributed binaries.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>gtk3</p></td><td class=\"confluenceTd\"><p>3.24.43</p></td><td class=\"confluenceTd\"><p>LGPL-2.0+</p></td><td class=\"confluenceTd\"><p>GTK graphical toolkit \u2014 transitive dependency.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>pango</p></td><td class=\"confluenceTd\"><p>1.56.4</p></td><td class=\"confluenceTd\"><p>LGPL-2.0+</p></td><td class=\"confluenceTd\"><p>Text layout and rendering.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>librsvg</p></td><td class=\"confluenceTd\"><p>2.58.4</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>SVG rendering.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>gdk-pixbuf</p></td><td class=\"confluenceTd\"><p>2.44.5</p></td><td class=\"confluenceTd\"><p>LGPL-2.0+</p></td><td class=\"confluenceTd\"><p>Image handling.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libglib</p></td><td class=\"confluenceTd\"><p>2.86.4</p></td><td class=\"confluenceTd\"><p>LGPL-2.0+ or MPL-1.1</p></td><td class=\"confluenceTd\"><p>Core GLib library.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>glib-tools</p></td><td class=\"confluenceTd\"><p>2.86.4</p></td><td class=\"confluenceTd\"><p>LGPL-2.0+ or MPL-1.1</p></td><td class=\"confluenceTd\"><p>Core library tools.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>graphite2</p></td><td class=\"confluenceTd\"><p>1.3.14</p></td><td class=\"confluenceTd\"><p>LGPL-2.0+ or MPL-1.1</p></td><td class=\"confluenceTd\"><p>Font shaping.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>gmp</p></td><td class=\"confluenceTd\"><p>6.3.0</p></td><td class=\"confluenceTd\"><p>LGPL-3.0+</p></td><td class=\"confluenceTd\"><p>Multiple precision arithmetic.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>gts</p></td><td class=\"confluenceTd\"><p>0.7.6</p></td><td class=\"confluenceTd\"><p>LGPL-2.0+</p></td><td class=\"confluenceTd\"><p>Geometric algorithms.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>gnutls</p></td><td class=\"confluenceTd\"><p>3.8.11</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+ (or GPL-3.0+)</p></td><td class=\"confluenceTd\"><p>TLS/SSL \u2014 verify LGPL variant is used.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>lame</p></td><td class=\"confluenceTd\"><p>3.100</p></td><td class=\"confluenceTd\"><p>LGPL-2.0+</p></td><td class=\"confluenceTd\"><p>MP3 encoding.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libacl</p></td><td class=\"confluenceTd\"><p>2.3.2</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>POSIX ACL library.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libblasfeo</p></td><td class=\"confluenceTd\"><p>0.1.4.2</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>BLAS/LAPACK library.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libfatrop</p></td><td class=\"confluenceTd\"><p>0.0.4</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Fast trajectory optimization.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libiconv</p></td><td class=\"confluenceTd\"><p>1.18</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Character encoding.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libmicrohttpd</p></td><td class=\"confluenceTd\"><p>1.0.2</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>HTTP server library.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libnsl</p></td><td class=\"confluenceTd\"><p>2.0.1</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Network services.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libntlm</p></td><td class=\"confluenceTd\"><p>1.8</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>NTLM authentication.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libsndfile</p></td><td class=\"confluenceTd\"><p>1.2.2</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Sound file library.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libsystemd0</p></td><td class=\"confluenceTd\"><p>259.1</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Systemd library.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libtasn1</p></td><td class=\"confluenceTd\"><p>4.21.0</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>ASN.1 library.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libudev1</p></td><td class=\"confluenceTd\"><p>259.1</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>udev device library.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libunistring</p></td><td class=\"confluenceTd\"><p>0.9.10</p></td><td class=\"confluenceTd\"><p>LGPL-3.0+</p></td><td class=\"confluenceTd\"><p>Unicode string library.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libusb</p></td><td class=\"confluenceTd\"><p>1.0.29</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>USB device library.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>libxcrypt</p></td><td class=\"confluenceTd\"><p>4.4.36</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Password hashing.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>mpg123</p></td><td class=\"confluenceTd\"><p>1.32.9</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>MPEG audio decoding.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>pulseaudio-client</p></td><td class=\"confluenceTd\"><p>17.0</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>PulseAudio client.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>pygame</p></td><td class=\"confluenceTd\"><p>2.5.2</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Game development.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>pynput</p></td><td class=\"confluenceTd\"><p>1.7.7</p></td><td class=\"confluenceTd\"><p>LGPL-3.0</p></td><td class=\"confluenceTd\"><p>Keyboard/mouse control.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>num2words</p></td><td class=\"confluenceTd\"><p>0.5.14</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Number-to-words conversion.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>humanfriendly</p></td><td class=\"confluenceTd\"><p>10.0</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Human-readable formatting.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>keyutils</p></td><td class=\"confluenceTd\"><p>1.6.3</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Kernel key utilities.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>fribidi</p></td><td class=\"confluenceTd\"><p>1.0.16</p></td><td class=\"confluenceTd\"><p>LGPL-2.1+</p></td><td class=\"confluenceTd\"><p>Bidirectional text.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>empy</p></td><td class=\"confluenceTd\"><p>3.3.4</p></td><td class=\"confluenceTd\"><p>LGPL-2.0+</p></td><td class=\"confluenceTd\"><p>Template language.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>eiquadprog</p></td><td class=\"confluenceTd\"><p>1.3.1</p></td><td class=\"confluenceTd\"><p>LGPL-3.0</p></td><td class=\"confluenceTd\"><p>Quadratic programming solver.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>eigen</p></td><td class=\"confluenceTd\"><p>3.4.0</p></td><td class=\"confluenceTd\"><p>MPL-2.0</p></td><td class=\"confluenceTd\"><p>Linear algebra (file-level copyleft only).</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>jsonlines</p></td><td class=\"confluenceTd\"><p>4.0.0</p></td><td class=\"confluenceTd\"><p>MPL-2.0</p></td><td class=\"confluenceTd\"><p>JSON Lines format.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>tqdm</p></td><td class=\"confluenceTd\"><p>4.66.0</p></td><td class=\"confluenceTd\"><p>MPL-2.0 / MIT</p></td><td class=\"confluenceTd\"><p>Progress bar (dual licensed).</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>pytest-rerunfailures</p></td><td class=\"confluenceTd\"><p>16.1</p></td><td class=\"confluenceTd\"><p>MPL-2.0</p></td><td class=\"confluenceTd\"><p>Test plugin.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_training-GRAY\u2014UnknownLicense\">GRAY \u2014 Unknown License</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi.lock</p></td><td class=\"confluenceTd\"><p>icu</p></td><td class=\"confluenceTd\"><p>78.2</p></td><td class=\"confluenceTd\"><p>International Components for Unicode \u2014 likely Unicode License (permissive).</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>robocasa</p></td><td class=\"confluenceTd\"><p>0.2.0</p></td><td class=\"confluenceTd\"><p>Kitchen simulation benchmark. No license in <a href=\"http://setup.py\" class=\"external-link\" rel=\"nofollow\">setup.py</a>.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>xdof_sdk</p></td><td class=\"confluenceTd\"><p>custom</p></td><td class=\"confluenceTd\"><p>X-DOF hand SDK. No LICENSE file.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_training-BundledThird-PartyCode\">Bundled Third-Party Code</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Location</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>lerobot</strong></p></td><td class=\"confluenceTd\"><p><code>third_party/lerobot/</code></p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>libero</strong></p></td><td class=\"confluenceTd\"><p><code>third_party/libero/</code></p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>robocasa</strong></p></td><td class=\"confluenceTd\"><p><code>third_party/robocasa/</code></p></td><td class=\"confluenceTd\"><p><strong>UNKNOWN</strong> \u2014 no license in <a href=\"http://setup.py\" class=\"external-link\" rel=\"nofollow\">setup.py</a></p></td><td class=\"confluenceTd\"><p>GRAY</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>simplerenv</strong></p></td><td class=\"confluenceTd\"><p><code>third_party/simplerenv/</code></p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>xdof_sdk</strong></p></td><td class=\"confluenceTd\"><p><code>third_party/xdof_sdk/</code></p></td><td class=\"confluenceTd\"><p><strong>UNKNOWN</strong> \u2014 no LICENSE file</p></td><td class=\"confluenceTd\"><p>GRAY</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_training-GREEN\u2014PermissiveDependencies(Selectedfrom571total)\">GREEN \u2014 Permissive Dependencies (Selected from 571 total)</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>python</p></td><td class=\"confluenceTd\"><p>3.11.14</p></td><td class=\"confluenceTd\"><p>PSF</p></td><td class=\"confluenceTd\"><p>Runtime</p></td></tr><tr><td class=\"confluenceTd\"><p>numpy</p></td><td class=\"confluenceTd\"><p>1.26.4</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Numerical</p></td></tr><tr><td class=\"confluenceTd\"><p>scipy</p></td><td class=\"confluenceTd\"><p>1.16.3</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Scientific Computing</p></td></tr><tr><td class=\"confluenceTd\"><p>torch</p></td><td class=\"confluenceTd\"><p>2.2.1</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Deep Learning</p></td></tr><tr><td class=\"confluenceTd\"><p>torchvision</p></td><td class=\"confluenceTd\"><p>0.21.0</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Computer Vision</p></td></tr><tr><td class=\"confluenceTd\"><p>transformers</p></td><td class=\"confluenceTd\"><p>4.21.1</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>NLP</p></td></tr><tr><td class=\"confluenceTd\"><p>diffusers</p></td><td class=\"confluenceTd\"><p>0.35.2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Diffusion Models</p></td></tr><tr><td class=\"confluenceTd\"><p>accelerate</p></td><td class=\"confluenceTd\"><p>1.12.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Distributed Training</p></td></tr><tr><td class=\"confluenceTd\"><p>datasets</p></td><td class=\"confluenceTd\"><p>4.0.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>huggingface-hub</p></td><td class=\"confluenceTd\"><p>0.34.2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>ML Hub</p></td></tr><tr><td class=\"confluenceTd\"><p>safetensors</p></td><td class=\"confluenceTd\"><p>0.4.3</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Serialization</p></td></tr><tr><td class=\"confluenceTd\"><p>peft</p></td><td class=\"confluenceTd\"><p>0.18.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Fine-tuning</p></td></tr><tr><td class=\"confluenceTd\"><p>opencv</p></td><td class=\"confluenceTd\"><p>4.11.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Computer Vision</p></td></tr><tr><td class=\"confluenceTd\"><p>pinocchio</p></td><td class=\"confluenceTd\"><p>3.7.0</p></td><td class=\"confluenceTd\"><p>BSD-2</p></td><td class=\"confluenceTd\"><p>Robot Dynamics</p></td></tr><tr><td class=\"confluenceTd\"><p>mujoco</p></td><td class=\"confluenceTd\"><p>3.3.2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Physics</p></td></tr><tr><td class=\"confluenceTd\"><p>gymnasium</p></td><td class=\"confluenceTd\"><p>1.1.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>RL Environments</p></td></tr><tr><td class=\"confluenceTd\"><p>pandas</p></td><td class=\"confluenceTd\"><p>2.2.2</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>h5py</p></td><td class=\"confluenceTd\"><p>3.15.1</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>HDF5</p></td></tr><tr><td class=\"confluenceTd\"><p>matplotlib</p></td><td class=\"confluenceTd\"><p>3.10.3</p></td><td class=\"confluenceTd\"><p>PSF</p></td><td class=\"confluenceTd\"><p>Plotting</p></td></tr><tr><td class=\"confluenceTd\"><p>wandb</p></td><td class=\"confluenceTd\"><p>0.21.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Experiment Tracking</p></td></tr><tr><td class=\"confluenceTd\"><p>rerun-sdk</p></td><td class=\"confluenceTd\"><p>0.28.2</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Visualization</p></td></tr><tr><td class=\"confluenceTd\"><p>flash-attn</p></td><td class=\"confluenceTd\"><p>2.5.9</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>ML Optimization</p></td></tr><tr><td class=\"confluenceTd\"><p>lerobot</p></td><td class=\"confluenceTd\"><p>0.4.3</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Robotics</p></td></tr><tr><td class=\"confluenceTd\"><p>robomimic</p></td><td class=\"confluenceTd\"><p>0.2.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Robot Learning</p></td></tr><tr><td class=\"confluenceTd\"><p>robosuite</p></td><td class=\"confluenceTd\"><p>1.4.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Robot Simulation</p></td></tr><tr><td class=\"confluenceTd\"><p>hydra-core</p></td><td class=\"confluenceTd\"><p>1.2.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Config</p></td></tr><tr><td class=\"confluenceTd\"><p>pytest</p></td><td class=\"confluenceTd\"><p>8.4.2</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Testing</p></td></tr><tr><td class=\"confluenceTd\"><p>pre-commit</p></td><td class=\"confluenceTd\"><p>4.5.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Dev Tool</p></td></tr><tr><td class=\"confluenceTd\"><p>ipython</p></td><td class=\"confluenceTd\"><p>9.10.0</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Development</p></td></tr><tr><td class=\"confluenceTd\"><p>openssl</p></td><td class=\"confluenceTd\"><p>3.6.1</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Crypto</p></td></tr><tr><td class=\"confluenceTd\"><p>protobuf</p></td><td class=\"confluenceTd\"><p>6.31.1</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Serialization</p></td></tr><tr><td class=\"confluenceTd\"><p>grpcio</p></td><td class=\"confluenceTd\"><p>1.60.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>RPC</p></td></tr><tr><td class=\"confluenceTd\"><p>pillow</p></td><td class=\"confluenceTd\"><p>12.1.1</p></td><td class=\"confluenceTd\"><p>HPND</p></td><td class=\"confluenceTd\"><p>Image Processing</p></td></tr><tr><td class=\"confluenceTd\"><p>numba</p></td><td class=\"confluenceTd\"><p>0.56.4</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>JIT</p></td></tr><tr><td class=\"confluenceTd\"><p>sqlite</p></td><td class=\"confluenceTd\"><p>3.51.2</p></td><td class=\"confluenceTd\"><p>Public Domain</p></td><td class=\"confluenceTd\"><p>Database</p></td></tr><tr><td class=\"confluenceTd\"><p>zlib</p></td><td class=\"confluenceTd\"><p>1.3.1</p></td><td class=\"confluenceTd\"><p>Zlib</p></td><td class=\"confluenceTd\"><p>Compression</p></td></tr><tr><td class=\"confluenceTd\"><p>libxml2</p></td><td class=\"confluenceTd\"><p>2.13.9</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>XML</p></td></tr><tr><td class=\"confluenceTd\"><p>libcurl</p></td><td class=\"confluenceTd\"><p>8.18.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>HTTP</p></td></tr><tr><td class=\"confluenceTd\"><p>harfbuzz</p></td><td class=\"confluenceTd\"><p>12.2.0</p></td><td class=\"confluenceTd\"><p>MIT/ISC</p></td><td class=\"confluenceTd\"><p>Font</p></td></tr><tr><td class=\"confluenceTd\"><p>fontconfig</p></td><td class=\"confluenceTd\"><p>2.17.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Font Config</p></td></tr><tr><td class=\"confluenceTd\"><p>ncurses</p></td><td class=\"confluenceTd\"><p>6.5</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Terminal</p></td></tr><tr><td class=\"confluenceTd\"><p>libarchive</p></td><td class=\"confluenceTd\"><p>3.8.1</p></td><td class=\"confluenceTd\"><p>BSD-2</p></td><td class=\"confluenceTd\"><p>Archive</p></td></tr><tr><td class=\"confluenceTd\"><p>opengl</p></td><td class=\"confluenceTd\"><p>1.7.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Graphics</p></td></tr><tr><td class=\"confluenceTd\"><p>vulkan-loader</p></td><td class=\"confluenceTd\"><p>1.4.341.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Graphics</p></td></tr><tr><td class=\"confluenceTd\"><p>glfw</p></td><td class=\"confluenceTd\"><p>3.4</p></td><td class=\"confluenceTd\"><p>Zlib</p></td><td class=\"confluenceTd\"><p>Window</p></td></tr><tr><td class=\"confluenceTd\"><p>cmake</p></td><td class=\"confluenceTd\"><p>4.2.3</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td></tr><tr><td class=\"confluenceTd\"><p>ninja</p></td><td class=\"confluenceTd\"><p>1.13.2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td></tr><tr><td class=\"confluenceTd\"><p>s5cmd</p></td><td class=\"confluenceTd\"><p>2.3.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>S3 Tool</p></td></tr></tbody></table></div>"
        },
        {
          "id": "1839038509",
          "title": "OSS Audit: hmnd_robot",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1839038509",
          "last_modified": "2026-04-08T10:20:47.149Z",
          "created_at": "2026-04-08T09:49:03.909Z",
          "body_html": "<h1 id=\"OSSAudit:hmnd_robot-hmnd_robot\u2014DependencyLicenseAudit\">hmnd_robot \u2014 Dependency License Audit</h1><p><strong>Risk Level: HIGH (confirmed by code analysis)</strong>    <br/><strong>Key Concerns:</strong> EtherCAT (GPL-2.0) ships in OS image, FFmpeg direct C linkage in quest_stream_viewer, spidev (GPL-2.0) on robot hardware</p><hr/><h2 id=\"OSSAudit:hmnd_robot-Summary\">Summary</h2><p>hmnd_robot is the largest module with 950+ total dependencies across conda (pixi), PyPI, Rust (Cargo), npm, and bundled third-party source code. It contains the most significant licensing risks in the entire repository due to the bundled EtherCAT driver (GPL-2.0) and the inclusion of GPL video codecs.</p><hr/><h2 id=\"OSSAudit:hmnd_robot-ActualCodeUsageAnalysis\">Actual Code Usage Analysis</h2><p>The following traces each problematic dependency to its actual usage in the codebase, determining real vs theoretical risk.</p><h3 id=\"OSSAudit:hmnd_robot-EtherCAT\u2014CRITICAL(GPL-2.0,shipsinrobotOSimage)\">EtherCAT \u2014 CRITICAL (GPL-2.0, ships in robot OS image)</h3><p><strong>Full linkage chain:</strong></p><ol start=\"1\"><li><p><strong>Source:</strong> <code>core/third_party/ethercat/etherlab-ethercat/</code> \u2014 bundled GPL-2.0 source code with <code>COPYING</code> file confirming GPL-2.0</p></li><li><p><strong>Build:</strong> <code>core/third_party/ethercat/CMakeLists.txt</code> compiles this into <code>libethercat.so</code> (shared library)</p></li><li><p><strong>ROS integration:</strong> <code>ros/third_party/icube-ethercat-ros2/ethercat_interface/CMakeLists.txt</code> contains <code>find_library(ETHERCAT_LIB ethercat)</code> and <code>target_link_libraries(${PROJECT_NAME} ${ETHERCAT_LIB})</code> \u2014 links the GPL library</p></li><li><p><strong>Driver:</strong> <code>ros/hardware/alpha_universal_driver/CMakeLists.txt</code> links to <code>ethercat_interface</code>, and <code>src/ethercat_bus_driver.cpp</code> includes <code>#include &quot;ethercat_interface/ec_master.hpp&quot;</code></p></li><li><p><strong>Packaging:</strong> <code>targets/congatech_rtpc/BUILD</code> packages <code>hmnd-ethercat</code> and <code>hmnd-ethercat-modules</code> as Debian package dependencies</p></li><li><p><strong>Distribution:</strong> Installed in Congatech RTPC and Orin AGX OS images (squashfs and repo-installer targets)</p></li></ol><p><strong>Verdict:</strong> This is a hard GPL-2.0 linkage chain from source code through shared library, through ROS node, into the shipped robot OS image. This is the single highest-priority licensing issue.</p><h3 id=\"OSSAudit:hmnd_robot-FFmpeginquest_stream_viewer.cpp\u2014HIGH(GPL-2.0,compiledbinary)\">FFmpeg in quest_stream_viewer.cpp \u2014 HIGH (GPL-2.0, compiled binary)</h3><p><strong>Direct C library linkage in</strong> <code>core/hmndlib_teleoperation/meta_quest_openxr/examples/quest_stream_viewer.cpp</code>:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"83dfa1cf-a849-46f8-aefb-db5f6909652c\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: cpp; gutter: false; theme: Confluence\" data-theme=\"Confluence\">extern &quot;C&quot; {\n#include &lt;libavcodec/avcodec.h&gt;\n#include &lt;libavutil/avutil.h&gt;\n#include &lt;libswscale/swscale.h&gt;\n}</pre>\n</div></div><p><strong>API calls:</strong> <code>avcodec_send_packet()</code>, <code>avcodec_receive_frame()</code>, <code>avcodec_find_decoder(AV_CODEC_ID_H264)</code></p><p><strong>CMake linkage:</strong> <code>pkg_check_modules(FFMPEG QUIET libavcodec libavutil libswscale)</code> \u2192 <code>target_link_libraries(${QUEST_VIEWER} PRIVATE ${FFMPEG_LIBRARIES})</code></p><p><strong>Verdict:</strong> This binary directly links ffmpeg C libraries. Since the conda-forge ffmpeg is built with GPL codecs (x264/x265), this binary becomes a GPL derivative. Must either refactor to subprocess invocation, build an LGPL-only ffmpeg, or replace with a permissive codec.</p><h3 id=\"OSSAudit:hmnd_robot-spidev\u2014MEDIUM(GPL-2.0,robothardware)\">spidev \u2014 MEDIUM (GPL-2.0, robot hardware)</h3><p><strong>Usage in</strong> <code>ros/hardware/alpha_hri/hri_control/.../led_strip_spi.py</code>:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"7cc7c057-f9a3-46cf-9cad-0020326e7ebe\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">from spidev import SpiDev</pre>\n</div></div><p>Used for SPI bus communication to WS2812 LED strips on the robot. Packaged as ROS2 node <code>led_strip_node</code>. This runs on the robot hardware at runtime.</p><p><strong>Verdict:</strong> GPL-2.0 Python module imported at runtime on robot hardware. Whether this constitutes &quot;distribution&quot; under GPL depends on how the robot is delivered to customers. If the OS image is distributed, this is a GPL compliance issue.</p><h3 id=\"OSSAudit:hmnd_robot-pygame\u2014LOW(LGPL-2.1,safewithdynamiclinking)\">pygame \u2014 LOW (LGPL-2.1, safe with dynamic linking)</h3><p><strong>Usage in:</strong></p><ul><li><p><code>ros/hardware/alpha_hri/hri_control/.../head_display.py</code> \u2014 production head display rendering</p></li><li><p><code>ros/hardware/alpha_hri/hri_control/.../icon_loader.py</code> \u2014 <code>pygame.image.load()</code>, <code>pygame.surfarray.array3d()</code></p></li></ul><p><strong>Verdict:</strong> LGPL (weak copyleft). Used in production on the robot, but dynamic linking is standard for Python packages. Safe as long as pygame itself is not modified. No action required.</p><h3 id=\"OSSAudit:hmnd_robot-pynput\u2014NONE(deaddependency)\">pynput \u2014 NONE (dead dependency)</h3><p><strong>Declared in</strong> <code>pixi.toml</code> but <strong>never imported anywhere</strong> in the codebase. Zero matches for <code>import pynput</code> or <code>from pynput</code> across the entire repository.</p><p><strong>Verdict:</strong> Dead dependency. Should be removed from pixi.toml for cleanliness.</p><hr/><h2 id=\"OSSAudit:hmnd_robot-RED\u2014GPLDependencies(StrongCopyleft)\">RED \u2014 GPL Dependencies (Strong Copyleft)</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th><th class=\"confluenceTh\"><p>Actual Usage</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p><strong>EtherLab EtherCAT</strong></p></td><td class=\"confluenceTd\"><p>custom</p></td><td class=\"confluenceTd\"><p>GPL-2.0 + LGPL-2.1</p></td><td class=\"confluenceTd\"><p>Hardware</p></td><td class=\"confluenceTd\"><p><strong>LINKED \u2192 shipped in OS image</strong></p></td><td class=\"confluenceTd\"><p>See linkage chain above. <strong>PRIMARY RISK.</strong></p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>ffmpeg</p></td><td class=\"confluenceTd\"><p>=7.1.0,&lt;8</p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>Video</p></td><td class=\"confluenceTd\"><p><strong>LINKED in quest_stream_viewer.cpp</strong></p></td><td class=\"confluenceTd\"><p>Direct C library linkage. See analysis above.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>x264</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>Video</p></td><td class=\"confluenceTd\"><p>Transitive via ffmpeg</p></td><td class=\"confluenceTd\"><p>Linked into ffmpeg build. Risk depends on ffmpeg usage.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-PYPI</p></td><td class=\"confluenceTd\"><p>spidev</p></td><td class=\"confluenceTd\"><p>=3.7,&lt;4</p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>Hardware</p></td><td class=\"confluenceTd\"><p><strong>IMPORTED at runtime</strong></p></td><td class=\"confluenceTd\"><p>SPI LED strip control on robot hardware.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>gcc</p></td><td class=\"confluenceTd\"><p>=11,&lt;12</p></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td><td class=\"confluenceTd\"><p>Build-time only</p></td><td class=\"confluenceTd\"><p>Compiler \u2014 GCC Runtime Exception applies.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>gxx</p></td><td class=\"confluenceTd\"><p>=11,&lt;12</p></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td><td class=\"confluenceTd\"><p>Build-time only</p></td><td class=\"confluenceTd\"><p>Compiler \u2014 not linked into output.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>make</p></td><td class=\"confluenceTd\"><p>=4.4.1,&lt;5</p></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td><td class=\"confluenceTd\"><p>Build-time only</p></td><td class=\"confluenceTd\"><p>Build tool \u2014 not linked.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>binutils</p></td><td class=\"confluenceTd\"><p>=11,&lt;12</p></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td><td class=\"confluenceTd\"><p>Build-time only</p></td><td class=\"confluenceTd\"><p>Assembler/linker tools \u2014 not linked.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>libstdcxx</p></td><td class=\"confluenceTd\"><p>=15.1.0,&lt;16</p></td><td class=\"confluenceTd\"><p>GPL-3.0 (w/ Runtime Exception)</p></td><td class=\"confluenceTd\"><p>Core Library</p></td><td class=\"confluenceTd\"><p>Runtime library</p></td><td class=\"confluenceTd\"><p>Exception permits proprietary linking \u2014 safe.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>libcap</p></td><td class=\"confluenceTd\"><p>=2.71,&lt;3</p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>Core Library</p></td><td class=\"confluenceTd\"><p>System library</p></td><td class=\"confluenceTd\"><p>Linux capabilities library.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>kernel-headers</p></td><td class=\"confluenceTd\"><p>=5.14.0,&lt;6</p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>Linux</p></td><td class=\"confluenceTd\"><p>Build-time only</p></td><td class=\"confluenceTd\"><p>Development headers.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>git</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>VCS</p></td><td class=\"confluenceTd\"><p>Tool only</p></td><td class=\"confluenceTd\"><p>Version control \u2014 not linked.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>shellcheck</p></td><td class=\"confluenceTd\"><p>=0.10.0,&lt;0.11</p></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Code Quality</p></td><td class=\"confluenceTd\"><p>Dev tool only</p></td><td class=\"confluenceTd\"><p>Shell linter \u2014 not linked.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_robot-YELLOW\u2014LGPL/MPLDependencies(WeakCopyleft)\">YELLOW \u2014 LGPL/MPL Dependencies (Weak Copyleft)</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th><th class=\"confluenceTh\"><p>Actual Usage</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>zeromq</p></td><td class=\"confluenceTd\"><p>=4.3.5,&lt;5</p></td><td class=\"confluenceTd\"><p>LGPL-3.0</p></td><td class=\"confluenceTd\"><p>Message Queue</p></td><td class=\"confluenceTd\"><p>Dynamic linking</p></td><td class=\"confluenceTd\"><p>Safe if dynamically linked.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>nlopt</p></td><td class=\"confluenceTd\"><p>=2.10.0,&lt;3</p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p>Optimization</p></td><td class=\"confluenceTd\"><p>Dynamic linking</p></td><td class=\"confluenceTd\"><p>Verify linking method.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>libusb</p></td><td class=\"confluenceTd\"><p>=1.0.29,&lt;2</p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p>Hardware</p></td><td class=\"confluenceTd\"><p>Dynamic linking</p></td><td class=\"confluenceTd\"><p>Typically dynamic.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>libudev</p></td><td class=\"confluenceTd\"><p>=257.4,&lt;258</p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p>Hardware</p></td><td class=\"confluenceTd\"><p>System library</p></td><td class=\"confluenceTd\"><p>Device enumeration.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>libsystemd</p></td><td class=\"confluenceTd\"><p>=257,&lt;258</p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p>Core Library</p></td><td class=\"confluenceTd\"><p>System library</p></td><td class=\"confluenceTd\"><p>systemd library.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>mesalib</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>MIT/LGPL</p></td><td class=\"confluenceTd\"><p>Graphics</p></td><td class=\"confluenceTd\"><p>Dynamic linking</p></td><td class=\"confluenceTd\"><p>OpenGL implementation.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-CONDA</p></td><td class=\"confluenceTd\"><p>eigen</p></td><td class=\"confluenceTd\"><p>=3.4.0,&lt;4</p></td><td class=\"confluenceTd\"><p>MPL-2.0</p></td><td class=\"confluenceTd\"><p>Math</p></td><td class=\"confluenceTd\"><p>Header-only</p></td><td class=\"confluenceTd\"><p>File-level copyleft only.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-PYPI</p></td><td class=\"confluenceTd\"><p>ruckig</p></td><td class=\"confluenceTd\"><p>=0.15.3,&lt;0.16</p></td><td class=\"confluenceTd\"><p>LGPL-3.0</p></td><td class=\"confluenceTd\"><p>Control</p></td><td class=\"confluenceTd\"><p>Dynamic linking</p></td><td class=\"confluenceTd\"><p>Trajectory generation. Also bundled.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-PYPI</p></td><td class=\"confluenceTd\"><p>pynput</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>LGPL-3.0</p></td><td class=\"confluenceTd\"><p>Input</p></td><td class=\"confluenceTd\"><p><strong>Never imported</strong></p></td><td class=\"confluenceTd\"><p>Dead dependency \u2014 remove from pixi.toml.</p></td></tr><tr><td class=\"confluenceTd\"><p>PIXI-PYPI</p></td><td class=\"confluenceTd\"><p>pygame</p></td><td class=\"confluenceTd\"><p>=2.6.1,&lt;3</p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p>Graphics</p></td><td class=\"confluenceTd\"><p><strong>Production use</strong></p></td><td class=\"confluenceTd\"><p>Head display + icon loading on robot. Safe (LGPL, dynamic).</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_robot-GRAY\u2014BundledThird-Party(Unknown/UnverifiedLicense)\">GRAY \u2014 Bundled Third-Party (Unknown/Unverified License)</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Location</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>nrobotics</p></td><td class=\"confluenceTd\"><p><code>core/third_party/nrobotics/</code></p></td><td class=\"confluenceTd\"><p>ARM/X86 binary distributions. No LICENSE file.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>oculus_reader</p></td><td class=\"confluenceTd\"><p><code>core/third_party/oculus_reader/</code></p></td><td class=\"confluenceTd\"><p>Meta Quest tracking reader. Apache-2.0 per README but verify.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>BehaviorTree.CPP</p></td><td class=\"confluenceTd\"><p><code>ros/third_party/BehaviorTree.CPP/</code></p></td><td class=\"confluenceTd\"><p>MIT \u2014 verified via LICENSE file.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>BehaviorTree.ROS2</p></td><td class=\"confluenceTd\"><p><code>ros/third_party/BehaviorTree.ROS2/</code></p></td><td class=\"confluenceTd\"><p>Apache-2.0 \u2014 verified.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>manus_ros_drivers</p></td><td class=\"confluenceTd\"><p><code>ros/third_party/manus_ros_drivers/</code></p></td><td class=\"confluenceTd\"><p>No LICENSE file found.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>nr_tofcam_ros_dist</p></td><td class=\"confluenceTd\"><p><code>ros/third_party/nr_tofcam_ros_dist/</code></p></td><td class=\"confluenceTd\"><p>No LICENSE file found.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>neo_* (common2, gz_worlds, msgs2, relayboard_v3, srvs2)</p></td><td class=\"confluenceTd\"><p><code>ros/third_party/neo_*/</code></p></td><td class=\"confluenceTd\"><p>Neobotix platform libs. neo_gz_worlds is Apache-2.0; others need verification.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>rox, rox_argo_kinematics</p></td><td class=\"confluenceTd\"><p><code>ros/third_party/rox*/</code></p></td><td class=\"confluenceTd\"><p>rox_argo_kinematics is BSD-3 (Neobotix). rox core has no LICENSE.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>ros2_robotiq_gripper</p></td><td class=\"confluenceTd\"><p><code>ros/third_party/ros2_robotiq_gripper/</code></p></td><td class=\"confluenceTd\"><p>BSD-3-Clause (PickNik Robotics) \u2014 verified.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>ros2_xhand</p></td><td class=\"confluenceTd\"><p><code>ros/third_party/ros2_xhand/</code></p></td><td class=\"confluenceTd\"><p>No LICENSE file found.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>serial</p></td><td class=\"confluenceTd\"><p><code>ros/third_party/serial/</code></p></td><td class=\"confluenceTd\"><p>No LICENSE file found.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>icube-ethercat-ros2</p></td><td class=\"confluenceTd\"><p><code>ros/third_party/icube-ethercat-ros2/</code></p></td><td class=\"confluenceTd\"><p>Apache-2.0 \u2014 verified.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>placo</p></td><td class=\"confluenceTd\"><p><code>core/third_party/placo/</code></p></td><td class=\"confluenceTd\"><p>MIT (Rhoban Team) \u2014 verified.</p></td></tr><tr><td class=\"confluenceTd\"><p>BUNDLED</p></td><td class=\"confluenceTd\"><p>time_optimal_trajectory_generation_py</p></td><td class=\"confluenceTd\"><p><code>core/third_party/time_optimal_trajectory_generation_py/</code></p></td><td class=\"confluenceTd\"><p>Contains pybind11 (BSD-3). Root package license unclear.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_robot-GREEN\u2014PermissiveDependencies(Safe)\">GREEN \u2014 Permissive Dependencies (Safe)</h2><h3 id=\"OSSAudit:hmnd_robot-PixiConda(Selected\u2014700+total,allpermissiveunlesslistedabove)\">Pixi Conda (Selected \u2014 700+ total, all permissive unless listed above)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>cmake</p></td><td class=\"confluenceTd\"><p>=3.30.5,&lt;4</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td></tr><tr><td class=\"confluenceTd\"><p>clangxx</p></td><td class=\"confluenceTd\"><p>=19.1.7,&lt;20</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td></tr><tr><td class=\"confluenceTd\"><p>ninja</p></td><td class=\"confluenceTd\"><p>=1.12.1,&lt;2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td></tr><tr><td class=\"confluenceTd\"><p>lld</p></td><td class=\"confluenceTd\"><p>=19.1.2,&lt;20</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Linker</p></td></tr><tr><td class=\"confluenceTd\"><p>python</p></td><td class=\"confluenceTd\"><p>=3.11.11,&lt;3.12</p></td><td class=\"confluenceTd\"><p>PSF</p></td><td class=\"confluenceTd\"><p>Runtime</p></td></tr><tr><td class=\"confluenceTd\"><p>pybind11</p></td><td class=\"confluenceTd\"><p>=2.13.6,&lt;3</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Binding</p></td></tr><tr><td class=\"confluenceTd\"><p>libboost / libboost-devel</p></td><td class=\"confluenceTd\"><p>=1.86.0,&lt;2</p></td><td class=\"confluenceTd\"><p>BSL-1.0</p></td><td class=\"confluenceTd\"><p>Core Library</p></td></tr><tr><td class=\"confluenceTd\"><p>spdlog</p></td><td class=\"confluenceTd\"><p>=1.14.0,&lt;1.15</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Logging</p></td></tr><tr><td class=\"confluenceTd\"><p>yaml-cpp</p></td><td class=\"confluenceTd\"><p>=0.8.0,&lt;0.9</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Config</p></td></tr><tr><td class=\"confluenceTd\"><p>aws-sdk-cpp</p></td><td class=\"confluenceTd\"><p>=1.11,&lt;2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>AWS</p></td></tr><tr><td class=\"confluenceTd\"><p>prometheus-cpp</p></td><td class=\"confluenceTd\"><p>=1.3.0,&lt;2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Monitoring</p></td></tr><tr><td class=\"confluenceTd\"><p>pinocchio</p></td><td class=\"confluenceTd\"><p>=3.4.0,&lt;3.5.0</p></td><td class=\"confluenceTd\"><p>BSD-2</p></td><td class=\"confluenceTd\"><p>Robot Dynamics</p></td></tr><tr><td class=\"confluenceTd\"><p>ompl</p></td><td class=\"confluenceTd\"><p>=1.6.0,&lt;2</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Motion Planning</p></td></tr><tr><td class=\"confluenceTd\"><p>opencv</p></td><td class=\"confluenceTd\"><p>=4.10.0,&lt;5</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Computer Vision</p></td></tr><tr><td class=\"confluenceTd\"><p>ceres-solver</p></td><td class=\"confluenceTd\"><p>=2.2.0,&lt;3</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Optimization</p></td></tr><tr><td class=\"confluenceTd\"><p>glog</p></td><td class=\"confluenceTd\"><p>=0.7.1,&lt;0.8</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Logging</p></td></tr><tr><td class=\"confluenceTd\"><p>gtest / gmock</p></td><td class=\"confluenceTd\"><p>=1.15.2,&lt;2</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Testing</p></td></tr><tr><td class=\"confluenceTd\"><p>flatbuffers</p></td><td class=\"confluenceTd\"><p>=24.3.0,&lt;25</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Serialization</p></td></tr><tr><td class=\"confluenceTd\"><p>libopentelemetry-cpp</p></td><td class=\"confluenceTd\"><p>=1.18.0,&lt;2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Tracing</p></td></tr><tr><td class=\"confluenceTd\"><p>ros-humble-desktop</p></td><td class=\"confluenceTd\"><p>=0.10.0,&lt;0.11</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>ROS 2</p></td></tr><tr><td class=\"confluenceTd\"><p>ros-humble-navigation2</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>ROS 2 Navigation</p></td></tr><tr><td class=\"confluenceTd\"><p>ros-humble-slam-toolbox</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>SLAM</p></td></tr><tr><td class=\"confluenceTd\"><p>ros-humble-foxglove-bridge</p></td><td class=\"confluenceTd\"><p>=0.8.2,&lt;0.9</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Visualization</p></td></tr><tr><td class=\"confluenceTd\"><p>h5py</p></td><td class=\"confluenceTd\"><p>=3.13.0,&lt;4</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>postgresql</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>PostgreSQL License</p></td><td class=\"confluenceTd\"><p>Database</p></td></tr><tr><td class=\"confluenceTd\"><p>rust</p></td><td class=\"confluenceTd\"><p>=1.90.0,&lt;1.91</p></td><td class=\"confluenceTd\"><p>MIT/Apache-2.0</p></td><td class=\"confluenceTd\"><p>Language</p></td></tr><tr><td class=\"confluenceTd\"><p>nodejs</p></td><td class=\"confluenceTd\"><p>=24.10.0,&lt;24.11</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>JS Runtime</p></td></tr><tr><td class=\"confluenceTd\"><p>glfw</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>Zlib</p></td><td class=\"confluenceTd\"><p>Graphics</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_robot-PixiPyPI(Selected)\">Pixi PyPI (Selected)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>grpcio / grpcio-tools</p></td><td class=\"confluenceTd\"><p>=1.78.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>RPC</p></td></tr><tr><td class=\"confluenceTd\"><p>protobuf</p></td><td class=\"confluenceTd\"><p>=6.33.5</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Serialization</p></td></tr><tr><td class=\"confluenceTd\"><p>bleak</p></td><td class=\"confluenceTd\"><p>=0.22</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Bluetooth</p></td></tr><tr><td class=\"confluenceTd\"><p>dbus-next</p></td><td class=\"confluenceTd\"><p>=0.2.3</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>IPC</p></td></tr><tr><td class=\"confluenceTd\"><p>pyserial</p></td><td class=\"confluenceTd\"><p>=3.5</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Serial</p></td></tr><tr><td class=\"confluenceTd\"><p>websockets</p></td><td class=\"confluenceTd\"><p>=15.0.1</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Networking</p></td></tr><tr><td class=\"confluenceTd\"><p>fastapi</p></td><td class=\"confluenceTd\"><p>=0.68.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Web Framework</p></td></tr><tr><td class=\"confluenceTd\"><p>uvicorn</p></td><td class=\"confluenceTd\"><p>=0.15.0</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Web Server</p></td></tr><tr><td class=\"confluenceTd\"><p>pydantic</p></td><td class=\"confluenceTd\"><p>=1.8.2</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Validation</p></td></tr><tr><td class=\"confluenceTd\"><p>hydra-core</p></td><td class=\"confluenceTd\"><p>=1.3.2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Config</p></td></tr><tr><td class=\"confluenceTd\"><p>mujoco</p></td><td class=\"confluenceTd\"><p>=3.3.2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Simulation</p></td></tr><tr><td class=\"confluenceTd\"><p>open3d</p></td><td class=\"confluenceTd\"><p>&lt;=0.19.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>3D Processing</p></td></tr><tr><td class=\"confluenceTd\"><p>imageio</p></td><td class=\"confluenceTd\"><p>=2.37.0</p></td><td class=\"confluenceTd\"><p>BSD-2</p></td><td class=\"confluenceTd\"><p>Image I/O</p></td></tr><tr><td class=\"confluenceTd\"><p>requests</p></td><td class=\"confluenceTd\"><p>=2.32.4</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>HTTP</p></td></tr><tr><td class=\"confluenceTd\"><p>openai</p></td><td class=\"confluenceTd\"><p>=1.52.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>AI</p></td></tr><tr><td class=\"confluenceTd\"><p>dvc</p></td><td class=\"confluenceTd\"><p>*[s3]</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Data Versioning</p></td></tr><tr><td class=\"confluenceTd\"><p>jupyterlab</p></td><td class=\"confluenceTd\"><p>=4.4.5</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Notebook</p></td></tr><tr><td class=\"confluenceTd\"><p>rich</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Terminal</p></td></tr><tr><td class=\"confluenceTd\"><p>tqdm</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>MIT/MPL</p></td><td class=\"confluenceTd\"><p>Progress</p></td></tr><tr><td class=\"confluenceTd\"><p>trimesh</p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Geometry</p></td></tr><tr><td class=\"confluenceTd\"><p>flask</p></td><td class=\"confluenceTd\"><p>=3.1.0</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Web Framework</p></td></tr><tr><td class=\"confluenceTd\"><p>opentelemetry-api/sdk/exporter</p></td><td class=\"confluenceTd\"><p>=1.20.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Tracing</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_robot-Rust/Cargo(Allpermissive)\">Rust / Cargo (All permissive)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>anyhow</p></td><td class=\"confluenceTd\"><p>1.0.99</p></td><td class=\"confluenceTd\"><p>MIT/Apache-2.0</p></td><td class=\"confluenceTd\"><p>Error Handling</p></td></tr><tr><td class=\"confluenceTd\"><p>axum</p></td><td class=\"confluenceTd\"><p>0.8.4</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Web Framework</p></td></tr><tr><td class=\"confluenceTd\"><p>chrono</p></td><td class=\"confluenceTd\"><p>0.4.42</p></td><td class=\"confluenceTd\"><p>MIT/Apache-2.0</p></td><td class=\"confluenceTd\"><p>Time</p></td></tr><tr><td class=\"confluenceTd\"><p>clap</p></td><td class=\"confluenceTd\"><p>4.5.47</p></td><td class=\"confluenceTd\"><p>MIT/Apache-2.0</p></td><td class=\"confluenceTd\"><p>CLI</p></td></tr><tr><td class=\"confluenceTd\"><p>git2</p></td><td class=\"confluenceTd\"><p>0.20.2</p></td><td class=\"confluenceTd\"><p>MIT/Apache-2.0</p></td><td class=\"confluenceTd\"><p>VCS</p></td></tr><tr><td class=\"confluenceTd\"><p>jsonschema</p></td><td class=\"confluenceTd\"><p>0.33.0</p></td><td class=\"confluenceTd\"><p>MIT/Apache-2.0</p></td><td class=\"confluenceTd\"><p>Validation</p></td></tr><tr><td class=\"confluenceTd\"><p>nix</p></td><td class=\"confluenceTd\"><p>0.30.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>System</p></td></tr><tr><td class=\"confluenceTd\"><p>serde / serde_json</p></td><td class=\"confluenceTd\"><p>1.0.225</p></td><td class=\"confluenceTd\"><p>MIT/Apache-2.0</p></td><td class=\"confluenceTd\"><p>Serialization</p></td></tr><tr><td class=\"confluenceTd\"><p>tempfile</p></td><td class=\"confluenceTd\"><p>3.22.0</p></td><td class=\"confluenceTd\"><p>MIT/Apache-2.0</p></td><td class=\"confluenceTd\"><p>Filesystem</p></td></tr><tr><td class=\"confluenceTd\"><p>thiserror</p></td><td class=\"confluenceTd\"><p>2.0.16</p></td><td class=\"confluenceTd\"><p>MIT/Apache-2.0</p></td><td class=\"confluenceTd\"><p>Error Handling</p></td></tr><tr><td class=\"confluenceTd\"><p>tokio / tokio-util</p></td><td class=\"confluenceTd\"><p>1.47.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Async Runtime</p></td></tr><tr><td class=\"confluenceTd\"><p>tracing / tracing-subscriber</p></td><td class=\"confluenceTd\"><p>0.1.41</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Tracing</p></td></tr><tr><td class=\"confluenceTd\"><p>utoipa / utoipa-axum / utoipa-swagger-ui</p></td><td class=\"confluenceTd\"><p>5.4+</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>API Docs</p></td></tr><tr><td class=\"confluenceTd\"><p>uefi</p></td><td class=\"confluenceTd\"><p>0.34</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Bootloader</p></td></tr><tr><td class=\"confluenceTd\"><p>log</p></td><td class=\"confluenceTd\"><p>0.4</p></td><td class=\"confluenceTd\"><p>MIT/Apache-2.0</p></td><td class=\"confluenceTd\"><p>Logging</p></td></tr><tr><td class=\"confluenceTd\"><p>libfuzzer-sys</p></td><td class=\"confluenceTd\"><p>0.4</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Testing</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_robot-npm/Node.js(Allpermissive\u2014sockpuppetfrontend)\">npm / Node.js (All permissive \u2014 sockpuppet frontend)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>react / react-dom</p></td><td class=\"confluenceTd\"><p>^19.0.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Framework</p></td></tr><tr><td class=\"confluenceTd\"><p>next</p></td><td class=\"confluenceTd\"><p>^15.0.3</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Framework</p></td></tr><tr><td class=\"confluenceTd\"><p>@radix-ui/*</p></td><td class=\"confluenceTd\"><p>various</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>UI Components</p></td></tr><tr><td class=\"confluenceTd\"><p>@tanstack/react-query</p></td><td class=\"confluenceTd\"><p>^5.59.14</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Data Fetching</p></td></tr><tr><td class=\"confluenceTd\"><p>zustand</p></td><td class=\"confluenceTd\"><p>^4.5.5</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>State Management</p></td></tr><tr><td class=\"confluenceTd\"><p>zod</p></td><td class=\"confluenceTd\"><p>^3.23.8</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Validation</p></td></tr><tr><td class=\"confluenceTd\"><p>tailwindcss</p></td><td class=\"confluenceTd\"><p>^3.4.14</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>CSS</p></td></tr><tr><td class=\"confluenceTd\"><p>lucide-react</p></td><td class=\"confluenceTd\"><p>^0.462.0</p></td><td class=\"confluenceTd\"><p>ISC</p></td><td class=\"confluenceTd\"><p>Icons</p></td></tr><tr><td class=\"confluenceTd\"><p>typescript</p></td><td class=\"confluenceTd\"><p>^5.6.3</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Language</p></td></tr><tr><td class=\"confluenceTd\"><p>vitest</p></td><td class=\"confluenceTd\"><p>^2.1.4</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Testing</p></td></tr><tr><td class=\"confluenceTd\"><p>eslint</p></td><td class=\"confluenceTd\"><p>^9.12.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Linting</p></td></tr></tbody></table></div>"
        },
        {
          "id": "1840054289",
          "title": "OSS Licensing \"Audit\"",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1840054289",
          "last_modified": "2026-04-08T10:19:24.694Z",
          "created_at": "2026-04-08T09:33:09.979Z",
          "body_html": "<h1 id=\"OSSLicensing&quot;Audit&quot;-OSSDependencyLicenseAudit\">OSS Dependency License Audit</h1><p><strong>Date:</strong> April 8, 2026    <br/><strong>Scope:</strong> All direct, transitive, and bundled third-party dependencies across Rust (Cargo), Python (pixi/uv/pip), Node.js (npm), and Bazel ecosystems    <br/><strong>Method:</strong> Automated scan of all <code>pixi.toml</code>, <code>pixi.lock</code>, <code>uv.lock</code>, <code>pyproject.toml</code>, <code>requirements.txt</code>, <code>package.json</code>, <code>Cargo.toml</code>, <code>Cargo.lock</code>, <code>MODULE.bazel</code>, and <code>third_party/</code> directories</p><hr/><h2 id=\"OSSLicensing&quot;Audit&quot;-CriticalFindings\u2014ActionRequired\">Critical Findings \u2014 Action Required</h2><h3 id=\"OSSLicensing&quot;Audit&quot;-ActualUsageAnalysis\">Actual Usage Analysis</h3><p>The following analysis traces each RED dependency to its actual usage in code \u2014 determining whether it is compiled/linked into shipped binaries, used only at dev/build time, or declared but never actually imported.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Component</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Shipped in Binary?</p></th><th class=\"confluenceTh\"><p>Actual Usage</p></th><th class=\"confluenceTh\"><p>Real Risk</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>EtherLab EtherCAT</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p><strong><span class=\"inline-comment-marker\" data-ref=\"cfcea96b-0f37-4cf2-8c6f-d63d558c0909\">YES</span> \u2014 robot OS image</strong></p></td><td class=\"confluenceTd\"><p>Compiled to <code>libethercat.so</code> \u2192 linked by <code>ethercat_interface</code> \u2192 linked by <code>alpha_universal_driver</code> \u2192 packaged as <code>hmnd-ethercat</code> + <code>hmnd-ethercat-modules</code> Debian packages \u2192 installed in Congatech RTPC and Orin AGX OS images</p></td><td class=\"confluenceTd\"><p><strong>CRITICAL</strong> \u2014 hard GPL linkage chain into shipped robot binaries. Must resolve before commercial distribution.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>FFmpeg (quest_stream_viewer.cpp)</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p><strong><span class=\"inline-comment-marker\" data-ref=\"cb97e799-46a3-4435-8dc1-cb6c165e0f5d\">YES</span> \u2014 compiled binary</strong></p></td><td class=\"confluenceTd\"><p>Direct C library linkage: <code>#include &lt;libavcodec/avcodec.h&gt;</code>, calls <code>avcodec_send_packet()</code>, <code>avcodec_receive_frame()</code>, <code>avcodec_find_decoder(AV_CODEC_ID_H264)</code>. CMake: <code>pkg_check_modules(FFMPEG)</code> \u2192 <code>target_link_libraries(${QUEST_VIEWER} PRIVATE ${FFMPEG_LIBRARIES})</code></p></td><td class=\"confluenceTd\"><p><strong>HIGH</strong> \u2014 direct library linkage in <code>hmnd_robot/core/hmndlib_teleoperation/meta_quest_openxr/examples/quest_stream_viewer.cpp</code>. GPL infection of the binary.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>FFmpeg/PyAV (lerobot)</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>No \u2014 training only</p></td><td class=\"confluenceTd\"><p><code>import av</code> in <code>hmnd_training/third_party/lerobot/src/lerobot/datasets/video_utils.py</code>. PyAV uses C bindings to libavcodec (GPL trigger), but this code only runs in training environments, never distributed.</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong> \u2014 GPL trigger exists but training code is not distributed externally.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>FFmpeg CLI (flywheel/training scripts)</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>No \u2014 subprocess only</p></td><td class=\"confluenceTd\"><p><code>subprocess.run([&quot;ffmpeg&quot;, ...])</code> in <code>hmnd_flywheel/databricks/5_mcap_to_mp4/episode_utils.py</code> and <code>hmnd_training/tools/data/agibot/scripts/agibot_hdf5_to_lerobot_v3.py</code>. Invoked as external CLI process.</p></td><td class=\"confluenceTd\"><p><strong>NONE</strong> \u2014 subprocess invocation does not trigger GPL copyleft.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>spidev</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p><strong><span class=\"inline-comment-marker\" data-ref=\"953484b9-7a66-4c21-917f-6618135b8cfa\">YES</span> \u2014 robot hardware</strong></p></td><td class=\"confluenceTd\"><p><code>from spidev import SpiDev</code> in <code>hmnd_robot/ros/hardware/alpha_hri/hri_control/.../led_strip_spi.py</code>. Used for SPI bus communication to WS2812 LED strips. Packaged as ROS2 node <code>led_strip_node</code>.</p></td><td class=\"confluenceTd\"><p><strong>MEDIUM</strong> \u2014 GPL Python module imported at runtime on robot hardware. Runs on the robot only (not distributed as a general product).</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>pygame</strong></p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p><strong>YES \u2014 robot hardware</strong></p></td><td class=\"confluenceTd\"><p><code>import pygame</code> in <code>hmnd_robot/ros/hardware/alpha_hri/hri_control/.../head_display.py</code> and <code>icon_loader.py</code>. Used for production head display rendering on robot.</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong> \u2014 LGPL (weak copyleft). Dynamic linking is standard. Safe if unmodified and dynamically linked.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>PyQt5</strong></p></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p><strong>No \u2014 dev script only</strong></p></td><td class=\"confluenceTd\"><p>Only imported in <code>hmnd_wholebody/scripts/sys-id/presentation/simple_visualiser.py</code> \u2014 a developer-only visualization tool. Not listed in any <code>setup.py</code>, not part of any installed package, not in any production pipeline.</p></td><td class=\"confluenceTd\"><p><strong>NONE for distribution</strong> \u2014 dev-only script. Could still be replaced with PySide6 for cleanliness, but not a distribution risk.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>pynput</strong></p></td><td class=\"confluenceTd\"><p>LGPL-3.0</p></td><td class=\"confluenceTd\"><p><strong>No \u2014 dead dependency</strong></p></td><td class=\"confluenceTd\"><p>Declared in <code>hmnd_robot/pixi.toml</code> but never imported anywhere in the codebase. Zero <code>import pynput</code> or <code>from pynput</code> matches.</p></td><td class=\"confluenceTd\"><p><strong>NONE</strong> \u2014 dead dependency. Can be safely removed from pixi.toml.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>readline</strong></p></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>No \u2014 transitive only</p></td><td class=\"confluenceTd\"><p>Pulled in by IPython via pixi.lock. Never directly imported in any HMND code. Only active when a developer uses the IPython REPL interactively.</p></td><td class=\"confluenceTd\"><p><strong>NONE</strong> \u2014 transitive dev dependency, never imported or distributed.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>x264/x265</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>Transitive via ffmpeg</p></td><td class=\"confluenceTd\"><p>Linked into the conda-forge ffmpeg build. Risk depends on how ffmpeg is consumed (see rows above).</p></td><td class=\"confluenceTd\"><p>Varies \u2014 <strong>HIGH</strong> where ffmpeg is library-linked, <strong>NONE</strong> where ffmpeg is subprocess-only.</p></td></tr></tbody></table></div><h3 id=\"OSSLicensing&quot;Audit&quot;-RevisedRiskAssessment\">Revised Risk Assessment</h3><p>Based on actual code usage tracing, the effective risk levels differ from the initial declaration-based scan:</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Module</p></th><th class=\"confluenceTh\"><p>Initial Risk</p></th><th class=\"confluenceTh\"><p>Revised Risk</p></th><th class=\"confluenceTh\"><p>Reason</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_robot</strong></p></td><td class=\"confluenceTd\"><p>HIGH</p></td><td class=\"confluenceTd\"><p><strong>HIGH (confirmed)</strong></p></td><td class=\"confluenceTd\"><p>EtherCAT GPL linkage chain is real and ships in OS image. quest_stream_viewer.cpp links ffmpeg directly.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_training</strong></p></td><td class=\"confluenceTd\"><p>HIGH</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>ffmpeg usage is either PyAV (training-only, not distributed) or subprocess (safe). readline is transitive/unused. All RED items are build tools with GCC Runtime Exception.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_wholebody</strong></p></td><td class=\"confluenceTd\"><p>HIGH</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>PyQt5 is only used in a dev-only script, not in any distributed package.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_locomotion</strong></p></td><td class=\"confluenceTd\"><p>MEDIUM</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>LGPL deps only (paramiko, psycopg2). Dynamic linking is standard.</p></td></tr></tbody></table></div><hr/><h3 id=\"OSSLicensing&quot;Audit&quot;-RED:StrongCopyleft(GPL)\u2014LinkedintoDistributedBinaries\">RED: Strong Copyleft (GPL) \u2014 Linked into Distributed Binaries</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Component</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Module(s)</p></th><th class=\"confluenceTh\"><p>Risk</p></th><th class=\"confluenceTh\"><p>Suggested Action</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>EtherLab EtherCAT</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0 + LGPL-2.1</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code> (bundled source in <code>core/third_party/ethercat/</code>)</p></td><td class=\"confluenceTd\"><p>Bundled and compiled into robot binaries. GPL-2.0 requires entire linked work to be GPL-compatible if distributed.</p></td><td class=\"confluenceTd\"><p>Isolate into a separate process communicating via IPC, or obtain a commercial license, or evaluate SOEM (dual GPL/commercial).</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>x264 / libx264</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code>, <code>hmnd_training</code> (via pixi conda)</p></td><td class=\"confluenceTd\"><p>H.264 video codec. If linked into any binary, that binary becomes a GPL derivative.</p></td><td class=\"confluenceTd\"><p>Replace with libvpx (BSD) for VP8/VP9, use hardware encoding APIs, or ensure ffmpeg is invoked as a subprocess only.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>x265 / libx265</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p><code>hmnd_training</code> (via pixi conda)</p></td><td class=\"confluenceTd\"><p>H.265 video codec. Same viral risk as x264.</p></td><td class=\"confluenceTd\"><p>Same as above \u2014 replace or isolate.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>FFmpeg</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0 (when built with GPL codecs)</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code> (7.1+), <code>hmnd_training</code> (7.1.1), <code>hmnd_flywheel</code> (via pixi)</p></td><td class=\"confluenceTd\"><p>conda-forge builds include GPL codecs (x264, x265). Core libs are LGPL, but the full package is GPL.</p></td><td class=\"confluenceTd\"><p><strong>quest_stream_viewer.cpp</strong> directly links ffmpeg C libraries \u2014 must refactor to subprocess or build LGPL-only ffmpeg. CLI subprocess usage in flywheel/training is safe.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>PyQt5</strong></p></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p><code>hmnd_wholebody</code> (dev script only)</p></td><td class=\"confluenceTd\"><p><del>Any application linking PyQt5 must be distributed under GPL-3.0.</del> <strong>REVISED:</strong> Only used in <code>scripts/sys-id/presentation/simple_visualiser.py</code> \u2014 a dev-only visualization tool, not in any <a href=\"http://setup.py\" class=\"external-link\" rel=\"nofollow\">setup.py</a> or distributed package.</p></td><td class=\"confluenceTd\"><p>Low priority. Replace with PySide6 (LGPL-3.0) for cleanliness, but this is not a distribution risk.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>spidev</strong></p></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code> (PyPI)</p></td><td class=\"confluenceTd\"><p>SPI device interface for hardware. Links into Python runtime on robot.</p></td><td class=\"confluenceTd\"><p>Evaluate if this runs only on the robot (not distributed externally) or replace with a permissive SPI library.</p></td></tr></tbody></table></div><h3 id=\"OSSLicensing&quot;Audit&quot;-YELLOW:WeakCopyleft(LGPL/MPL)\u2014MonitorforStaticLinking\">YELLOW: Weak Copyleft (LGPL/MPL) \u2014 Monitor for Static Linking</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Component</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Module(s)</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>zeromq / libzmq</strong></p></td><td class=\"confluenceTd\"><p>LGPL-3.0</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code></p></td><td class=\"confluenceTd\"><p>Safe if dynamically linked. Static linking requires providing object files for relinking.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>nlopt</strong></p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code></p></td><td class=\"confluenceTd\"><p>Nonlinear optimization. Same dynamic vs static linking concern.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>ruckig</strong></p></td><td class=\"confluenceTd\"><p>LGPL-3.0</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code> (bundled + pixi)</p></td><td class=\"confluenceTd\"><p>Trajectory generation. Verify linking method.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>libusb</strong></p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code></p></td><td class=\"confluenceTd\"><p>USB device library. Typically dynamically linked \u2014 safe.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>libudev / libsystemd</strong></p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code></p></td><td class=\"confluenceTd\"><p>System libraries. Dynamic linking is standard.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>pynput</strong></p></td><td class=\"confluenceTd\"><p>LGPL-3.0</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code></p></td><td class=\"confluenceTd\"><p><del>Keyboard/mouse input.</del> <strong>REVISED:</strong> Dead dependency \u2014 declared in pixi.toml but never imported in any code. Can be removed.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>pygame</strong></p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p><code>hmnd_robot</code>, <code>hmnd_design</code></p></td><td class=\"confluenceTd\"><p>Used in production head display (<code>head_display.py</code>, <code>icon_loader.py</code>). LGPL \u2014 safe with dynamic linking.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>paramiko</strong></p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p><code>hmnd_locomotion</code></p></td><td class=\"confluenceTd\"><p>SSH library. Must disclose source if modified.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>psycopg2-binary</strong></p></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p><code>hmnd_locomotion</code></p></td><td class=\"confluenceTd\"><p>PostgreSQL driver. Must disclose source if modified.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>Eigen</strong></p></td><td class=\"confluenceTd\"><p>MPL-2.0</p></td><td class=\"confluenceTd\"><p>Transitive (via pinocchio, ceres, etc.)</p></td><td class=\"confluenceTd\"><p>File-level copyleft only \u2014 must share modifications to Eigen source files, not your code.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>glib / gtk3 / pango / librsvg</strong></p></td><td class=\"confluenceTd\"><p>LGPL-2.0+</p></td><td class=\"confluenceTd\"><p><code>hmnd_training</code> (transitive via pixi.lock)</p></td><td class=\"confluenceTd\"><p>GUI/text rendering stack. Typically dynamically linked.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>GnuTLS</strong></p></td><td class=\"confluenceTd\"><p>LGPL-2.1 (or GPL-3.0)</p></td><td class=\"confluenceTd\"><p><code>hmnd_training</code> (transitive via pixi.lock)</p></td><td class=\"confluenceTd\"><p>TLS library. Verify LGPL variant is used, not GPL.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>readline</strong></p></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p><code>hmnd_training</code> (transitive via IPython in pixi.lock)</p></td><td class=\"confluenceTd\"><p><strong>REVISED:</strong> Never directly imported in any HMND code. Transitive dependency of IPython \u2014 only active in interactive REPL sessions. Not a distribution risk.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>Qt6</strong></p></td><td class=\"confluenceTd\"><p>LGPL-3.0</p></td><td class=\"confluenceTd\"><p><code>hmnd_training</code> (transitive via pixi.lock)</p></td><td class=\"confluenceTd\"><p>Verify not linked into distributed binaries.</p></td></tr></tbody></table></div><h3 id=\"OSSLicensing&quot;Audit&quot;-GRAY:NoLicenseFileFound\u2014NeedsInvestigation\">GRAY: No License File Found \u2014 Needs Investigation</h3><p>These bundled third-party components have <strong>no LICENSE or COPYING file</strong> in the repository:</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Component</p></th><th class=\"confluenceTh\"><p>Location</p></th><th class=\"confluenceTh\"><p>What It Is</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>nrobotics</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_robot/core/third_party/nrobotics/</code></p></td><td class=\"confluenceTd\"><p>ARM/X86 binary distributions</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>xdof_sdk</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_training/third_party/xdof_sdk/</code></p></td><td class=\"confluenceTd\"><p>X-DOF hand SDK</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>manus_ros_drivers</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_robot/ros/third_party/manus_ros_drivers/</code></p></td><td class=\"confluenceTd\"><p>Manus hand tracking drivers</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>nr_tofcam_ros_dist</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_robot/ros/third_party/nr_tofcam_ros_dist/</code></p></td><td class=\"confluenceTd\"><p>Time-of-flight camera ROS driver</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>rox</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_robot/ros/third_party/rox/</code></p></td><td class=\"confluenceTd\"><p>Rox platform core libraries</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>ros2_xhand</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_robot/ros/third_party/ros2_xhand/</code></p></td><td class=\"confluenceTd\"><p>X-hand gripper ROS2 package</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>serial</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_robot/ros/third_party/serial/</code></p></td><td class=\"confluenceTd\"><p>Serial communication library</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>robocasa</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_training/third_party/robocasa/</code></p></td><td class=\"confluenceTd\"><p>Kitchen sim benchmark \u2014 no license in <a href=\"http://setup.py\" class=\"external-link\" rel=\"nofollow\">setup.py</a></p></td></tr></tbody></table></div><h3 id=\"OSSLicensing&quot;Audit&quot;-BLUE:Proprietary\u2014RedistributionTermsApply\">BLUE: Proprietary \u2014 Redistribution Terms Apply</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Component</p></th><th class=\"confluenceTh\"><p>Module(s)</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>NVIDIA Isaac Sim</strong> (4.5\u20135.1)</p></td><td class=\"confluenceTd\"><p><code>hmnd_locomotion</code>, <code>hmnd_wholebody</code>, <code>hmnd_sim</code>, <code>hmnd_training</code></p></td><td class=\"confluenceTd\"><p>Requires NVIDIA EULA. Cannot redistribute without permission.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>NVIDIA CUDA</strong> (12.1\u201313.0)</p></td><td class=\"confluenceTd\"><p><code>hmnd_training</code>, <code>hmnd_wholebody</code>, <code>hmnd_locomotion</code></p></td><td class=\"confluenceTd\"><p>Redistributable under CUDA EULA terms.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>egl_probe</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_locomotion</code></p></td><td class=\"confluenceTd\"><p>NVIDIA proprietary component.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>databricks-sql-connector</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_flywheel</code></p></td><td class=\"confluenceTd\"><p>Databricks proprietary.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>google-genai</strong></p></td><td class=\"confluenceTd\"><p><code>hmnd_flywheel</code></p></td><td class=\"confluenceTd\"><p>Google proprietary SDK.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSLicensing&quot;Audit&quot;-RiskSummarybyModule\">Risk Summary by Module</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Module</p></th><th class=\"confluenceTh\"><p>GREEN</p></th><th class=\"confluenceTh\"><p>YELLOW</p></th><th class=\"confluenceTh\"><p>RED</p></th><th class=\"confluenceTh\"><p>BLUE</p></th><th class=\"confluenceTh\"><p>GRAY</p></th><th class=\"confluenceTh\"><p>Overall Risk</p></th><th class=\"confluenceTh\"><p>Key Concern</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_robot</strong></p></td><td class=\"confluenceTd\"><p>700+</p></td><td class=\"confluenceTd\"><p>10</p></td><td class=\"confluenceTd\"><p>12</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>8</p></td><td class=\"confluenceTd\"><p><strong>HIGH</strong></p></td><td class=\"confluenceTd\"><p>EtherCAT GPL linkage ships in OS image. quest_stream_viewer.cpp links ffmpeg. spidev GPL on robot hardware.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_training</strong></p></td><td class=\"confluenceTd\"><p>83</p></td><td class=\"confluenceTd\"><p>39</p></td><td class=\"confluenceTd\"><p>51</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>2</p></td><td class=\"confluenceTd\"><p><strong>LOW (revised)</strong></p></td><td class=\"confluenceTd\"><p>ffmpeg used via PyAV (training-only) or subprocess (safe). readline transitive/unused. All other REDs are build tools with GCC Runtime Exception.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_wholebody</strong></p></td><td class=\"confluenceTd\"><p>19</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>2</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p><strong>LOW (revised)</strong></p></td><td class=\"confluenceTd\"><p>PyQt5 only in dev-only script (<code>scripts/sys-id/presentation/simple_visualiser.py</code>), not in any distributed package.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_locomotion</strong></p></td><td class=\"confluenceTd\"><p>73</p></td><td class=\"confluenceTd\"><p>2</p></td><td class=\"confluenceTd\"><p>4</p></td><td class=\"confluenceTd\"><p>2</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>LGPL deps only (paramiko, psycopg2). Dynamic linking standard. isaacsim (proprietary).</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_sim</strong></p></td><td class=\"confluenceTd\"><p>32</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>3</p></td><td class=\"confluenceTd\"><p>2</p></td><td class=\"confluenceTd\"><p>1</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>Build tools only (gcc/gxx/make). isaacsim (proprietary).</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_flywheel</strong></p></td><td class=\"confluenceTd\"><p>64</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>2</p></td><td class=\"confluenceTd\"><p>12</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>No copyleft. ffmpeg via subprocess only. Some unknown licenses on npm devDeps.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_fleet</strong></p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>1</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>Minimal external deps.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_services</strong></p></td><td class=\"confluenceTd\"><p>11</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>All permissive.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_update</strong></p></td><td class=\"confluenceTd\"><p>9</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>All permissive.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>hmnd_design</strong></p></td><td class=\"confluenceTd\"><p>38</p></td><td class=\"confluenceTd\"><p>1</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>pygame (LGPL) in beta-hri-display only.</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>Root / Bazel</strong></p></td><td class=\"confluenceTd\"><p>21</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p><strong>LOW</strong></p></td><td class=\"confluenceTd\"><p>All permissive (Apache-2.0, MIT, BSD, BSL-1.0).</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSLicensing&quot;Audit&quot;-RecommendedActions\">Recommended Actions</h2><p><strong>Priority 1 \u2014 Address before any commercial distribution:</strong></p><ol start=\"1\"><li><p><strong>EtherCAT (GPL-2.0):</strong> This is the #1 issue. The GPL linkage chain is confirmed: bundled source \u2192 <code>libethercat.so</code> \u2192 <code>ethercat_interface</code> \u2192 <code>alpha_universal_driver</code> \u2192 Debian packages \u2192 robot OS image. Isolate into a separate process behind IPC, obtain a commercial license from EtherLab/Beckhoff, or evaluate SOEM as an alternative.</p></li><li><p><strong>FFmpeg in quest_stream_viewer.cpp:</strong> Direct C library linkage (<code>libavcodec</code>, <code>libavutil</code>, <code>libswscale</code>) makes this binary a GPL derivative. Refactor to use ffmpeg as a subprocess, build an LGPL-only ffmpeg (without x264/x265), or replace with libvpx (BSD) for VP8/VP9.</p></li></ol><p><strong>Priority 2 \u2014 Evaluate before external release:</strong></p><ol start=\"3\"><li><p><strong>spidev (GPL-2.0) on robot hardware:</strong> Used in LED strip control via SPI. Evaluate whether the robot OS image constitutes &quot;distribution&quot; under GPL. If so, replace with a permissive SPI library or provide GPL source compliance.</p></li><li><p><strong>Obtain license files</strong> for the 8 bundled components with no license (nrobotics, xdof_sdk, manus_ros_drivers, nr_tofcam_ros_dist, rox, ros2_xhand, serial, robocasa).</p></li><li><p><strong>Verify LGPL dynamic linking</strong> for zeromq, nlopt, ruckig, libusb, libudev. Ensure no static linking occurs in production builds.</p></li><li><p><strong>Verify NVIDIA redistribution terms</strong> for Isaac Sim, CUDA, and egl_probe.</p></li></ol><p><strong>Priority 3 \u2014 Housekeeping:</strong></p><ol start=\"7\"><li><p><strong>Remove dead dependency </strong><code>pynput</code> from <code>hmnd_robot/pixi.toml</code> \u2014 declared but never imported.</p></li><li><p><strong>Replace PyQt5 with PySide6</strong> in <code>hmnd_wholebody/pixi.toml</code> for cleanliness, even though it's dev-only.</p></li><li><p><strong>Document the GCC Runtime Library Exception</strong> applicability for all C++ binaries. libgcc, libstdc++, libgomp are GPL-3.0 but the Runtime Exception permits linking into proprietary code.</p></li><li><p><strong>Audit build-only vs runtime dependencies.</strong> Many RED items (gcc, gxx, make, shellcheck, pylint, git, kernel-headers) are build/dev tools that never ship \u2014 these are non-issues for distribution.</p></li></ol><hr/><h2 id=\"OSSLicensing&quot;Audit&quot;-Sub-Pages\">Sub-Pages</h2><p>Detailed per-dependency tables for each module are available as child pages below.</p>"
        },
        {
          "id": "1839693858",
          "title": "OSS Audit: hmnd_design, hmnd_playground, Root/Bazel",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1839693858",
          "last_modified": "2026-04-08T09:52:20.172Z",
          "created_at": "2026-04-08T09:52:20.172Z",
          "body_html": "<h1 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-hmnd_design,hmnd_playground,Root/Bazel\u2014DependencyLicenseAudit\">hmnd_design, hmnd_playground, Root/Bazel \u2014 Dependency License Audit</h1><p><strong>Risk Level: LOW</strong>  <br/><strong>Key Concerns:</strong> pygame (LGPL-2.1) in hmnd_design beta-hri-display; matplotlib (LGPL components) in playground projects</p><hr/><h2 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-hmnd_design\">hmnd_design</h2><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-data-collection-app(Node.js\u2014package.json)\">data-collection-app (Node.js \u2014 package.json)</h3><p>All 36 dependencies are <strong>MIT or Apache-2.0</strong>. No copyleft issues.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>@emotion/react</p></td><td class=\"confluenceTd\"><p>^11.14.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Styling</p></td></tr><tr><td class=\"confluenceTd\"><p>@emotion/styled</p></td><td class=\"confluenceTd\"><p>^11.14.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Styling</p></td></tr><tr><td class=\"confluenceTd\"><p>@mui/icons-material</p></td><td class=\"confluenceTd\"><p>^7.3.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>UI</p></td></tr><tr><td class=\"confluenceTd\"><p>@mui/material</p></td><td class=\"confluenceTd\"><p>^7.3.2</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>UI</p></td></tr><tr><td class=\"confluenceTd\"><p>@mui/x-charts</p></td><td class=\"confluenceTd\"><p>^8.11.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Charts</p></td></tr><tr><td class=\"confluenceTd\"><p>@mui/x-data-grid</p></td><td class=\"confluenceTd\"><p>^8.11.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Data Grid</p></td></tr><tr><td class=\"confluenceTd\"><p>@mui/x-date-pickers</p></td><td class=\"confluenceTd\"><p>^8.11.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Date Picker</p></td></tr><tr><td class=\"confluenceTd\"><p>@mui/x-tree-view</p></td><td class=\"confluenceTd\"><p>^8.11.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Tree View</p></td></tr><tr><td class=\"confluenceTd\"><p>@react-spring/web</p></td><td class=\"confluenceTd\"><p>^10.0.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Animation</p></td></tr><tr><td class=\"confluenceTd\"><p>clsx</p></td><td class=\"confluenceTd\"><p>^2.1.1</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Utilities</p></td></tr><tr><td class=\"confluenceTd\"><p>dayjs</p></td><td class=\"confluenceTd\"><p>^1.11.15</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Date</p></td></tr><tr><td class=\"confluenceTd\"><p>react / react-dom</p></td><td class=\"confluenceTd\"><p>^18.2.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Framework</p></td></tr><tr><td class=\"confluenceTd\"><p>react-router-dom</p></td><td class=\"confluenceTd\"><p>^7.8.2</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Routing</p></td></tr><tr><td class=\"confluenceTd\"><p>@storybook/*</p></td><td class=\"confluenceTd\"><p>^9.1.7</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Dev Tool</p></td></tr><tr><td class=\"confluenceTd\"><p>@typescript-eslint/*</p></td><td class=\"confluenceTd\"><p>^6.14.0</p></td><td class=\"confluenceTd\"><p>BSD-2</p></td><td class=\"confluenceTd\"><p>Linting</p></td></tr><tr><td class=\"confluenceTd\"><p>eslint / eslint-plugin-*</p></td><td class=\"confluenceTd\"><p>various</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Linting</p></td></tr><tr><td class=\"confluenceTd\"><p>playwright</p></td><td class=\"confluenceTd\"><p>^1.55.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Testing</p></td></tr><tr><td class=\"confluenceTd\"><p>typescript</p></td><td class=\"confluenceTd\"><p>^5.2.2</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Language</p></td></tr><tr><td class=\"confluenceTd\"><p>vite</p></td><td class=\"confluenceTd\"><p>^5.0.8</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Build</p></td></tr><tr><td class=\"confluenceTd\"><p>vitest</p></td><td class=\"confluenceTd\"><p>^3.2.4</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Testing</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-beta-hri-display/test1(Python\u2014requirements.txt)\">beta-hri-display/test1 (Python \u2014 requirements.txt)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>pygame</strong></p></td><td class=\"confluenceTd\"><blockquote><p>=2.5.0</p></blockquote></td><td class=\"confluenceTd\"><p><strong>LGPL-2.1</strong></p></td><td class=\"confluenceTd\"><p><strong>YELLOW</strong> \u2014 graphics library with weak copyleft</p></td></tr><tr><td class=\"confluenceTd\"><p>moderngl</p></td><td class=\"confluenceTd\"><blockquote><p>=5.8.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>numpy</p></td><td class=\"confluenceTd\"><blockquote><p>=1.24.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>Pillow</p></td><td class=\"confluenceTd\"><blockquote><p>=10.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>HPND</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>noise</p></td><td class=\"confluenceTd\"><blockquote><p>=1.2.2</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-hmnd_playground\">hmnd_playground</h2><p>Playground projects are experimental / developer sandboxes. Not shipped in production. Key dependencies by project:</p><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-karim_shaban/calibration(pixi.toml)\">karim_shaban/calibration (pixi.toml)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>opencv</p></td><td class=\"confluenceTd\"><blockquote><p>=4.11.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pinocchio</p></td><td class=\"confluenceTd\"><blockquote><p>=3.4.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-2</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>ceres-solver</p></td><td class=\"confluenceTd\"><blockquote><p>=2.2.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>matplotlib</p></td><td class=\"confluenceTd\"><blockquote><p>=3.10.8</p></blockquote></td><td class=\"confluenceTd\"><p>PSF/BSD (some LGPL components)</p></td><td class=\"confluenceTd\"><p>YELLOW-LOW</p></td></tr><tr><td class=\"confluenceTd\"><p>scipy</p></td><td class=\"confluenceTd\"><blockquote><p>=1.15.2</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>ros-humble-desktop</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-karim_shaban/depth_anything_3(pixi.toml)\">karim_shaban/depth_anything_3 (pixi.toml)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>torch</p></td><td class=\"confluenceTd\"><blockquote><p>=2.4.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>torchvision</p></td><td class=\"confluenceTd\"><blockquote><p>=0.19.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>opencv-python</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>matplotlib</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>PSF/BSD</p></td><td class=\"confluenceTd\"><p>YELLOW-LOW</p></td></tr><tr><td class=\"confluenceTd\"><p>huggingface-hub</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-claudio_coppola(pixi.toml)\">claudio_coppola (pixi.toml)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>matplotlib</p></td><td class=\"confluenceTd\"><blockquote><p>=3.10.8</p></blockquote></td><td class=\"confluenceTd\"><p>PSF/BSD</p></td><td class=\"confluenceTd\"><p>YELLOW-LOW</p></td></tr><tr><td class=\"confluenceTd\"><p>pinocchio</p></td><td class=\"confluenceTd\"><blockquote><p>=3.4.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-2</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>rerun-sdk</p></td><td class=\"confluenceTd\"><blockquote><p>=0.22.1</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>mcap-ros2-support</p></td><td class=\"confluenceTd\"><blockquote><p>=0.5.5</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>ros-humble-desktop</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-federico_proni/intrinsics_colmap(pixi.toml)\">federico_proni/intrinsics_colmap (pixi.toml)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>colmap</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>opencv</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>numpy</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-vaibhav_mehta/vislam(pixi.toml)\">vaibhav_mehta/vislam (pixi.toml)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>ros-humble-desktop</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>opencv</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>All others</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT/BSD/Apache</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-sergei_fedotov/ray_dataset_v3(pixi.toml)\">sergei_fedotov/ray_dataset_v3 (pixi.toml)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>ray[default]</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>polars</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>All others</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT/BSD/Apache</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-Root/Bazel/pixi.toml\">Root / Bazel / pixi.toml</h2><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-Rootpixi.tomlDependencies\">Root pixi.toml Dependencies</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>gcc</p></td><td class=\"confluenceTd\"><blockquote><p>=11,&lt;12</p></blockquote></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>RED (build tool \u2014 not linked)</p></td></tr><tr><td class=\"confluenceTd\"><p>gxx</p></td><td class=\"confluenceTd\"><blockquote><p>=11,&lt;12</p></blockquote></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>RED (build tool \u2014 not linked)</p></td></tr><tr><td class=\"confluenceTd\"><p>binutils</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>RED (build tool \u2014 not linked)</p></td></tr><tr><td class=\"confluenceTd\"><p>make</p></td><td class=\"confluenceTd\"><blockquote><p>=4.4.1,&lt;5</p></blockquote></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>RED (build tool \u2014 not linked)</p></td></tr><tr><td class=\"confluenceTd\"><p>git</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>RED (tool \u2014 not linked)</p></td></tr><tr><td class=\"confluenceTd\"><p>curl</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>python</p></td><td class=\"confluenceTd\"><blockquote><p>=3.10</p></blockquote></td><td class=\"confluenceTd\"><p>PSF</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>openjdk</p></td><td class=\"confluenceTd\"><blockquote><p>=11,&lt;12</p></blockquote></td><td class=\"confluenceTd\"><p>GPL-2.0 + Classpath Exception</p></td><td class=\"confluenceTd\"><p>Safe (Classpath Exception)</p></td></tr><tr><td class=\"confluenceTd\"><p>bazelisk</p></td><td class=\"confluenceTd\"><blockquote><p>=1.20.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pydpkg</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-MODULE.bazelDependencies(AllPermissive)\">MODULE.bazel Dependencies (All Permissive)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>bazel-diff</p></td><td class=\"confluenceTd\"><p>12.0.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>platforms</p></td><td class=\"confluenceTd\"><p>1.0.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>rules_foreign_cc</p></td><td class=\"confluenceTd\"><p>0.15.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>rules_pkg</p></td><td class=\"confluenceTd\"><p>1.1.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>rules_shell</p></td><td class=\"confluenceTd\"><p>0.6.1</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>bazel_skylib</p></td><td class=\"confluenceTd\"><p>1.9.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>rules_cc</p></td><td class=\"confluenceTd\"><p>0.2.16</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>rules_rust</p></td><td class=\"confluenceTd\"><p>0.67.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>googletest</p></td><td class=\"confluenceTd\"><p>1.17.0</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>flatbuffers</p></td><td class=\"confluenceTd\"><p>25.12.19</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>grpc</p></td><td class=\"confluenceTd\"><p>1.72.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>protobuf</p></td><td class=\"confluenceTd\"><p>30.0</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>rules_proto</p></td><td class=\"confluenceTd\"><p>7.1.0</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>rules_python</p></td><td class=\"confluenceTd\"><p>1.6.3</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>aws_sdk</p></td><td class=\"confluenceTd\"><p>1.11.321</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>boost.asio</p></td><td class=\"confluenceTd\"><p>1.89.0</p></td><td class=\"confluenceTd\"><p>BSL-1.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>boost.beast</p></td><td class=\"confluenceTd\"><p>1.89.0</p></td><td class=\"confluenceTd\"><p>BSL-1.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>boost.system</p></td><td class=\"confluenceTd\"><p>1.89.0</p></td><td class=\"confluenceTd\"><p>BSL-1.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>spdlog</p></td><td class=\"confluenceTd\"><p>1.17.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>tl-expected</p></td><td class=\"confluenceTd\"><p>1.1.0</p></td><td class=\"confluenceTd\"><p>CC0-1.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-hmnd_test_and_integration\">hmnd_test_and_integration</h2><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-alpha_head_tests(pixi.toml)\u2014Minimaldependencies\">alpha_head_tests (pixi.toml) \u2014 Minimal dependencies</h3><h3 id=\"OSSAudit:hmnd_design,hmnd_playground,Root/Bazel-sensor_evaluation/depth_testing(pixi.toml)\u2014OpenCV,NumPy,etc.\">sensor_evaluation/depth_testing (pixi.toml) \u2014 OpenCV, NumPy, etc.</h3><p>All test/integration dependencies are permissively licensed (MIT, BSD, Apache-2.0). No copyleft concerns.</p>"
        },
        {
          "id": "1840807976",
          "title": "OSS Audit: hmnd_fleet, hmnd_services, hmnd_update",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1840807976",
          "last_modified": "2026-04-08T09:51:46.738Z",
          "created_at": "2026-04-08T09:51:46.738Z",
          "body_html": "<h1 id=\"OSSAudit:hmnd_fleet,hmnd_services,hmnd_update-hmnd_fleet,hmnd_services,hmnd_update\u2014DependencyLicenseAudit\">hmnd_fleet, hmnd_services, hmnd_update \u2014 Dependency License Audit</h1><p><strong>Risk Level: LOW</strong>  <br/><strong>Key Concerns:</strong> None \u2014 all dependencies are permissively licensed.</p><hr/><h2 id=\"OSSAudit:hmnd_fleet,hmnd_services,hmnd_update-hmnd_fleet\">hmnd_fleet</h2><h3 id=\"OSSAudit:hmnd_fleet,hmnd_services,hmnd_update-Summary\">Summary</h3><p>Minimal external dependencies. The pixi.toml installs only a local editable package (<code>hmnd-fleet</code>). No third-party copyleft issues.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi (pypi)</p></td><td class=\"confluenceTd\"><p>hmnd-fleet</p></td><td class=\"confluenceTd\"><p>local editable</p></td><td class=\"confluenceTd\"><p>Proprietary (internal)</p></td><td class=\"confluenceTd\"><p>BLUE</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_fleet,hmnd_services,hmnd_update-hmnd_services/backbone\">hmnd_services/backbone</h2><h3 id=\"OSSAudit:hmnd_fleet,hmnd_services,hmnd_update-Summary.1\">Summary</h3><p>Backend API service using FastAPI, SQLAlchemy, and AWS. All 11 dependencies are permissively licensed (MIT, Apache-2.0, BSD). Project itself is marked as Proprietary.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>alembic</p></td><td class=\"confluenceTd\"><blockquote><p>=1.14.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>boto3</p></td><td class=\"confluenceTd\"><blockquote><p>=1.34.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>fastapi</p></td><td class=\"confluenceTd\"><blockquote><p>=0.110.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>httpx</p></td><td class=\"confluenceTd\"><blockquote><p>=0.27.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>PyJWT[crypto]</p></td><td class=\"confluenceTd\"><blockquote><p>=2.9.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>psycopg[binary]</p></td><td class=\"confluenceTd\"><blockquote><p>=3.2.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD (LGPL-free \u2014 note: psycopg3 is BSD, unlike psycopg2 which is LGPL)</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>pydantic</p></td><td class=\"confluenceTd\"><blockquote><p>=2.6.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>sqlalchemy</p></td><td class=\"confluenceTd\"><blockquote><p>=2.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>uuid6</p></td><td class=\"confluenceTd\"><blockquote><p>=2025.0.1</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>uvicorn</p></td><td class=\"confluenceTd\"><blockquote><p>=0.23.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml (dev)</p></td><td class=\"confluenceTd\"><p>pytest</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_fleet,hmnd_services,hmnd_update-uv.lockTransitiveDependencies(Selected)\">uv.lock Transitive Dependencies (Selected)</h3><p>All resolved packages in <code>uv.lock</code> are MIT, Apache-2.0, or BSD licensed. No copyleft detected.</p><hr/><h2 id=\"OSSAudit:hmnd_fleet,hmnd_services,hmnd_update-hmnd_update\">hmnd_update</h2><h3 id=\"OSSAudit:hmnd_fleet,hmnd_services,hmnd_update-Summary.2\">Summary</h3><p>OTA update service using FastAPI and S3. All 9 dependencies are permissively licensed.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>fastapi</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>pydantic</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>requests</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>uvicorn[standard]</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>boto3</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>sniffio</p></td><td class=\"confluenceTd\"><blockquote><p>=1.3.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml (dev)</p></td><td class=\"confluenceTd\"><p>pytest</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml (dev)</p></td><td class=\"confluenceTd\"><p>moto[s3]</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml (dev)</p></td><td class=\"confluenceTd\"><p>pytest-asyncio</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_fleet,hmnd_services,hmnd_update-uv.lockTransitiveDependencies\">uv.lock Transitive Dependencies</h3><p>All resolved packages are permissively licensed. No copyleft detected.</p>"
        },
        {
          "id": "1839071263",
          "title": "OSS Audit: hmnd_locomotion",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1839071263",
          "last_modified": "2026-04-08T09:51:17.061Z",
          "created_at": "2026-04-08T09:51:17.061Z",
          "body_html": "<h1 id=\"OSSAudit:hmnd_locomotion-hmnd_locomotion\u2014DependencyLicenseAudit\">hmnd_locomotion \u2014 Dependency License Audit</h1><p><strong>Risk Level: MEDIUM</strong>  <br/><strong>Key Concerns:</strong> paramiko/psycopg2 (LGPL-2.1), build tools (GPL), NVIDIA Isaac Sim (proprietary)</p><hr/><h2 id=\"OSSAudit:hmnd_locomotion-Summary\">Summary</h2><p>hmnd_locomotion contains the locomotion training stack built on Isaac Sim / IsaacLab. It has 81 direct dependencies. The only RED items are build tools (gcc, gxx, make) and pylint (dev tool) \u2014 none of which ship in distributed binaries. The LGPL concerns (paramiko, psycopg2-binary) are weak copyleft and safe if used unmodified.</p><hr/><h2 id=\"OSSAudit:hmnd_locomotion-RED\u2014GPLDependencies\">RED \u2014 GPL Dependencies</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi (conda)</p></td><td class=\"confluenceTd\"><p>gcc</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Build tool \u2014 not linked.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi (conda)</p></td><td class=\"confluenceTd\"><p>gxx</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Build tool \u2014 not linked.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi (conda)</p></td><td class=\"confluenceTd\"><p>make</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Build tool \u2014 not linked.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi (pypi)</p></td><td class=\"confluenceTd\"><p>pylint</p></td><td class=\"confluenceTd\"><blockquote><p>=3.3.0</p></blockquote></td><td class=\"confluenceTd\"><p>GPL-2.0</p></td><td class=\"confluenceTd\"><p>Development linter \u2014 not shipped.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_locomotion-YELLOW\u2014LGPLDependencies\">YELLOW \u2014 LGPL Dependencies</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi (pypi)</p></td><td class=\"confluenceTd\"><p>paramiko</p></td><td class=\"confluenceTd\"><blockquote><p>=2.9.0</p></blockquote></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p>SSH client library. Must disclose source if modified.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi (pypi)</p></td><td class=\"confluenceTd\"><p>psycopg2-binary</p></td><td class=\"confluenceTd\"><blockquote><p>=2.9.0</p></blockquote></td><td class=\"confluenceTd\"><p>LGPL-2.1</p></td><td class=\"confluenceTd\"><p>PostgreSQL driver. Must disclose source if modified.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_locomotion-BLUE\u2014Proprietary\">BLUE \u2014 Proprietary</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi (pypi)</p></td><td class=\"confluenceTd\"><p>isaacsim</p></td><td class=\"confluenceTd\"><p>4.5.0.0</p></td><td class=\"confluenceTd\"><p>NVIDIA Proprietary</p></td><td class=\"confluenceTd\"><p>Physics simulator. Requires EULA.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi (pypi)</p></td><td class=\"confluenceTd\"><p>egl_probe</p></td><td class=\"confluenceTd\"><p>1.0.2</p></td><td class=\"confluenceTd\"><p>NVIDIA Proprietary</p></td><td class=\"confluenceTd\"><p>EGL probe utility.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_locomotion-GREEN\u2014PermissiveDependencies(73total)\">GREEN \u2014 Permissive Dependencies (73 total)</h2><h3 id=\"OSSAudit:hmnd_locomotion-ML/TrainingStack\">ML / Training Stack</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>torch</p></td><td class=\"confluenceTd\"><blockquote><p>=2.4.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Deep Learning</p></td></tr><tr><td class=\"confluenceTd\"><p>torchvision</p></td><td class=\"confluenceTd\"><blockquote><p>=0.19.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Computer Vision</p></td></tr><tr><td class=\"confluenceTd\"><p>triton</p></td><td class=\"confluenceTd\"><blockquote><p>=3.1.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>GPU Compilation</p></td></tr><tr><td class=\"confluenceTd\"><p>gymnasium</p></td><td class=\"confluenceTd\"><blockquote><p>=1.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>RL Environments</p></td></tr><tr><td class=\"confluenceTd\"><p>stable-baselines3</p></td><td class=\"confluenceTd\"><p>2.7.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>RL</p></td></tr><tr><td class=\"confluenceTd\"><p>diffusers</p></td><td class=\"confluenceTd\"><blockquote><p>=0.11.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Diffusion Models</p></td></tr><tr><td class=\"confluenceTd\"><p>huggingface-hub</p></td><td class=\"confluenceTd\"><blockquote><p>=0.23.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>ML Hub</p></td></tr><tr><td class=\"confluenceTd\"><p>tensorboard</p></td><td class=\"confluenceTd\"><blockquote><p>=2.18.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Logging</p></td></tr><tr><td class=\"confluenceTd\"><p>tensorboardX</p></td><td class=\"confluenceTd\"><blockquote><p>=2.6.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Logging</p></td></tr><tr><td class=\"confluenceTd\"><p>wandb</p></td><td class=\"confluenceTd\"><blockquote><p>=0.19.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Experiment Tracking</p></td></tr><tr><td class=\"confluenceTd\"><p>onnx</p></td><td class=\"confluenceTd\"><blockquote><p>=1.16.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Model Format</p></td></tr><tr><td class=\"confluenceTd\"><p>flash-attn</p></td><td class=\"confluenceTd\"><p>(implicit)</p></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>ML Optimization</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_locomotion-Robotics\">Robotics</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>pinocchio</p></td><td class=\"confluenceTd\"><blockquote><p>=3.4.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-2</p></td><td class=\"confluenceTd\"><p>Robot Dynamics</p></td></tr><tr><td class=\"confluenceTd\"><p>mujoco</p></td><td class=\"confluenceTd\"><blockquote><p>=3.3.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Physics</p></td></tr><tr><td class=\"confluenceTd\"><p>scipy</p></td><td class=\"confluenceTd\"><blockquote><p>=1.11.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Scientific</p></td></tr><tr><td class=\"confluenceTd\"><p>numpy</p></td><td class=\"confluenceTd\"><p>&lt;2</p></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Numerical</p></td></tr><tr><td class=\"confluenceTd\"><p>opencv-python</p></td><td class=\"confluenceTd\"><blockquote><p>=4.11.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Vision</p></td></tr><tr><td class=\"confluenceTd\"><p>usd-core</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Scene Description</p></td></tr><tr><td class=\"confluenceTd\"><p>robomimic</p></td><td class=\"confluenceTd\"><p>(git)</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Robot Learning</p></td></tr><tr><td class=\"confluenceTd\"><p>xacrodoc</p></td><td class=\"confluenceTd\"><blockquote><p>=1.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>URDF</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_locomotion-Web/Config/Dev\">Web / Config / Dev</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>fastapi</p></td><td class=\"confluenceTd\"><blockquote><p>=0.115.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Web</p></td></tr><tr><td class=\"confluenceTd\"><p>flask</p></td><td class=\"confluenceTd\"><blockquote><p>=3.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Web</p></td></tr><tr><td class=\"confluenceTd\"><p>pydantic</p></td><td class=\"confluenceTd\"><blockquote><p>=2.9.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Validation</p></td></tr><tr><td class=\"confluenceTd\"><p>hydra-core</p></td><td class=\"confluenceTd\"><blockquote><p>=1.3.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Config</p></td></tr><tr><td class=\"confluenceTd\"><p>omegaconf</p></td><td class=\"confluenceTd\"><blockquote><p>=2.3.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Config</p></td></tr><tr><td class=\"confluenceTd\"><p>click</p></td><td class=\"confluenceTd\"><blockquote><p>=8.1.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>CLI</p></td></tr><tr><td class=\"confluenceTd\"><p>rich</p></td><td class=\"confluenceTd\"><blockquote><p>=13.8.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Terminal</p></td></tr><tr><td class=\"confluenceTd\"><p>tqdm</p></td><td class=\"confluenceTd\"><blockquote><p>=4.66.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Progress</p></td></tr><tr><td class=\"confluenceTd\"><p>pyyaml</p></td><td class=\"confluenceTd\"><blockquote><p>=6.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Config</p></td></tr><tr><td class=\"confluenceTd\"><p>pytest / pytest-cov</p></td><td class=\"confluenceTd\"><p>various</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Testing</p></td></tr><tr><td class=\"confluenceTd\"><p>pre-commit</p></td><td class=\"confluenceTd\"><blockquote><p>=4.3.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Dev</p></td></tr><tr><td class=\"confluenceTd\"><p>black</p></td><td class=\"confluenceTd\"><blockquote><p>=24.8.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Formatting</p></td></tr><tr><td class=\"confluenceTd\"><p>isort</p></td><td class=\"confluenceTd\"><blockquote><p>=5.13.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Imports</p></td></tr><tr><td class=\"confluenceTd\"><p>mypy</p></td><td class=\"confluenceTd\"><blockquote><p>=1.11.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Type Checking</p></td></tr><tr><td class=\"confluenceTd\"><p>ipython</p></td><td class=\"confluenceTd\"><blockquote><p>=8.27.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Development</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_locomotion-Data/Cloud\">Data / Cloud</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>h5py</p></td><td class=\"confluenceTd\"><blockquote><p>=3.11.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>HDF5</p></td></tr><tr><td class=\"confluenceTd\"><p>pandas</p></td><td class=\"confluenceTd\"><blockquote><p>=2.3.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>boto3 / botocore</p></td><td class=\"confluenceTd\"><blockquote><p>=1.35.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>AWS</p></td></tr><tr><td class=\"confluenceTd\"><p>fsspec</p></td><td class=\"confluenceTd\"><blockquote><p>=2023.1.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Filesystem</p></td></tr><tr><td class=\"confluenceTd\"><p>dask</p></td><td class=\"confluenceTd\"><blockquote><p>=2024.9.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Parallel Compute</p></td></tr><tr><td class=\"confluenceTd\"><p>celery</p></td><td class=\"confluenceTd\"><blockquote><p>=5.4.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Task Queue</p></td></tr><tr><td class=\"confluenceTd\"><p>redis</p></td><td class=\"confluenceTd\"><blockquote><p>=5.1.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Cache</p></td></tr><tr><td class=\"confluenceTd\"><p>SQLAlchemy</p></td><td class=\"confluenceTd\"><blockquote><p>=2.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>ORM</p></td></tr><tr><td class=\"confluenceTd\"><p>Jinja2</p></td><td class=\"confluenceTd\"><blockquote><p>=3.1.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Templating</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_locomotion-Conda\">Conda</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>python</p></td><td class=\"confluenceTd\"><p>3.10</p></td><td class=\"confluenceTd\"><p>PSF</p></td><td class=\"confluenceTd\"><p>Runtime</p></td></tr><tr><td class=\"confluenceTd\"><p>pip</p></td><td class=\"confluenceTd\"><blockquote><p>=24.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Package Manager</p></td></tr><tr><td class=\"confluenceTd\"><p>cmake</p></td><td class=\"confluenceTd\"><blockquote><p>=3.22.0,&lt;3.27</p></blockquote></td><td class=\"confluenceTd\"><p>BSD</p></td><td class=\"confluenceTd\"><p>Build</p></td></tr><tr><td class=\"confluenceTd\"><p>xorg-libsm</p></td><td class=\"confluenceTd\"><blockquote><p>=1.2.6</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Display</p></td></tr><tr><td class=\"confluenceTd\"><p>xorg-libxt</p></td><td class=\"confluenceTd\"><blockquote><p>=1.3.1</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Display</p></td></tr><tr><td class=\"confluenceTd\"><p>libglu</p></td><td class=\"confluenceTd\"><blockquote><p>=9.0.3</p></blockquote></td><td class=\"confluenceTd\"><p>SGI-B-2.0</p></td><td class=\"confluenceTd\"><p>Graphics</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_locomotion-IsaacLabSub-packages(allwithinhmnd_locomotion/source/)\">IsaacLab Sub-packages (all within hmnd_locomotion/source/)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>License</p></th></tr><tr><td class=\"confluenceTd\"><p>isaaclab</p></td><td class=\"confluenceTd\"><p>BSD-3-Clause (NVIDIA)</p></td></tr><tr><td class=\"confluenceTd\"><p>isaaclab-assets</p></td><td class=\"confluenceTd\"><p>BSD-3-Clause</p></td></tr><tr><td class=\"confluenceTd\"><p>isaaclab-locomotion</p></td><td class=\"confluenceTd\"><p>Internal</p></td></tr><tr><td class=\"confluenceTd\"><p>isaaclab-mimic</p></td><td class=\"confluenceTd\"><p>BSD-3-Clause</p></td></tr><tr><td class=\"confluenceTd\"><p>isaaclab-rl</p></td><td class=\"confluenceTd\"><p>BSD-3-Clause</p></td></tr><tr><td class=\"confluenceTd\"><p>isaaclab-tasks</p></td><td class=\"confluenceTd\"><p>BSD-3-Clause</p></td></tr></tbody></table></div>"
        },
        {
          "id": "1840873486",
          "title": "OSS Audit: hmnd_flywheel",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1840873486",
          "last_modified": "2026-04-08T09:50:51.744Z",
          "created_at": "2026-04-08T09:50:51.744Z",
          "body_html": "<h1 id=\"OSSAudit:hmnd_flywheel-hmnd_flywheel\u2014DependencyLicenseAudit\">hmnd_flywheel \u2014 Dependency License Audit</h1><p><strong>Risk Level: LOW</strong>  <br/><strong>Key Concerns:</strong> No copyleft. Some proprietary SDKs (Databricks, Google GenAI). Several npm dev dependencies with unverified licenses.</p><hr/><h2 id=\"OSSAudit:hmnd_flywheel-Summary\">Summary</h2><p>hmnd_flywheel contains the data pipeline, dataset management, Databricks integrations, humanoid console, and prefect workflow orchestration. 78 unique dependencies were identified across 7 pixi.toml files, 10 pyproject.toml files, and npm package.json files. Zero GPL or LGPL dependencies were found. The module is clean for commercial distribution.</p><hr/><h2 id=\"OSSAudit:hmnd_flywheel-BLUE\u2014Proprietary\">BLUE \u2014 Proprietary</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>PyPI</p></td><td class=\"confluenceTd\"><p>databricks-sql-connector</p></td><td class=\"confluenceTd\"><blockquote><p>=3,&lt;5</p></blockquote></td><td class=\"confluenceTd\"><p>Proprietary (Databricks)</p></td><td class=\"confluenceTd\"><p>Databricks SQL access. Check redistribution terms.</p></td></tr><tr><td class=\"confluenceTd\"><p>PyPI</p></td><td class=\"confluenceTd\"><p>google-genai</p></td><td class=\"confluenceTd\"><blockquote><p>=1.38.0</p></blockquote></td><td class=\"confluenceTd\"><p>Proprietary (Google)</p></td><td class=\"confluenceTd\"><p>Google AI SDK. Check terms of service.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_flywheel-GRAY\u2014UnknownLicense(NeedsVerification)\">GRAY \u2014 Unknown License (Needs Verification)</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>npm</p></td><td class=\"confluenceTd\"><p>@types/react</p></td><td class=\"confluenceTd\"><p>^18.2.73</p></td><td class=\"confluenceTd\"><p>DefinitelyTyped \u2014 likely MIT</p></td></tr><tr><td class=\"confluenceTd\"><p>npm</p></td><td class=\"confluenceTd\"><p>@types/react-dom</p></td><td class=\"confluenceTd\"><p>^18.2.23</p></td><td class=\"confluenceTd\"><p>DefinitelyTyped \u2014 likely MIT</p></td></tr><tr><td class=\"confluenceTd\"><p>npm</p></td><td class=\"confluenceTd\"><p>@vitejs/plugin-react</p></td><td class=\"confluenceTd\"><p>^4.2.1</p></td><td class=\"confluenceTd\"><p>Likely MIT</p></td></tr><tr><td class=\"confluenceTd\"><p>npm</p></td><td class=\"confluenceTd\"><p>bufferutil</p></td><td class=\"confluenceTd\"><p>^4.0.9</p></td><td class=\"confluenceTd\"><p>Likely MIT</p></td></tr><tr><td class=\"confluenceTd\"><p>npm</p></td><td class=\"confluenceTd\"><p>utf-8-validate</p></td><td class=\"confluenceTd\"><p>^6.0.5</p></td><td class=\"confluenceTd\"><p>Likely MIT</p></td></tr><tr><td class=\"confluenceTd\"><p>npm</p></td><td class=\"confluenceTd\"><p>vite-plugin-electron</p></td><td class=\"confluenceTd\"><p>^0.28.6</p></td><td class=\"confluenceTd\"><p>Needs verification</p></td></tr><tr><td class=\"confluenceTd\"><p>npm</p></td><td class=\"confluenceTd\"><p>vite-plugin-electron-renderer</p></td><td class=\"confluenceTd\"><p>^0.14.5</p></td><td class=\"confluenceTd\"><p>Needs verification</p></td></tr><tr><td class=\"confluenceTd\"><p>npm</p></td><td class=\"confluenceTd\"><p>ws</p></td><td class=\"confluenceTd\"><p>^8.18.3</p></td><td class=\"confluenceTd\"><p>Likely MIT</p></td></tr><tr><td class=\"confluenceTd\"><p>PyPI</p></td><td class=\"confluenceTd\"><p>hc-client</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Internal package</p></td></tr><tr><td class=\"confluenceTd\"><p>PyPI</p></td><td class=\"confluenceTd\"><p>humanoid-console-models</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Internal package</p></td></tr><tr><td class=\"confluenceTd\"><p>PyPI</p></td><td class=\"confluenceTd\"><p>hatchling.build</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Likely MIT (part of hatchling)</p></td></tr><tr><td class=\"confluenceTd\"><p>PyPI</p></td><td class=\"confluenceTd\"><p>src/hmnd_console_api</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Internal package</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_flywheel-GREEN\u2014PermissiveDependencies(All)\">GREEN \u2014 Permissive Dependencies (All)</h2><h3 id=\"OSSAudit:hmnd_flywheel-Python(PyPIviapixiandpyproject.toml)\">Python (PyPI via pixi and pyproject.toml)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>boto3</p></td><td class=\"confluenceTd\"><blockquote><p>=1.34</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>AWS</p></td></tr><tr><td class=\"confluenceTd\"><p>click</p></td><td class=\"confluenceTd\"><blockquote><p>=8.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>CLI</p></td></tr><tr><td class=\"confluenceTd\"><p>duckdb</p></td><td class=\"confluenceTd\"><blockquote><p>=1.4.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Database</p></td></tr><tr><td class=\"confluenceTd\"><p>fastapi</p></td><td class=\"confluenceTd\"><p>(implicit)</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Web Framework</p></td></tr><tr><td class=\"confluenceTd\"><p>ffmpeg-python</p></td><td class=\"confluenceTd\"><blockquote><p>=0.2.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Video (Python wrapper \u2014 NOT the GPL binary)</p></td></tr><tr><td class=\"confluenceTd\"><p>filelock</p></td><td class=\"confluenceTd\"><blockquote><p>=3.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>Unlicense</p></td><td class=\"confluenceTd\"><p>Filesystem</p></td></tr><tr><td class=\"confluenceTd\"><p>fsspec</p></td><td class=\"confluenceTd\"><blockquote><p>=2024.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Filesystem</p></td></tr><tr><td class=\"confluenceTd\"><p>hatchling</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td></tr><tr><td class=\"confluenceTd\"><p>httpx</p></td><td class=\"confluenceTd\"><blockquote><p>=0.27,&lt;1</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>HTTP</p></td></tr><tr><td class=\"confluenceTd\"><p>imageio-ffmpeg</p></td><td class=\"confluenceTd\"><blockquote><p>=0.5.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Video</p></td></tr><tr><td class=\"confluenceTd\"><p>ipykernel</p></td><td class=\"confluenceTd\"><blockquote><p>=6.30.1</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Notebook</p></td></tr><tr><td class=\"confluenceTd\"><p>jupyter</p></td><td class=\"confluenceTd\"><blockquote><p>=1.1.1</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Notebook</p></td></tr><tr><td class=\"confluenceTd\"><p>kubernetes</p></td><td class=\"confluenceTd\"><blockquote><p>=30.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Orchestration</p></td></tr><tr><td class=\"confluenceTd\"><p>kubernetes-asyncio</p></td><td class=\"confluenceTd\"><blockquote><p>=32.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Orchestration</p></td></tr><tr><td class=\"confluenceTd\"><p>lerobot</p></td><td class=\"confluenceTd\"><blockquote><p>=0.4.3</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Robotics</p></td></tr><tr><td class=\"confluenceTd\"><p>marimo</p></td><td class=\"confluenceTd\"><blockquote><p>=0.17.7</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Notebook</p></td></tr><tr><td class=\"confluenceTd\"><p>mcap-ros2-support</p></td><td class=\"confluenceTd\"><p>==0.5.5</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Data Format</p></td></tr><tr><td class=\"confluenceTd\"><p>mcp</p></td><td class=\"confluenceTd\"><blockquote><p>=1</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Protocol</p></td></tr><tr><td class=\"confluenceTd\"><p>moto[s3server]</p></td><td class=\"confluenceTd\"><blockquote><p>=5.0.15</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>AWS Testing</p></td></tr><tr><td class=\"confluenceTd\"><p>nicegui</p></td><td class=\"confluenceTd\"><blockquote><p>=2.18.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Web UI</p></td></tr><tr><td class=\"confluenceTd\"><p>numpy</p></td><td class=\"confluenceTd\"><blockquote><p>=1.26.0,&lt;2.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Numerical</p></td></tr><tr><td class=\"confluenceTd\"><p>openai</p></td><td class=\"confluenceTd\"><blockquote><p>=1.109.1</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>AI</p></td></tr><tr><td class=\"confluenceTd\"><p>opencv-python</p></td><td class=\"confluenceTd\"><p>==4.11.0.86</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Computer Vision</p></td></tr><tr><td class=\"confluenceTd\"><p>pandas</p></td><td class=\"confluenceTd\"><blockquote><p>=1.4,&lt;3</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>pillow</p></td><td class=\"confluenceTd\"><blockquote><p>=10.0.0,&lt;11.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>HPND</p></td><td class=\"confluenceTd\"><p>Image</p></td></tr><tr><td class=\"confluenceTd\"><p>plotly</p></td><td class=\"confluenceTd\"><blockquote><p>=6.3.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Visualization</p></td></tr><tr><td class=\"confluenceTd\"><p>polars[all]</p></td><td class=\"confluenceTd\"><blockquote><p>=1.33.1</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>prefect</p></td><td class=\"confluenceTd\"><p>==3.6.5</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Workflow</p></td></tr><tr><td class=\"confluenceTd\"><p>prefect-databricks</p></td><td class=\"confluenceTd\"><blockquote><p>=0.3.2</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Workflow</p></td></tr><tr><td class=\"confluenceTd\"><p>prefect-docker</p></td><td class=\"confluenceTd\"><blockquote><p>=0.6.6</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Workflow</p></td></tr><tr><td class=\"confluenceTd\"><p>prefect-github</p></td><td class=\"confluenceTd\"><blockquote><p>=0.3.2</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Workflow</p></td></tr><tr><td class=\"confluenceTd\"><p>prefect-kubernetes</p></td><td class=\"confluenceTd\"><blockquote><p>=0.7.1</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Workflow</p></td></tr><tr><td class=\"confluenceTd\"><p>prefect-slack</p></td><td class=\"confluenceTd\"><blockquote><p>=0.3.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Workflow</p></td></tr><tr><td class=\"confluenceTd\"><p>pyarrow</p></td><td class=\"confluenceTd\"><blockquote><p>=16.0.0,&lt;18.0.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>pydantic</p></td><td class=\"confluenceTd\"><blockquote><p>=2.8</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Validation</p></td></tr><tr><td class=\"confluenceTd\"><p>pyspark</p></td><td class=\"confluenceTd\"><blockquote><p>=3.5,&lt;4.0</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Big Data</p></td></tr><tr><td class=\"confluenceTd\"><p>pytest</p></td><td class=\"confluenceTd\"><blockquote><p>=7</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Testing</p></td></tr><tr><td class=\"confluenceTd\"><p>python-dateutil</p></td><td class=\"confluenceTd\"><blockquote><p>=2.9.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Time</p></td></tr><tr><td class=\"confluenceTd\"><p>python-jose[crypto]</p></td><td class=\"confluenceTd\"><blockquote><p>=3.5.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>JWT</p></td></tr><tr><td class=\"confluenceTd\"><p>pyyaml</p></td><td class=\"confluenceTd\"><blockquote><p>=6.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Config</p></td></tr><tr><td class=\"confluenceTd\"><p>ray[default]</p></td><td class=\"confluenceTd\"><blockquote><p>=2.50,&lt;3</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Distributed</p></td></tr><tr><td class=\"confluenceTd\"><p>requests</p></td><td class=\"confluenceTd\"><blockquote><p>=2.32.5</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>HTTP</p></td></tr><tr><td class=\"confluenceTd\"><p>ruamel.yaml</p></td><td class=\"confluenceTd\"><blockquote><p>=0.18.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Config</p></td></tr><tr><td class=\"confluenceTd\"><p>sqlglot</p></td><td class=\"confluenceTd\"><blockquote><p>=27.18.0</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>SQL</p></td></tr><tr><td class=\"confluenceTd\"><p>tenacity</p></td><td class=\"confluenceTd\"><blockquote><p>=8,&lt;10</p></blockquote></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Retry</p></td></tr><tr><td class=\"confluenceTd\"><p>tqdm</p></td><td class=\"confluenceTd\"><blockquote><p>=4.67.1</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Progress</p></td></tr><tr><td class=\"confluenceTd\"><p>vegafusion</p></td><td class=\"confluenceTd\"><blockquote><p>=2.0.2</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Visualization</p></td></tr><tr><td class=\"confluenceTd\"><p>vl-convert-python</p></td><td class=\"confluenceTd\"><blockquote><p>=1.8.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Visualization</p></td></tr><tr><td class=\"confluenceTd\"><p>watchfiles</p></td><td class=\"confluenceTd\"><blockquote><p>=1.0.5</p></blockquote></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Filesystem</p></td></tr><tr><td class=\"confluenceTd\"><p>websockets</p></td><td class=\"confluenceTd\"><blockquote><p>=15.0.1</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Networking</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_flywheel-Node.js(npm)\">Node.js (npm)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>@emotion/react</p></td><td class=\"confluenceTd\"><p>^11.11.4</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Styling</p></td></tr><tr><td class=\"confluenceTd\"><p>@emotion/styled</p></td><td class=\"confluenceTd\"><p>^11.11.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Styling</p></td></tr><tr><td class=\"confluenceTd\"><p>@mui/icons-material</p></td><td class=\"confluenceTd\"><p>^5.15.15</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>UI</p></td></tr><tr><td class=\"confluenceTd\"><p>@mui/material</p></td><td class=\"confluenceTd\"><p>^5.15.15</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>UI</p></td></tr><tr><td class=\"confluenceTd\"><p>@tanstack/react-query</p></td><td class=\"confluenceTd\"><p>^5.28.9</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>react / react-dom</p></td><td class=\"confluenceTd\"><p>^18.2.0</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Framework</p></td></tr><tr><td class=\"confluenceTd\"><p>zod</p></td><td class=\"confluenceTd\"><p>^3.22.4</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Validation</p></td></tr><tr><td class=\"confluenceTd\"><p>electron</p></td><td class=\"confluenceTd\"><p>^29.1.6</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Desktop</p></td></tr><tr><td class=\"confluenceTd\"><p>electron-builder</p></td><td class=\"confluenceTd\"><p>^24.13.3</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Build</p></td></tr><tr><td class=\"confluenceTd\"><p>typescript</p></td><td class=\"confluenceTd\"><p>^5.4.3</p></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Language</p></td></tr><tr><td class=\"confluenceTd\"><p>vite</p></td><td class=\"confluenceTd\"><p>^5.2.7</p></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Build</p></td></tr></tbody></table></div>"
        },
        {
          "id": "1840775181",
          "title": "OSS Audit: hmnd_sim",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1840775181",
          "last_modified": "2026-04-08T09:50:21.482Z",
          "created_at": "2026-04-08T09:50:21.482Z",
          "body_html": "<h1 id=\"OSSAudit:hmnd_sim-hmnd_sim\u2014DependencyLicenseAudit\">hmnd_sim \u2014 Dependency License Audit</h1><p><strong>Risk Level: LOW</strong>  <br/><strong>Key Concerns:</strong> Build tools (gcc/gxx/make \u2014 GPL, not linked), NVIDIA Isaac Sim (proprietary)</p><hr/><h2 id=\"OSSAudit:hmnd_sim-Summary\">Summary</h2><p>hmnd_sim is relatively clean from a licensing perspective. The primary dependencies are ROS 2 (Apache-2.0), DVC (Apache-2.0), Ray (Apache-2.0), and the NVIDIA Isaac Sim + IsaacLab stack. The only GPL items are build tools that don't ship in binaries. The main concern is the proprietary NVIDIA Isaac Sim licensing.</p><hr/><h2 id=\"OSSAudit:hmnd_sim-BundledThird-PartyCode\">Bundled Third-Party Code</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Location</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Risk</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>IsaacLab</strong></p></td><td class=\"confluenceTd\"><p><code>third_party/IsaacLab/</code></p></td><td class=\"confluenceTd\"><p>BSD-3-Clause</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>IsaacLab ai_agent</strong></p></td><td class=\"confluenceTd\"><p><code>third_party/IsaacLab/</code> (submodule)</p></td><td class=\"confluenceTd\"><p>BSD-3-Clause</p></td><td class=\"confluenceTd\"><p>GREEN</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_sim-RED\u2014GPLDependencies\">RED \u2014 GPL Dependencies</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>gcc</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Build tool \u2014 not linked.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>gxx</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Build tool \u2014 not linked.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>make</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>GPL-3.0</p></td><td class=\"confluenceTd\"><p>Build tool \u2014 not linked.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_sim-BLUE\u2014Proprietary\">BLUE \u2014 Proprietary</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi.toml (system-req)</p></td><td class=\"confluenceTd\"><p>isaacsim</p></td><td class=\"confluenceTd\"><p>5.0+ / 5.1.0.0</p></td><td class=\"confluenceTd\"><p>NVIDIA Proprietary</p></td><td class=\"confluenceTd\"><p>Requires NVIDIA EULA. Cannot redistribute without permission.</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>pixi-pycharm</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Proprietary</p></td><td class=\"confluenceTd\"><p>IDE integration.</p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_sim-GREEN\u2014PermissiveDependencies\">GREEN \u2014 Permissive Dependencies</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Source</p></th><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Version</p></th><th class=\"confluenceTh\"><p>License</p></th><th class=\"confluenceTh\"><p>Category</p></th></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>python</p></td><td class=\"confluenceTd\"><blockquote><p>=3.10</p></blockquote></td><td class=\"confluenceTd\"><p>PSF</p></td><td class=\"confluenceTd\"><p>Runtime</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>numpy</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Numerical</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>pandas</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Data</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>scipy</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Scientific</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>cmake</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Build Tool</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>dvc[s3]</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Data Versioning</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>ray-default</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Distributed Compute</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>ros-humble-desktop</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>ROS 2</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>ros-humble-foxglove-bridge</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Visualization</p></td></tr><tr><td class=\"confluenceTd\"><p>pixi.toml</p></td><td class=\"confluenceTd\"><p>ros-humble-ros-gz</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Gazebo Bridge</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>torch</p></td><td class=\"confluenceTd\"><blockquote><p>=2.4.0</p></blockquote></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Deep Learning</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>torchvision</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Computer Vision</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>gymnasium</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>RL Environments</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>opencv-python</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Computer Vision</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>matplotlib</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>PSF/BSD</p></td><td class=\"confluenceTd\"><p>Plotting</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>tensorboard</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Logging</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>wandb</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>MIT</p></td><td class=\"confluenceTd\"><p>Experiment Tracking</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>hydra-core</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Config</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>protobuf</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Serialization</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>pillow</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>HPND</p></td><td class=\"confluenceTd\"><p>Image Processing</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>mujoco</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>Physics Simulation</p></td></tr><tr><td class=\"confluenceTd\"><p>pyproject.toml</p></td><td class=\"confluenceTd\"><p>pinocchio</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>BSD-2</p></td><td class=\"confluenceTd\"><p>Robot Dynamics</p></td></tr><tr><td class=\"confluenceTd\"><p>requirements.txt</p></td><td class=\"confluenceTd\"><p>python-dotenv</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>BSD-3</p></td><td class=\"confluenceTd\"><p>Config</p></td></tr><tr><td class=\"confluenceTd\"><p>requirements.txt</p></td><td class=\"confluenceTd\"><p>requests</p></td><td class=\"confluenceTd\"><ul><li><p /></li></ul></td><td class=\"confluenceTd\"><p>Apache-2.0</p></td><td class=\"confluenceTd\"><p>HTTP</p></td></tr></tbody></table></div><h3 id=\"OSSAudit:hmnd_sim-IsaacLabSub-packages(allBSD-3-Clause)\">IsaacLab Sub-packages (all BSD-3-Clause)</h3><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Location</p></th></tr><tr><td class=\"confluenceTd\"><p>isaaclab</p></td><td class=\"confluenceTd\"><p><code>third_party/IsaacLab/source/isaaclab/</code></p></td></tr><tr><td class=\"confluenceTd\"><p>isaaclab-assets</p></td><td class=\"confluenceTd\"><p><code>third_party/IsaacLab/source/isaaclab_assets/</code></p></td></tr><tr><td class=\"confluenceTd\"><p>isaaclab-mimic</p></td><td class=\"confluenceTd\"><p><code>third_party/IsaacLab/source/isaaclab_mimic/</code></p></td></tr><tr><td class=\"confluenceTd\"><p>isaaclab-rl</p></td><td class=\"confluenceTd\"><p><code>third_party/IsaacLab/source/isaaclab_rl/</code></p></td></tr><tr><td class=\"confluenceTd\"><p>isaaclab-tasks</p></td><td class=\"confluenceTd\"><p><code>third_party/IsaacLab/source/isaaclab_tasks/</code></p></td></tr></tbody></table></div><hr/><h2 id=\"OSSAudit:hmnd_sim-GRAY\u2014Unknown\">GRAY \u2014 Unknown</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Name</p></th><th class=\"confluenceTh\"><p>Location</p></th><th class=\"confluenceTh\"><p>Notes</p></th></tr><tr><td class=\"confluenceTd\"><p>urdf_pipeline</p></td><td class=\"confluenceTd\"><p><code>sim_tools/urdf_pipeline/</code></p></td><td class=\"confluenceTd\"><p>Local editable module \u2014 needs internal license header check.</p></td></tr></tbody></table></div>"
        },
        {
          "id": "1823735863",
          "title": "Road to Pilot \u2014 Epic-Level Plan",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1823735863",
          "last_modified": "2026-04-02T15:34:20.835Z",
          "created_at": "2026-04-02T15:08:54.145Z",
          "body_html": "<p local-id=\"d497aa4201ec\"><em>Claude | April 2, 2026</em></p><h2 local-id=\"3a83bc60c790\" id=\"RoadtoPilot\u2014Epic-LevelPlan-NorthStar\">North Star</h2><p local-id=\"0c19f25f0239\"><strong><span class=\"inline-comment-marker\" data-ref=\"38474262-f9cc-481b-8c21-3c68f7349a21\">By end of 2026, operate a handful of robots in sustained, real operations at a customer site (Schaeffler), meeting the KPIs and metrics defined in the MSA.</span></strong></p><p local-id=\"f748dec329fd\">That means: ring picking at 440 UPH, navigation at 320 UPH across 2 stations, and a secondary use case (end-of-line package handling) \u2014 all running continuously, not as a rehearsed demo.</p><hr local-id=\"2721e7ea1cbf\"/><h2 local-id=\"8ea902b3b333\" id=\"RoadtoPilot\u2014Epic-LevelPlan-TheStrategy:ClosetheLoop,ThenIterate\">The Strategy: Close the Loop, Then Iterate</h2><p local-id=\"db1a296dc5f3\">We don't know all the things that will break in a sustained pilot. Nobody does. What we <em>can</em> do is close the product loop as fast as possible \u2014 get a robot autonomously executing an operator-authored workflow in a Schaeffler-like setup \u2014 and then run it until it fails. Fix what fails. Repeat.</p><p local-id=\"e44d3d4c1cb5\">This plan is organized around that principle. Phase 1 closes the loop. Phase 2 stress-tests it. Phase 3 hardens based on what we learn. <span class=\"inline-comment-marker\" data-ref=\"53f0f9b7-8a70-4fe2-a90f-7107e293681b\">Phase 4</span> is the pilot itself. The epics in Phases 2\u20133 are deliberately less specified because the whole point is to let real failure data drive the work.</p><hr local-id=\"2a504b0b4c63\"/><h2 local-id=\"169b2c413941\" id=\"RoadtoPilot\u2014Epic-LevelPlan-Phase1:ClosetheProductLoop\">Phase 1: Close the Product Loop</h2><p local-id=\"5fc4cbee0684\"><strong>April \u2013 May 2026</strong></p><p local-id=\"ddd529b141fc\"><em>Goal: An operator can deploy a robot to a new space, teach it a task via teleop, and have it execute that task autonomously \u2014 without engineering involvement.</em></p><div class=\"table-wrap\"><table data-table-width=\"1800\" data-layout=\"default\" data-local-id=\"4f0526f95324\" class=\"confluenceTable\"><tbody><tr data-local-id=\"b568fde50a49\"><th data-local-id=\"de3ea06193c9\" class=\"confluenceTh\"><p local-id=\"39f14a911eb8\">Epic</p></th><th data-local-id=\"4912058cffad\" class=\"confluenceTh\"><p local-id=\"25f6afe2e83f\">What it means</p></th><th data-local-id=\"b639b6119c6c\" class=\"confluenceTh\"><p local-id=\"ce60ff647e4d\">Status</p></th></tr><tr data-local-id=\"c377a66e30cd\"><td data-local-id=\"3a77d9364731\" class=\"confluenceTd\"><p local-id=\"3b51e498198f\"><strong>Symphony V2 \u2014 Agentic Workflow Authoring</strong></p></td><td data-local-id=\"b38d3f60bbf7\" class=\"confluenceTd\"><p local-id=\"30c64f29123a\">LLM agent can create/edit workflows from operator interaction. Integrated with runtime executor.</p></td><td data-local-id=\"871d6436a479\" class=\"confluenceTd\"><p local-id=\"e153792d7dcb\">In progress \u2014 PRs in flight</p></td></tr><tr data-local-id=\"1697701d0f1c\"><td data-local-id=\"e5b1b2ebc508\" class=\"confluenceTd\"><p local-id=\"d19f8e103a02\"><strong>Single-Shot Deployment MVP</strong></p></td><td data-local-id=\"02bacdef9bc0\" class=\"confluenceTd\"><p local-id=\"3ed675f15947\">Mapping pipeline (lidar \u2192 occupancy grid), deployment mode recording, workflow inference, package upload to S3/Coordinator. The full teleop-to-autonomous pipeline.</p></td><td data-local-id=\"0f8fe8b33a96\" class=\"confluenceTd\"><p local-id=\"ac8cbfc66f8b\">Demonstrated on robot</p></td></tr><tr data-local-id=\"ca0cfa8b6368\"><td data-local-id=\"f4466c49be3c\" class=\"confluenceTd\"><p local-id=\"02a5a98cdbe1\"><strong>Release Stabilization</strong></p></td><td data-local-id=\"f1495acb0604\" class=\"confluenceTd\"><p local-id=\"8bdb6e94212d\">Immutable, full-platform release images that fully capture all software running on the robot \u2014 OS, controls, policies, maps, agent runtime. Deployment team can run the latest release without chasing version mismatches between components.</p></td><td data-local-id=\"a5f888e5b34e\" class=\"confluenceTd\"><p local-id=\"2f8932fe9d57\">Ongoing pain point</p></td></tr></tbody></table></div><p local-id=\"1fb0e9febebf\"><strong>Exit criteria:</strong> One robot, one site (internal), operator-authored workflow executing autonomously end-to-end. Shitty is fine. Working is mandatory.</p><p local-id=\"68f39584bb76\"><strong><span class=\"inline-comment-marker\" data-ref=\"fbe14fd6-f62c-4179-997d-3dd1517d022e\">Known fires running in parallel (not part of this plan, but consuming people):</span></strong></p><ul local-id=\"2d2887ca374a\"><li local-id=\"e49b72518e05\"><p local-id=\"6e0e1de75226\">Hannover Messe Expo: Apr 20\u201324</p></li><li local-id=\"497b8cff5de4\"><p local-id=\"daf40c017c4e\"><del>Siemens Amberg PoC: ~May</del> \u2014 cancelled. This time is now available. Use it.</p></li></ul><hr local-id=\"63180ac5cd4c\"/><h2 local-id=\"cf1c9ec91ca1\" id=\"RoadtoPilot\u2014Epic-LevelPlan-Phase2:ShittyPilotv0\">Phase 2: Shitty Pilot v0</h2><p local-id=\"6902524fc83d\"><strong>June \u2013 July 2026</strong></p><p local-id=\"9d61106cd343\"><em>Goal: Run the product loop continuously on a Schaeffler-representative setup internally. Find out where it falls over.</em></p><div class=\"table-wrap\"><table data-table-width=\"1800\" data-layout=\"default\" data-local-id=\"d53535cd4598\" class=\"confluenceTable\"><tbody><tr data-local-id=\"dcc850a46a0c\"><th data-local-id=\"b2b25784930c\" class=\"confluenceTh\"><p local-id=\"56007f5fcda3\">Epic</p></th><th data-local-id=\"3c0726c3d198\" class=\"confluenceTh\"><p local-id=\"57cd5a4d0a65\">What it means</p></th><th data-local-id=\"926acefb01ae\" class=\"confluenceTh\"><p local-id=\"5f0c36477564\">Notes</p></th></tr><tr data-local-id=\"65f1b4a24c8c\"><td data-local-id=\"6db0409a4758\" class=\"confluenceTd\"><p local-id=\"f8b2aa15216a\"><strong>Schaeffler Use Case Standup</strong></p></td><td data-local-id=\"ba78b927d808\" class=\"confluenceTd\"><p local-id=\"7dc7b4401c51\">Ring picking workflow authored and running on internal setup. Measure actual UPH. Identify gaps to 440 target.</p></td><td data-local-id=\"425f40655755\" class=\"confluenceTd\"><p local-id=\"32774233cd1a\">Requires use-case-specific policy work + gripper readiness</p></td></tr><tr data-local-id=\"14cc5599a9a5\"><td data-local-id=\"1174061346aa\" class=\"confluenceTd\"><p local-id=\"7e8396287181\"><strong>Multi-Robot Coordination (Minimum)</strong></p></td><td data-local-id=\"70153f375bdd\" class=\"confluenceTd\"><p local-id=\"a68157ec6296\">2+ robots operating simultaneously without conflicts. Idle states, task handoff, charging hot-swap.</p></td><td data-local-id=\"955b636a1b66\" class=\"confluenceTd\"><p local-id=\"091c8295271f\">Fleet manager already needs idle state (Hannover blocker) \u2014 build on that</p></td></tr><tr data-local-id=\"904db50377f3\"><td data-local-id=\"0285209bb51e\" class=\"confluenceTd\"><p local-id=\"cb96b6107a60\"><strong>KPI Instrumentation</strong></p></td><td data-local-id=\"31dfaf4a7199\" class=\"confluenceTd\"><p local-id=\"8bd2a9511f18\">Can we actually <em>measure</em> UPH, uptime, navigation success rate, cycle time? If we can't measure it, we can't hit it.</p></td><td data-local-id=\"99a987afbe58\" class=\"confluenceTd\"><p local-id=\"e4fcf63827bf\">This is embarrassingly absent right now</p></td></tr><tr data-local-id=\"ba864999a1f9\"><td data-local-id=\"50f32b723e7d\" class=\"confluenceTd\"><p local-id=\"22f84099ac74\"><strong>Operator Iteration Workflow</strong></p></td><td data-local-id=\"a205d2de5e59\" class=\"confluenceTd\"><p local-id=\"210c3ce270b1\">Operator reviews execution, identifies failures, edits workflow, redeploys \u2014 without engineering. The &quot;iterate&quot; part of the loop.</p></td><td data-local-id=\"cf91d9dcf294\" class=\"confluenceTd\"><p local-id=\"6bdfc04d7723\">Conformance checking, Sockpuppet feedback, workflow versioning</p></td></tr></tbody></table></div><p local-id=\"3dd77825dd3d\"><strong>Exit criteria:</strong> Robots running Schaeffler ring-picking workflow daily, with KPI dashboards showing where we stand vs. MSA targets. A clear list of &quot;this is why we'd fail the pilot today.&quot;</p><hr local-id=\"7fd35f51defb\"/><h2 local-id=\"daace8c16064\" id=\"RoadtoPilot\u2014Epic-LevelPlan-Phase3:Harden\">Phase 3: Harden</h2><p local-id=\"e0e94582ab6f\"><strong>August \u2013 October 2026</strong></p><p local-id=\"26f5bbde63d6\"><em>Goal: Close the gap between &quot;shitty pilot&quot; and &quot;meets MSA KPIs.&quot; This phase is intentionally underspecified \u2014 it gets filled by whatever Phase 2 reveals.</em></p><div class=\"table-wrap\"><table data-table-width=\"1800\" data-layout=\"default\" data-local-id=\"9a46d33dee2b\" class=\"confluenceTable\"><tbody><tr data-local-id=\"267216dae48f\"><th data-local-id=\"2d9ce93b7869\" class=\"confluenceTh\"><p local-id=\"534e78f4ea68\">Epic</p></th><th data-local-id=\"06b93bf5b3e6\" class=\"confluenceTh\"><p local-id=\"9a1683777797\">What it means</p></th><th data-local-id=\"ed4ee6260e9a\" class=\"confluenceTh\"><p local-id=\"8ba5f8ab50a6\">Notes</p></th></tr><tr data-local-id=\"df2a57268fb3\"><td data-local-id=\"de43c1d501b3\" class=\"confluenceTd\"><p local-id=\"ea141dc37d0a\"><strong>[TBD] Top failures from v0</strong></p></td><td data-local-id=\"92f0460172be\" class=\"confluenceTd\"><p local-id=\"8f77cf91752e\">Whatever the top 3\u20135 failure modes are from Phase 2. Could be controls, could be mapping, could be fleet coordination, could be something we haven't thought of.</p></td><td data-local-id=\"f3c005191c6c\" class=\"confluenceTd\"><p local-id=\"b6da9d7d97b6\"><em>This is the whole point of the approach</em></p></td></tr><tr data-local-id=\"e4ef2e8b7da1\"><td data-local-id=\"7543d2bda9ee\" class=\"confluenceTd\"><p local-id=\"6789427c8aae\"><strong>Secondary Use Case Development</strong></p></td><td data-local-id=\"c340e5c8b620\" class=\"confluenceTd\"><p local-id=\"c57dd1420771\">End-of-line package handling \u2014 the use case that hasn't been attempted yet. This is the highest-risk Schaeffler KPI.</p></td><td data-local-id=\"2c27e99439f3\" class=\"confluenceTd\"><p local-id=\"dab153dd1f85\">Needs to start no later than August</p></td></tr><tr data-local-id=\"e64f53d7f827\"><td data-local-id=\"3d36cd37768f\" class=\"confluenceTd\"><p local-id=\"0bfad262f301\"><strong>Release &amp; Deployment Pipeline</strong></p></td><td data-local-id=\"4c3d97e34689\" class=\"confluenceTd\"><p local-id=\"30fa48e92c61\">OTA updates that work reliably. Map updates without rebuilding release images. Consistent policy versioning. The boring stuff that kills you in sustained ops.</p></td><td data-local-id=\"823e02849441\" class=\"confluenceTd\"><p local-id=\"2fb44433167b\">OTA already in progress. Map-baking issue known.</p></td></tr><tr data-local-id=\"4f09d074f2cc\"><td data-local-id=\"bbbe273eb876\" class=\"confluenceTd\"><p local-id=\"1328f125c8db\"><strong>Fleet Ops Minimum Viable</strong></p></td><td data-local-id=\"cc5771501e9e\" class=\"confluenceTd\"><p local-id=\"6f169d176ec2\">Enough monitoring, alerting, and remote diagnostics to keep robots running without an engineer on-site 24/7. Not a full NOC \u2014 just enough.</p></td><td data-local-id=\"bc316eada270\" class=\"confluenceTd\"><p local-id=\"2652ba2a614c\">On-robot logging service feeds into this</p></td></tr></tbody></table></div><p local-id=\"66b7e76bc8b2\"><strong>Exit criteria:</strong> KPIs trending toward MSA targets. Secondary use case demonstrated. Team confident enough to put robots on a truck to Schaeffler.</p><hr local-id=\"1ac18f179f51\"/><h2 local-id=\"a54eb071c04b\" id=\"RoadtoPilot\u2014Epic-LevelPlan-Phase4:Pilot\">Phase 4: Pilot</h2><p local-id=\"a5dcb6287abc\"><strong>November \u2013 December 2026</strong></p><p local-id=\"e08bf81b25d2\"><em>Goal: Robots operating at Schaeffler, meeting MSA commitments.</em></p><div class=\"table-wrap\"><table data-table-width=\"1800\" data-layout=\"default\" data-local-id=\"487d5240a565\" class=\"confluenceTable\"><tbody><tr data-local-id=\"cecc3de040a8\"><th data-local-id=\"d7c70034e2b2\" class=\"confluenceTh\"><p local-id=\"bba363250ac0\">Epic</p></th><th data-local-id=\"504c90b4383c\" class=\"confluenceTh\"><p local-id=\"6bf18a9b91fc\">What it means</p></th><th data-local-id=\"f97102f8821c\" class=\"confluenceTh\"><p local-id=\"b10147d4ccb3\">Notes</p></th></tr><tr data-local-id=\"1e334502786b\"><td data-local-id=\"e0d44efd6578\" class=\"confluenceTd\"><p local-id=\"29b6d9ac8ce0\"><strong>Site Deployment</strong></p></td><td data-local-id=\"24e76b54ffc5\" class=\"confluenceTd\"><p local-id=\"8c2c642f9c5c\">Physical deployment, <span class=\"inline-comment-marker\" data-ref=\"ee8ec935-ff70-49e4-ad50-f36b514a5842\">network bringup</span>, site acceptance test, operator training.</p></td><td data-local-id=\"168fda3c6365\" class=\"confluenceTd\"><p local-id=\"0680ef67e6ed\">Deployment readiness work feeds directly here</p></td></tr><tr data-local-id=\"2d93bb6a9145\"><td data-local-id=\"a279809afcd9\" class=\"confluenceTd\"><p local-id=\"2f25655bded2\"><strong>Sustained Operations</strong></p></td><td data-local-id=\"be32ff1dc6bb\" class=\"confluenceTd\"><p local-id=\"74c2ccd6dcd7\">Daily operation against MSA KPIs. Issue triage, remote support, on-site presence as needed.</p></td><td data-local-id=\"d523b35ad961\" class=\"confluenceTd\"><p local-id=\"49b5d9ffa8df\" /></td></tr><tr data-local-id=\"219bbba12ca6\"><td data-local-id=\"b147186fa676\" class=\"confluenceTd\"><p local-id=\"caced818d257\"><strong>KPI Validation &amp; Reporting</strong></p></td><td data-local-id=\"268bad83741d\" class=\"confluenceTd\"><p local-id=\"32d2c26859b3\">Formal measurement against SoW KPIs. Schaeffler sign-off.</p></td><td data-local-id=\"dd14df14ca87\" class=\"confluenceTd\"><p local-id=\"d0ae63715907\" /></td></tr></tbody></table></div><hr local-id=\"7f0164e4dc14\"/><h2 local-id=\"32f5f7812861\" id=\"RoadtoPilot\u2014Epic-LevelPlan-WhatThisPlanDeliberatelyDoesNOTInclude\">What This Plan Deliberately Does NOT Include</h2><ul local-id=\"bb6a1f163c84\"><li local-id=\"3b66e03070e6\"><p local-id=\"bbe715393b5a\"><strong>The 300+ PB backlog items.</strong> Most of those are noise until the product loop is closed and we have real operational data.</p></li><li local-id=\"39fe103e1831\"><p local-id=\"4b1e0ec859be\"><strong>Flow requirements as written.</strong> The requirements doc is a feature wishlist, not a buildable spec. We will derive real requirements from pilot failure data.</p></li><li local-id=\"0c4573825934\"><p local-id=\"3ee8d87de084\"><strong><span class=\"inline-comment-marker\" data-ref=\"27777db3-2e06-4bea-b8f5-b4dfce6b5bb9\">Full fleet management / NOC / global platform.</span></strong><span class=\"inline-comment-marker\" data-ref=\"27777db3-2e06-4bea-b8f5-b4dfce6b5bb9\"> That's a 2027 problem. We need to prove we can run 3 robots at one site first.</span></p></li><li local-id=\"446ce3c6c48f\"><p local-id=\"85d76b8321c9\"><strong>Home / consumer product stream.</strong> Separate track, separate plan.</p></li><li local-id=\"93d615e91ed9\"><p local-id=\"23a8ae540a6d\"><strong>VDA5050, <span class=\"inline-comment-marker\" data-ref=\"618fecd1-8c32-49f8-9735-ef480d61d956\">enterprise integrations</span>, multi-tenant isolation.</strong> Important eventually. Not blocking the pilot.</p></li></ul><hr local-id=\"a4dc6f3f4357\"/><h2 local-id=\"5d6eab4412d5\" id=\"RoadtoPilot\u2014Epic-LevelPlan-Dependencies&amp;Risks\">Dependencies &amp; Risks</h2><div class=\"table-wrap\"><table data-table-width=\"1800\" data-layout=\"default\" data-local-id=\"7f99c5ec2fa6\" class=\"confluenceTable\"><tbody><tr data-local-id=\"2fa6949b0cb2\"><th data-local-id=\"d9000cc0a591\" class=\"confluenceTh\"><p local-id=\"2c41877fa671\">Risk</p></th><th data-local-id=\"015165c62298\" class=\"confluenceTh\"><p local-id=\"fec97e071eb7\">Impact</p></th><th data-local-id=\"4a8933ddf7e4\" class=\"confluenceTh\"><p local-id=\"b522758be450\">Mitigation</p></th></tr><tr data-local-id=\"6cc5cb3775c6\"><td data-local-id=\"d4c776d0a669\" class=\"confluenceTd\"><p local-id=\"fd74d2879077\">Gripper hardware not ready for ring picking</p></td><td data-local-id=\"c1ff583e2e42\" class=\"confluenceTd\"><p local-id=\"230cf76b5461\">Blocks Phase 2 entirely</p></td><td data-local-id=\"bfd0f2c9cdd7\" class=\"confluenceTd\"><p local-id=\"abb3330d8a4d\">HECO-2526 (3-finger gripper v1.3.2) \u2014 track weekly, escalate early</p></td></tr><tr data-local-id=\"25cb0a32774e\"><td data-local-id=\"305ca9aa552a\" class=\"confluenceTd\"><p local-id=\"69a086c1337d\">Symphony V2 + deployment MVP don't integrate cleanly by May</p></td><td data-local-id=\"4b8995706b76\" class=\"confluenceTd\"><p local-id=\"71f39f95a310\">Phase 1 slips, everything shifts</p></td><td data-local-id=\"5c19e4b172e5\" class=\"confluenceTd\"><p local-id=\"6469c6d898a9\">Single integration owner needed. Treat PB-404 as the integration ticket.</p></td></tr><tr data-local-id=\"9b7e1f676393\"><td data-local-id=\"b8262e3b2600\" class=\"confluenceTd\"><p local-id=\"deda55a6fe08\">Release quality stays broken</p></td><td data-local-id=\"0f5d30c8ba5d\" class=\"confluenceTd\"><p local-id=\"125da44dabcb\">Every phase is harder if deployment can't use latest software</p></td><td data-local-id=\"b751da6d6e00\" class=\"confluenceTd\"><p local-id=\"27f83f391d2d\">Release stabilization is Phase 1 scope, not a nice-to-have</p></td></tr><tr data-local-id=\"8fa431e594a6\"><td data-local-id=\"95abf3eb45c8\" class=\"confluenceTd\"><p local-id=\"327dfcba0939\">Secondary use case (package handling) is harder than expected</p></td><td data-local-id=\"0134e8c89cb4\" class=\"confluenceTd\"><p local-id=\"669f64f480c4\">MSA KPI miss</p></td><td data-local-id=\"87b3d3aa4930\" class=\"confluenceTd\"><p local-id=\"484dba4d6c82\">Start early in Phase 3, treat as highest-priority unknown</p></td></tr><tr data-local-id=\"456371ea880c\"><td data-local-id=\"82ef2b2b6a24\" class=\"confluenceTd\"><p local-id=\"f97cb1201904\">Hannover + Siemens PoC consume key people through May</p></td><td data-local-id=\"09f79fbb404b\" class=\"confluenceTd\"><p local-id=\"bd7994d3555e\">Phase 1 work slows</p></td><td data-local-id=\"7b7cb6b41b88\" class=\"confluenceTd\"><p local-id=\"73c996fc40dc\">Accept it. Plan for reduced velocity April\u2013May.</p></td></tr><tr data-local-id=\"7a5ea2cd2c03\"><td data-local-id=\"4188b543f21d\" class=\"confluenceTd\"><p local-id=\"791ceeea968f\">Beta hardware delays affect robot availability</p></td><td data-local-id=\"ec578233e9c0\" class=\"confluenceTd\"><p local-id=\"2119d3f90adf\">Can't run enough robots for multi-robot testing</p></td><td data-local-id=\"05c880a0955d\" class=\"confluenceTd\"><p local-id=\"333ad0d437bc\">Monitor Beta-0 build schedule. Worst case, run on Alpha fleet.</p></td></tr></tbody></table></div><hr local-id=\"9a389d56c8d5\"/><h2 local-id=\"8af68bd54665\" id=\"RoadtoPilot\u2014Epic-LevelPlan-HowtoReadThisPlan\">How to Read This Plan</h2><p local-id=\"f435f08c124d\">This is a <em>direction</em>, not a Gantt chart. The phases are real and the exit criteria matter. The specific epics in Phases 2\u20133 will evolve as we learn. That's not a bug \u2014 that's the entire strategy.</p><p local-id=\"933c9ae7490b\">If the product loop works in Phase 1, we will have the fastest possible feedback mechanism to figure out what actually matters for the pilot. If it doesn't work, nothing else on any backlog matters anyway.</p>"
        },
        {
          "id": "1821671441",
          "title": "Robot Observability",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1821671441",
          "last_modified": "2026-04-01T14:59:51.610Z",
          "created_at": "2026-04-01T14:55:44.488Z",
          "body_html": "<h1 local-id=\"5c7fdf166755\" id=\"RobotObservability-RobotObservability\">Robot Observability</h1><p local-id=\"d0b33fd8bc4a\">This page is the practical guide to the HMND robot observability stack.</p><p local-id=\"19313469ae23\">It is meant to answer four questions:</p><ol start=\"1\" local-id=\"3db3933922f8\"><li local-id=\"00d3dee8d89b\"><p local-id=\"477c49aa503c\">What do we collect, and why?</p></li><li local-id=\"2692933e80bb\"><p local-id=\"bbade6a936da\">How does data get from a robot into Grafana?</p></li><li local-id=\"78483d761520\"><p local-id=\"cb492611ec48\">How do I instrument a node in <code>hmnd_robot</code>?</p></li><li local-id=\"8b251ff21155\"><p local-id=\"f2cbbe83d3d5\">How do I make that data show up in dashboards?</p></li></ol><p local-id=\"cf25b71d9f0c\">The goal is not exhaustive telemetry or full-fidelity replay of every internal signal. The goal is constant observability of enough data to diagnose real robot issues quickly and reliably.</p><p local-id=\"97a8ca256080\">In practice that means:</p><ul local-id=\"848405e2367c\"><li local-id=\"f80c1340a664\"><p local-id=\"47d8fa0aa87e\">We continuously ship low-cost metrics and logs.</p></li><li local-id=\"208052a0b951\"><p local-id=\"9b5073cd36d9\">We preserve the metadata needed to segment by robot, platform, and target.</p></li><li local-id=\"91d6f5fa3879\"><p local-id=\"2b5722cb3a10\">We use metrics for trends, rates, health, and distributions.</p></li><li local-id=\"fc83c623973e\"><p local-id=\"9a344963466b\">We use logs for sparse, structured events and explanations.</p></li><li local-id=\"b6d55abd4e00\"><p local-id=\"ed2c729d7de7\">We do <strong>not</strong> try to stream arbitrary high-rate control internals as observability data.</p></li><li local-id=\"28ba85fb554f\"><p local-id=\"e3140a90ed16\">If we need full-fidelity debugging or offline analysis, that is a rosbag / MCAP problem, not a Prometheus problem.</p></li></ul><h2 local-id=\"3dfe1de1b801\" id=\"RobotObservability-StackOverview\">Stack Overview</h2><p local-id=\"3f0b913d3e71\">At a high level:</p><p local-id=\"2fbc1aed365b\"><code>robot exporters + host/system logs -&gt; Vector on robot -&gt; Mimir/Loki/Tempo -&gt; Grafana</code></p><p local-id=\"2e7e8b3fd6ef\">The deployed stack today is:</p><ul local-id=\"93b5b6943354\"><li local-id=\"43bb40323588\"><p local-id=\"7cb6e60fa78e\"><strong>Grafana</strong> for visualization and exploration.</p></li><li local-id=\"70ea5b2fa4f5\"><p local-id=\"379789a58028\"><strong>Mimir</strong> for Prometheus-compatible time-series metrics.</p></li><li local-id=\"87f162567023\"><p local-id=\"1220b27fc9d9\"><strong>Loki</strong> for logs.</p></li><li local-id=\"513115a06233\"><p local-id=\"4f44f9171637\"><strong>Tempo</strong> for traces.</p></li><li local-id=\"e14008d19306\"><p local-id=\"7ece122b95b8\"><strong>Vector</strong> on each robot as the local collection, enrichment, buffering, and forwarding agent.</p></li></ul><p local-id=\"8e04e0c1d9c6\">Related background page:</p><ul local-id=\"e19136199101\"><li local-id=\"cb6d55d1d6b4\"><p local-id=\"06e448cce436\"><code>Observability Stack (Grafana/Loki/Tempo/Mimir)</code></p></li></ul><h2 local-id=\"66ce773f9f29\" id=\"RobotObservability-TheMentalModel\">The Mental Model</h2><p local-id=\"2296dc5097c5\">A useful way to think about observability on robots is:</p><ul local-id=\"966e35f1ea9b\"><li local-id=\"b8b3b20b8e4f\"><p local-id=\"c531d90134e2\"><strong>Metrics</strong> answer: &quot;is this healthy, how often is it happening, how big is it, what is the distribution?&quot;</p></li><li local-id=\"cac06c2411ff\"><p local-id=\"9b651663fa72\"><strong>Logs</strong> answer: &quot;what happened, where, and why?&quot;</p></li><li local-id=\"8f28c1abf5b8\"><p local-id=\"ed254fe2fe75\"><strong>Rosbags / MCAP</strong> answer: &quot;what exactly happened sample-by-sample?&quot;</p></li></ul><p local-id=\"3820729d6c85\">Those are different tools for different jobs.</p><h3 local-id=\"34b17bfcf2db\" id=\"RobotObservability-Whywedonotlogeverything\">Why we do not log everything</h3><p local-id=\"899a4e336f52\">A robot has many signals that update at high frequency. Some of those are control-loop internals, raw sensor streams, and dense state vectors. Continuously shipping all of that as centralized observability data would be expensive, noisy, and hard to query.</p><p local-id=\"a5a7e9386f1a\">For example, trying to push impedance internals at 1000 Hz into a metrics backend is the wrong abstraction:</p><ul local-id=\"927675abda6d\"><li local-id=\"acf41cc713ae\"><p local-id=\"d23ffd9d2289\">It creates unnecessary write volume.</p></li><li local-id=\"cff0710076c5\"><p local-id=\"8e2965106ab4\">It explodes cardinality if labels are added carelessly.</p></li><li local-id=\"3e3b23acad56\"><p local-id=\"36965ede2012\">It makes dashboards harder to interpret.</p></li><li local-id=\"05ed6f2a7650\"><p local-id=\"a4b913d686c6\">It still does not preserve the full context needed for offline replay.</p></li></ul><p local-id=\"c58fc8ccadfb\">Instead, we prefer compact health signals such as:</p><ul local-id=\"fca1f507672d\"><li local-id=\"c67613a67afb\"><p local-id=\"3b3f2160b171\">loop period histograms</p></li><li local-id=\"138d7b31dc25\"><p local-id=\"382d4677a391\">compute time histograms</p></li><li local-id=\"12bff717869c\"><p local-id=\"06bccbc53682\">overrun counters</p></li><li local-id=\"e4d31889188e\"><p local-id=\"f8355dc64268\">queue drop counters</p></li><li local-id=\"e37933848132\"><p local-id=\"e68b29f25412\">publish-rate gauges</p></li><li local-id=\"eff0f80bc43f\"><p local-id=\"b177b32f3c76\">delay / latency histograms</p></li><li local-id=\"0d1634ec84c5\"><p local-id=\"1c8387242c9d\">error counters by category</p></li></ul><p local-id=\"9b40e2711fec\">That gives us continuous fleet-scale visibility at a cost that actually scales.</p><h2 local-id=\"860d13dbb907\" id=\"RobotObservability-GrafanaStack:WhatGoesWhere\">Grafana Stack: What Goes Where</h2><h3 local-id=\"db499ce18c7d\" id=\"RobotObservability-Grafana\">Grafana</h3><p local-id=\"95802c9388b9\">Grafana is the operator-facing UI.</p><p local-id=\"1e71c02473d1\">Use it for:</p><ul local-id=\"2f27318b91c4\"><li local-id=\"ae4119aaff80\"><p local-id=\"a03d6b036356\">dashboards</p></li><li local-id=\"decf3cee309b\"><p local-id=\"9739e5a5bd73\">ad hoc exploration in Explore</p></li><li local-id=\"8563e820cfbb\"><p local-id=\"f65a626487c1\">fleet comparisons</p></li><li local-id=\"258687d1f15e\"><p local-id=\"12ab51f6d7f4\">robot-specific drill-downs</p></li><li local-id=\"338a46cc1a1d\"><p local-id=\"836c0d2203d7\">PromQL / LogQL / Tempo queries</p></li></ul><p local-id=\"f3b5bd8ad9b9\">Grafana does not store the data itself. It queries the backends.</p><h3 local-id=\"caa4182d3534\" id=\"RobotObservability-Mimir/Prometheus-compatiblemetrics\">Mimir / Prometheus-compatible metrics</h3><p local-id=\"357e4aaa7cc6\">Mimir stores our Prometheus-style metrics. Exporters expose <code>/metrics</code>, Vector scrapes those endpoints locally, and Vector remote-writes the samples to Mimir.</p><p local-id=\"6efec6e77eff\">This is the right fit for:</p><ul local-id=\"2e809aef2596\"><li local-id=\"7359de0051ea\"><p local-id=\"99cc5cefc19a\">counters</p></li><li local-id=\"6c34d106290e\"><p local-id=\"b8297c1c73d3\">gauges</p></li><li local-id=\"2b6c0c357d8b\"><p local-id=\"494fbfe7a710\">histograms</p></li><li local-id=\"c1c08d2a57e0\"><p local-id=\"4df64154c8fa\">derived rates</p></li><li local-id=\"b8fee3a68385\"><p local-id=\"081abc93440b\">percentiles computed from histogram buckets</p></li><li local-id=\"2436db48c90a\"><p local-id=\"9733632cb3ef\">alertable health signals</p></li></ul><h3 local-id=\"f95ea5cdaa63\" id=\"RobotObservability-Lokilogs\">Loki logs</h3><p local-id=\"577bf497151c\">Loki stores logs. On robot, Vector tails journald and internal logs, enriches them with robot metadata, and pushes them to Loki.</p><p local-id=\"6b51cd655183\">This is the right fit for:</p><ul local-id=\"11f3b297db63\"><li local-id=\"412cb1ec2df3\"><p local-id=\"816dbe97df74\">structured error events</p></li><li local-id=\"855328ae3d5a\"><p local-id=\"6c7463102e90\">startup / shutdown records</p></li><li local-id=\"9b22d22adf1b\"><p local-id=\"9bc4d7efa61a\">retry / failure reasons</p></li><li local-id=\"58ed6a18579f\"><p local-id=\"9a34fda2f1c5\">human-readable context around incidents</p></li><li local-id=\"90c40cb5f1b9\"><p local-id=\"bfadb3b9b2af\">sparse lifecycle breadcrumbs</p></li></ul><h3 local-id=\"8002c87e4457\" id=\"RobotObservability-Tempotraces\">Tempo traces</h3><p local-id=\"69269a59b96b\">Tempo is available for distributed traces and OTLP spans. It is useful for request-like flows, especially for services such as sockpuppet or reverb.</p><p local-id=\"c30aacf10951\">This page focuses mainly on metrics and logs, since that is the core robot observability path today.</p><h2 local-id=\"590132c55d84\" id=\"RobotObservability-Metrics101forRobotCode\">Metrics 101 for Robot Code</h2><h3 local-id=\"507f45da5edd\" id=\"RobotObservability-Counter\">Counter</h3><p local-id=\"210abe7121cb\">A counter only goes up.</p><p local-id=\"956f109a6de5\">Use a counter for things like:</p><ul local-id=\"25765a2cb79e\"><li local-id=\"e87bd2dcebb8\"><p local-id=\"d8f4ca807e3e\">messages received total</p></li><li local-id=\"6fe03cfb4cce\"><p local-id=\"c03bdcd971ed\">compute overruns total</p></li><li local-id=\"49a6a0003861\"><p local-id=\"b26419049c58\">queue drops total</p></li><li local-id=\"5c28e3454f05\"><p local-id=\"9b93c9f94b0c\">errors total</p></li><li local-id=\"e51365898e4d\"><p local-id=\"5cca6c33d7cd\">episodes saved total</p></li></ul><p local-id=\"e04a552a1bad\">Typical query pattern:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"5f24e058-2a8c-41c7-b819-4ddfe3452cea\" data-local-id=\"6b01d79f62e0\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">rate(hmnd_wbc_command_missed_cycles_total[5m])</pre>\n</div></div><p local-id=\"68dda65ae480\">That tells you the recent rate of failures, which is usually more useful than the raw cumulative count.</p><h3 local-id=\"efcfa17ee24c\" id=\"RobotObservability-Gauge\">Gauge</h3><p local-id=\"ec6ad6668394\">A gauge is the current value of something.</p><p local-id=\"f7223b618305\">Use a gauge for things like:</p><ul local-id=\"5df08d82ff7b\"><li local-id=\"fbf056ea25ac\"><p local-id=\"015073913912\">publish rate in Hz</p></li><li local-id=\"cbb5eada06a4\"><p local-id=\"cb5035be19b8\">current queue depth</p></li><li local-id=\"8cc628700f10\"><p local-id=\"deb7ca24d07c\">current battery percentage</p></li><li local-id=\"2627a73a355d\"><p local-id=\"5113e9dcc9ca\">current overrun ratio in a recent window</p></li><li local-id=\"526f873d2c90\"><p local-id=\"f9e0562a32ef\">latest observed delay</p></li></ul><p local-id=\"06c08c6acd34\">Typical query pattern:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"94008f7d-12a2-4276-8a3d-294e13fce269\" data-local-id=\"08e77371b767\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">hmnd_wbc_compute_overrun_ratio{hmnd_robot_id=&quot;$robot&quot;}</pre>\n</div></div><h3 local-id=\"c600bd3b5086\" id=\"RobotObservability-Histogram\">Histogram</h3><p local-id=\"5ad52e34ad5e\">A histogram records a distribution into fixed buckets.</p><p local-id=\"02e86d0fa5c5\">Use a histogram for things like:</p><ul local-id=\"da30f9153d14\"><li local-id=\"997c1837660d\"><p local-id=\"511c75ef6902\">loop period</p></li><li local-id=\"9926e7b208d6\"><p local-id=\"11928cb73bd6\">compute time</p></li><li local-id=\"3b87c2d9baff\"><p local-id=\"a57d5fcf7c0d\">frame poll delay</p></li><li local-id=\"2ae962688063\"><p local-id=\"0f944a0f938b\">inference latency</p></li><li local-id=\"0d28e1c4aae5\"><p local-id=\"f924a7bc800c\">end-to-end latency</p></li></ul><p local-id=\"e59dfcbe134c\">Histograms are the most important metric type for timing-sensitive robot systems because they let us answer questions like:</p><ul local-id=\"15e1e05ea890\"><li local-id=\"8a6734d9133c\"><p local-id=\"bbc8435f6ca6\">what is the median?</p></li><li local-id=\"d579516b9ec6\"><p local-id=\"480612b8c980\">what is the p95 or p99?</p></li><li local-id=\"285ff3c4dab4\"><p local-id=\"43feea0513af\">is the tail getting worse?</p></li><li local-id=\"642136011b0f\"><p local-id=\"41b23358b3d9\">are we jittering or drifting?</p></li><li local-id=\"a1f1f45c9689\"><p local-id=\"751acf1c2495\">which bucket mass is moving over time?</p></li></ul><p local-id=\"49e7e6c3af9c\">Typical query patterns:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"ba1da9eb-e9c1-408d-8c7a-10d704d695cc\" data-local-id=\"d297a6d82795\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">histogram_quantile(0.95, sum by (le) (rate(hmnd_wbc_command_publish_period_seconds_bucket[5m])))</pre>\n</div></div><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"54a8212a-4fd7-4b3d-9f95-7446b8f56df9\" data-local-id=\"af7866fe1aa3\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">histogram_quantile(0.99, sum by (le) (rate(hmnd_vision_topic_publish_period_seconds_bucket[5m])))</pre>\n</div></div><h3 local-id=\"76a705fc6fac\" id=\"RobotObservability-Summary\">Summary</h3><p local-id=\"123335e63c2f\"><code>hmnd_metrics</code> also exposes a summary helper, but in practice histograms are generally the better default for shared dashboards because bucketed histograms aggregate across instances cleanly.</p><h2 local-id=\"245a109af06f\" id=\"RobotObservability-Guidance:ChoosingtheRightMetric\">Guidance: Choosing the Right Metric</h2><p local-id=\"510f7e6d8b41\">Use this rule of thumb:</p><ul local-id=\"5427014a00c6\"><li local-id=\"428b34056c41\"><p local-id=\"66f7cb4c2047\">If you want to know <strong>how many times</strong> something happened, use a <strong>counter</strong>.</p></li><li local-id=\"5ae413344330\"><p local-id=\"acb93afc5a86\">If you want the <strong>current state</strong>, use a <strong>gauge</strong>.</p></li><li local-id=\"ff784c2856bd\"><p local-id=\"679d53ed0aa1\">If you care about the <strong>distribution of timings or sizes</strong>, use a <strong>histogram</strong>.</p></li></ul><p local-id=\"3830ce8c74d6\">On robots, timing histograms are usually more valuable than one-off gauges because they preserve tail behavior.</p><p local-id=\"897a57c23cd3\">For example:</p><ul local-id=\"5c6f8b5dde92\"><li local-id=\"4980ccbda89f\"><p local-id=\"e4c929e53b3b\">A gauge saying &quot;current loop time = 21 ms&quot; is weak.</p></li><li local-id=\"317e6890c32c\"><p local-id=\"65655f5e48ab\">A histogram saying &quot;p50 is 20 ms, p99 is 34 ms, tail got worse after 14:32&quot; is useful.</p></li></ul><h2 local-id=\"3a68b8ca4e73\" id=\"RobotObservability-MetricsvsLogsvsRosbags\">Metrics vs Logs vs Rosbags</h2><h3 local-id=\"898e2aaeaf33\" id=\"RobotObservability-Metrics\">Metrics</h3><p local-id=\"5115f2e12fa3\">Use metrics for continuous, cheap, queryable health signals.</p><p local-id=\"c123d724a893\">Good examples:</p><ul local-id=\"1168aa2c0636\"><li local-id=\"fe311dca0afc\"><p local-id=\"eece4ecc98b0\">WBC loop period</p></li><li local-id=\"e5f70ace0fd0\"><p local-id=\"041a1631a34f\">camera publish rate</p></li><li local-id=\"18000d32c32a\"><p local-id=\"6afed2a2c42f\">dropped frames</p></li><li local-id=\"cad62c757405\"><p local-id=\"0330039b571f\">policy inference latency</p></li><li local-id=\"002978e542c3\"><p local-id=\"b3d96ee5ef33\">controller overrun ratio</p></li><li local-id=\"c85e13b0f216\"><p local-id=\"e5664a83d41c\">battery percentage</p></li></ul><h3 local-id=\"621b20b2c77a\" id=\"RobotObservability-Logs\">Logs</h3><p local-id=\"39d8faaf0285\">Use logs for explanations and sparse events.</p><p local-id=\"451684769c82\">Good examples:</p><ul local-id=\"1425f5302ca1\"><li local-id=\"c121dd7932af\"><p local-id=\"c34fbca0967d\">hardware device failed to initialize</p></li><li local-id=\"de038f8db547\"><p local-id=\"9971797adc11\">configuration fallback was used</p></li><li local-id=\"6b69a33f821d\"><p local-id=\"54412363d9d9\">service reconnected after timeout</p></li><li local-id=\"254cb9368d39\"><p local-id=\"e3e4b1ef712b\">robot switched operating mode</p></li><li local-id=\"8c92f02bef35\"><p local-id=\"d54a50ac7f32\">a fault was raised or cleared</p></li></ul><h3 local-id=\"ac6d817476e8\" id=\"RobotObservability-Rosbags/MCAP\">Rosbags / MCAP</h3><p local-id=\"cc05583db3b4\">Use bags when you need full replay or dense signal inspection.</p><p local-id=\"ea7d00502242\">Good examples:</p><ul local-id=\"b0a3fec059e4\"><li local-id=\"468e378d57db\"><p local-id=\"714ac691d4e4\">actuator command debugging at controller rate</p></li><li local-id=\"8518a26c78f7\"><p local-id=\"c7d1ef81a31e\">raw sensor stream inspection</p></li><li local-id=\"224a95e813c1\"><p local-id=\"93f6d3975aa5\">synchronization bugs requiring exact timestamps</p></li><li local-id=\"d70c4c6f6e96\"><p local-id=\"88d6555fc470\">offline postmortems needing complete context</p></li></ul><p local-id=\"0d34ae2f393b\">The important distinction is that <strong>metrics/logs are always-on operational telemetry</strong>, while <strong>bags are episodic high-fidelity recordings</strong>.</p><h2 local-id=\"b63753f66fbe\" id=\"RobotObservability-CardinalityandScale\">Cardinality and Scale</h2><p local-id=\"6c66c752c802\">Prometheus-style systems scale well when each metric has a bounded number of label combinations.</p><p local-id=\"a4a0d1ba833d\">They scale badly when we attach unbounded labels such as:</p><ul local-id=\"1daf6bd35ff0\"><li local-id=\"e1c73925d4c5\"><p local-id=\"e5b0da362966\">raw IDs generated per request</p></li><li local-id=\"2dad9d35df17\"><p local-id=\"f7345a284438\">timestamps as labels</p></li><li local-id=\"030feee23094\"><p local-id=\"04558f72c87c\">paths or filenames with huge variety</p></li><li local-id=\"69416116771d\"><p local-id=\"5518d931e73e\">exception strings</p></li><li local-id=\"1b41f9a06e7a\"><p local-id=\"0b719f4749f2\">user-generated values</p></li><li local-id=\"a536743c8cfb\"><p local-id=\"caec34a896c1\">topic names that are dynamically synthesized without limit</p></li></ul><h3 local-id=\"d093eb20b6cb\" id=\"RobotObservability-Goodlabels\">Good labels</h3><p local-id=\"d10e47cd50eb\">Labels that are stable and bounded are good.</p><p local-id=\"6c217b59e5ee\">Examples we rely on heavily:</p><ul local-id=\"3ead1611b4e2\"><li local-id=\"39317efd51e5\"><p local-id=\"7f9271563257\"><code>hmnd_robot_id</code></p></li><li local-id=\"4f7723b21a08\"><p local-id=\"638d5fd1f38e\"><code>hmnd_robot_type</code></p></li><li local-id=\"9dac0509eee8\"><p local-id=\"e392f9bde5cd\"><code>hmnd_robot_target</code></p></li><li local-id=\"c6b3c4b845d7\"><p local-id=\"fca9c68ed700\"><code>controller</code></p></li><li local-id=\"cc22c0bc017e\"><p local-id=\"0770a11f5fa8\"><code>topic</code></p></li><li local-id=\"f2454f907c3e\"><p local-id=\"556f07b322e6\"><code>device</code></p></li><li local-id=\"d0c0e5071eef\"><p local-id=\"4b437e6d0543\"><code>error_type</code></p></li></ul><h3 local-id=\"7363a390dcb8\" id=\"RobotObservability-Badlabels\">Bad labels</h3><p local-id=\"76d53cdfe1d1\">Avoid labels whose value count grows without a clear upper bound.</p><p local-id=\"03c025ed3b41\">Examples:</p><ul local-id=\"4de3c4263b07\"><li local-id=\"81870ca7260b\"><p local-id=\"65edcf30fa98\">UUIDs</p></li><li local-id=\"82ca815a51fa\"><p local-id=\"22625071c2e5\">free-form error messages</p></li><li local-id=\"b6f5555cbd6a\"><p local-id=\"7538a4b2a478\">file paths</p></li><li local-id=\"62a0191d6e39\"><p local-id=\"9838d0df3b9e\">object names from untrusted input</p></li><li local-id=\"a686c8e45ec5\"><p local-id=\"f41b3cae4937\">per-frame IDs</p></li></ul><h3 local-id=\"388b305c5496\" id=\"RobotObservability-Practicalprinciple\">Practical principle</h3><p local-id=\"46bff3d3c453\">If a label value could create thousands or millions of new time series over time, it probably does not belong in metrics.</p><p local-id=\"fe6d96bc393b\">Put that information in logs instead.</p><h2 local-id=\"1022cfc65d9a\" id=\"RobotObservability-On-RobotCollection:Vectorandhmnd-shipping\">On-Robot Collection: Vector and <code>hmnd-shipping</code></h2><p local-id=\"6e6b79a95a29\">Vector is the agent that runs on the robot and makes the whole system operationally sane.</p><p local-id=\"3d235ab3b1ae\">It is responsible for:</p><ul local-id=\"9010c41c67d3\"><li local-id=\"f0db0d9e8a48\"><p local-id=\"b537ba2db89c\">scraping exporters</p></li><li local-id=\"c483cc96735d\"><p local-id=\"4417cb05f93c\">reading journald</p></li><li local-id=\"e51d6fc66a52\"><p local-id=\"35a181671c75\">reading Vector internal metrics/logs</p></li><li local-id=\"dc44c53edee4\"><p local-id=\"e222a572c0ec\">accepting OTLP traces</p></li><li local-id=\"1b4d9a151bfc\"><p local-id=\"4a15401d0f74\">enriching records with robot metadata</p></li><li local-id=\"7f39b25ff229\"><p local-id=\"c8ae1ef471b6\">buffering on disk when the network or backend is unavailable</p></li><li local-id=\"0394ef8a0434\"><p local-id=\"23282fafbc4b\">pushing data to Mimir, Loki, and Tempo</p></li></ul><h3 local-id=\"d91b9b197bf2\" id=\"RobotObservability-WhyVectorexistsinthemiddle\">Why Vector exists in the middle</h3><p local-id=\"b7662c3f4144\">Without Vector, every node would need to know:</p><ul local-id=\"4bc126d0a996\"><li local-id=\"08304bdd0491\"><p local-id=\"5ddb6a7c73e4\">backend endpoints</p></li><li local-id=\"5658894801f6\"><p local-id=\"2e7ad75c9125\">auth details</p></li><li local-id=\"53f333499da1\"><p local-id=\"43135bc44f15\">retry policy</p></li><li local-id=\"9a192cc29610\"><p local-id=\"f5b11bd033fd\">batching policy</p></li><li local-id=\"628802d10c5a\"><p local-id=\"2c5fbc32d6ed\">buffer policy</p></li><li local-id=\"83a4a3cf3d4a\"><p local-id=\"61aa166b9edb\">per-robot metadata labels</p></li></ul><p local-id=\"23d216c45d36\">That would be brittle and duplicated.</p><p local-id=\"47dbdb8070d1\">With Vector:</p><ul local-id=\"bf24edb85af2\"><li local-id=\"c06a64bc6a6b\"><p local-id=\"b38581f312c0\">exporters stay simple</p></li><li local-id=\"d9076dca7e7a\"><p local-id=\"a022cf3a8f6d\">application code only exposes local metrics or writes local logs</p></li><li local-id=\"23df610543f1\"><p local-id=\"643c5a9a72e3\">enrichment and delivery policy are centralized</p></li><li local-id=\"9e1389fb2b3e\"><p local-id=\"e26ebaab26c6\">temporary outages are absorbed by the agent buffer</p></li></ul><h2 local-id=\"c9de2b3e9147\" id=\"RobotObservability-hmnd-shippinglayout\"><code>hmnd-shipping</code> layout</h2><p local-id=\"323701ba0563\">The deployed Vector config is packaged through:</p><ul local-id=\"f188d0b6459f\"><li local-id=\"e1bc743e7e9b\"><p local-id=\"b3e923da0735\"><code>platforms/common/hmnd-shipping</code></p></li><li local-id=\"2645276b3128\"><p local-id=\"3fa4a1fbfed4\"><code>platforms/common/hmnd-shipping-robot</code></p></li></ul><p local-id=\"f7f8ca128203\">Important files:</p><ul local-id=\"d82b5ecf989a\"><li local-id=\"4a8b7f06ab3b\"><p local-id=\"7610ea179e80\"><code>platforms/common/hmnd-shipping/etc/hmnd/vector/common.yaml</code></p></li><li local-id=\"671cc3c3dbd9\"><p local-id=\"0240f812ba2d\"><code>platforms/common/hmnd-shipping-robot/etc/hmnd/vector/robot.yaml</code></p></li><li local-id=\"7ba8487d7d37\"><p local-id=\"fb77b4075771\"><code>platforms/common/hmnd-shipping/etc/systemd/system/vector.service.d/10-hmnd.conf</code></p></li></ul><h3 local-id=\"10d4df6c9a0e\" id=\"RobotObservability-Whatthecommonconfigdoes\">What the common config does</h3><p local-id=\"7aa9e9cdcace\">The common config defines the general data plane:</p><ul local-id=\"5d11aa335500\"><li local-id=\"fb1d2dd589f3\"><p local-id=\"f8ada63b0900\">journald log ingestion</p></li><li local-id=\"8aab4d9ac6c2\"><p local-id=\"69495a253214\">host metrics</p></li><li local-id=\"ca7378f8fa16\"><p local-id=\"c526a7d25ea4\">internal Vector metrics/logs</p></li><li local-id=\"7c51bcfa002d\"><p local-id=\"dc5d37e03448\">OTLP trace ingestion</p></li><li local-id=\"e2a34de5dd13\"><p local-id=\"9c4abdeb0204\">metadata enrichment transforms</p></li><li local-id=\"a0e14fd9e22f\"><p local-id=\"501357981efc\">sanitize transforms for problematic labels</p></li><li local-id=\"1c09930d93ba\"><p local-id=\"8d0d4d47f782\">sinks to Loki, Mimir, and Tempo</p></li></ul><p local-id=\"3f4488371783\">The key enrichment transform adds the robot identity labels from environment:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"bd777be2-302e-40d7-b169-6c63c0f23e0d\" data-local-id=\"b3f7f08884b2\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">.tags.hmnd_robot_type = get_env_var(&quot;ROBOT&quot;) ?? &quot;unknown&quot;\n.tags.hmnd_robot_id = get_env_var(&quot;ROBOT_ID&quot;) ?? &quot;unknown&quot;\n.tags.hmnd_robot_target = get_env_var(&quot;HMND_ROBOT_TARGET&quot;) ?? &quot;unknown&quot;</pre>\n</div></div><p local-id=\"afe4d5e5f7df\">That is what makes per-robot filtering in Grafana work consistently across exporters.</p><h3 local-id=\"ee5a4eedccb5\" id=\"RobotObservability-Whattherobotconfigdoes\">What the robot config does</h3><p local-id=\"cd1e388e14df\">The robot-specific config adds the Prometheus scrape endpoints for robot exporters.</p><p local-id=\"a71018fdfcd5\">Current scrape list includes ports such as:</p><ul local-id=\"45ebb862a6c6\"><li local-id=\"088e18911cc9\"><p local-id=\"342dfdb6db90\"><code>9201</code> <code>hmnd_vision</code></p></li><li local-id=\"6005f12b24f1\"><p local-id=\"20c4993c95e5\"><code>9202</code> <code>whole_body_controller</code></p></li><li local-id=\"eaa6e5adcd26\"><p local-id=\"29249f74a741\"><code>9203</code> <code>policy execution</code></p></li><li local-id=\"cd9381b6cd62\"><p local-id=\"d05271cc981c\"><code>9204</code> general HMND ROS exporter</p></li><li local-id=\"260935f8a5e2\"><p local-id=\"a4518a729eda\"><code>9205</code> <code>sockpuppet</code></p></li><li local-id=\"60a46861b0b4\"><p local-id=\"4821d2bb0b2c\"><code>9206</code> <code>alpha data collection</code></p></li><li local-id=\"c16d286853c2\"><p local-id=\"ea18c4fc6fec\"><code>9207</code> <code>reverb</code></p></li><li local-id=\"421da30c8e81\"><p local-id=\"e217afb6b610\"><code>9208</code> <code>hmnd_vio</code></p></li><li local-id=\"aa91a0021219\"><p local-id=\"57f800834fac\"><code>9209</code> controller overrun metrics</p></li><li local-id=\"cc74f60f9640\"><p local-id=\"d1a2aaeb362e\"><code>9210</code> teleoperation server</p></li><li local-id=\"cbd73da404e5\"><p local-id=\"8b9e738f2ad6\"><code>9212</code> FT gravity compensation diagnostics</p></li></ul><p local-id=\"119d415e543b\">That means adding a new exporter is usually a two-part change:</p><ol start=\"1\" local-id=\"32c43d0afe2d\"><li local-id=\"438cdbb0713d\"><p local-id=\"75bd48d17e0a\">expose a new local <code>/metrics</code> endpoint in the node</p></li><li local-id=\"7bbfc0e24717\"><p local-id=\"400cd80ccbf4\">add that endpoint to <code>hmnd-shipping-robot</code> so Vector scrapes it</p></li></ol><h3 local-id=\"4a47a84c0848\" id=\"RobotObservability-Bufferinganddeliverybehavior\">Buffering and delivery behavior</h3><p local-id=\"354898d505d2\">Vector is configured to batch conservatively and buffer to disk.</p><p local-id=\"f13c83cb9417\">That matters because robots can have intermittent connectivity, and we do not want every transient network failure to become dropped telemetry or backpressure inside application nodes.</p><p local-id=\"a98ce2b4102c\">The intent is:</p><ul local-id=\"f5cf5b5291fa\"><li local-id=\"abc159f8ce86\"><p local-id=\"e3ce2f31762d\">preserve robot resources first</p></li><li local-id=\"e3108ca4a5eb\"><p local-id=\"d549affd3266\">keep collection simple in the exporter</p></li><li local-id=\"0f5ed1041f96\"><p local-id=\"ec3a44f01ad1\">tolerate temporary backend or network problems</p></li><li local-id=\"64cc6f512bd1\"><p local-id=\"7b25d2f5b3c2\">avoid aggressive reconnect storms</p></li></ul><h2 local-id=\"fc6507876d25\" id=\"RobotObservability-InstrumentationAPI:hmnd_metrics\">Instrumentation API: <code>hmnd_metrics</code></h2><p local-id=\"09a56e5b9191\"><code>hmnd_metrics</code> is our shared library for exposing Prometheus metrics from robot code.</p><p local-id=\"c2109035388e\">It exists in:</p><ul local-id=\"ebc144200587\"><li local-id=\"57049dd78d76\"><p local-id=\"74e7cdc4c59e\"><code>ros/utils/hmnd_metrics</code></p></li></ul><p local-id=\"e48ef771ecce\">It supports both:</p><ul local-id=\"9317c44b7f3f\"><li local-id=\"1e6e6990bd06\"><p local-id=\"e298530b1b46\">Python exporters via <code>hmnd_metrics</code></p></li><li local-id=\"dbaca0a7b060\"><p local-id=\"309c718eeb3e\">C++ exporters via <code>hmnd::metrics</code></p></li></ul><h3 local-id=\"5fffd5e3afa6\" id=\"RobotObservability-Pythonpattern\">Python pattern</h3><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"2dad4b15-248d-4471-8f56-0d1f84068133\" data-local-id=\"2d111d103ffb\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">import hmnd_metrics\n\nhmnd_metrics.initialize_exporter(&quot;0.0.0.0:9207&quot;)\n\nrequests_total = hmnd_metrics.counter(\n    &quot;hmnd_mynode_requests_total&quot;,\n    &quot;Total requests processed&quot;,\n    labels=[&quot;endpoint&quot;],\n)\n\nlatency_seconds = hmnd_metrics.histogram(\n    &quot;hmnd_mynode_latency_seconds&quot;,\n    &quot;Request latency&quot;,\n    labels=[&quot;endpoint&quot;],\n    buckets=hmnd_metrics.HistogramBuckets.STANDARD_LATENCY.value,\n)\n\nrequests_total.labels(endpoint=&quot;/foo&quot;).inc()\nlatency_seconds.labels(endpoint=&quot;/foo&quot;).observe(0.025)</pre>\n</div></div><p local-id=\"18bf9391df14\">Important behaviors:</p><ul local-id=\"4e30465db190\"><li local-id=\"906367ccf468\"><p local-id=\"0bd04cd74c46\">initialize once per process</p></li><li local-id=\"eb9244921335\"><p local-id=\"3eb07df1aafc\">metrics are cached by name, type, labels, and buckets</p></li><li local-id=\"1b79d6f0db00\"><p local-id=\"0b9684998920\">use fixed, bounded label sets</p></li><li local-id=\"657cf9cd9bb4\"><p local-id=\"3887e00e1116\">use one exporter endpoint per process</p></li></ul><h3 local-id=\"6ab25075f245\" id=\"RobotObservability-C++pattern\">C++ pattern</h3><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"34bc8c8d-9b05-4b62-8db4-49b5e1f9f591\" data-local-id=\"4e2eca48ad6e\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: cpp; gutter: false; theme: Confluence\" data-theme=\"Confluence\">#include &lt;hmnd_metrics/metrics.hpp&gt;\n\nhmnd::metrics::InitializeExporter(&quot;0.0.0.0:9209&quot;);\n\nauto&amp; histogram = hmnd::metrics::HistogramFamily(\n    &quot;hmnd_mynode_latency_seconds&quot;, &quot;Latency&quot;);\n\nhistogram.Add({{&quot;topic&quot;, &quot;/foo&quot;}}, hmnd::metrics::StandardLatencyBuckets())\n    .Observe(0.025);</pre>\n</div></div><h3 local-id=\"fd265df85800\" id=\"RobotObservability-Namingconventions\">Naming conventions</h3><p local-id=\"39c4d8eb30a6\">Follow these conventions:</p><ul local-id=\"617593b70283\"><li local-id=\"69b1e177c40e\"><p local-id=\"da34f50154a9\">prefix metrics with <code>hmnd_&lt;subsystem&gt;_</code></p></li><li local-id=\"248833d908ac\"><p local-id=\"422bc0590e7b\">use <code>_total</code> for counters</p></li><li local-id=\"2cd286bed2c1\"><p local-id=\"d43654c16875\">use <code>_seconds</code> for durations</p></li><li local-id=\"a31e42b7b891\"><p local-id=\"8b1a33011ab4\">use snake_case</p></li><li local-id=\"bd239329ed17\"><p local-id=\"9be4acfe3e6b\">prefer stable subsystem prefixes such as <code>hmnd_wbc_*</code>, <code>hmnd_vision_*</code>, <code>hmnd_policy_*</code></p></li></ul><h3 local-id=\"b1791ca8c180\" id=\"RobotObservability-Portconventions\">Port conventions</h3><p local-id=\"10fdc1f8b966\">Current convention is:</p><ul local-id=\"9a0b4f456676\"><li local-id=\"90c8cb1ad02f\"><p local-id=\"5633d40dee35\"><code>91xx</code> for host daemons</p></li><li local-id=\"4972dc7e4d63\"><p local-id=\"98abe4d8a8a4\"><code>92xx</code> for robot nodes</p></li></ul><h2 local-id=\"0d292c0396e3\" id=\"RobotObservability-RealExamplesintheRepo\">Real Examples in the Repo</h2><h3 local-id=\"d6b6e6f6938f\" id=\"RobotObservability-Example:WBCinstrumentation\">Example: WBC instrumentation</h3><p local-id=\"49d175173a51\">The WBC node exposes loop health metrics on port <code>9202</code>.</p><p local-id=\"481ceb0a5d5b\">Relevant metrics include:</p><ul local-id=\"fa0983b8bc8d\"><li local-id=\"6fb0de220662\"><p local-id=\"91f0686c798a\"><code>hmnd_wbc_controller_period_seconds</code></p></li><li local-id=\"e62165ba4249\"><p local-id=\"d2623cb54736\"><code>hmnd_wbc_compute_time_seconds</code></p></li><li local-id=\"dbcce991b3a2\"><p local-id=\"56e0a43fb5a6\"><code>hmnd_wbc_compute_overrun_total</code></p></li><li local-id=\"a91f06318763\"><p local-id=\"64fefd997c96\"><code>hmnd_wbc_compute_overrun_ratio</code></p></li><li local-id=\"bf002ac2a8b1\"><p local-id=\"21961a0bbf8c\"><code>hmnd_wbc_commands_received_total</code></p></li></ul><p local-id=\"3f6b9a373038\">Example from <code>whole_body_controller_interface.py</code>:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"4516c6d4-ca9b-47f7-8b1b-3f931552c97c\" data-local-id=\"30635bd85c2d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">self._metrics_controller_period = hmnd_metrics.histogram(\n    &quot;hmnd_wbc_controller_period_seconds&quot;,\n    &quot;Observed execution period for the WBC control loop.&quot;,\n)\nself._metrics_compute_time = hmnd_metrics.histogram(\n    &quot;hmnd_wbc_compute_time_seconds&quot;,\n    &quot;WBC loop compute time in seconds (before sleep).&quot;,\n)\nself._metrics_compute_overrun_total = hmnd_metrics.counter(\n    &quot;hmnd_wbc_compute_overrun_total&quot;,\n    &quot;Number of WBC control cycles that exceeded the period budget.&quot;,\n)\nself._metrics_compute_overrun_ratio = hmnd_metrics.gauge(\n    &quot;hmnd_wbc_compute_overrun_ratio&quot;,\n    &quot;Ratio of overrun cycles to total cycles in the last metrics window.&quot;,\n)</pre>\n</div></div><p local-id=\"bc881eb82f4c\">This is a good pattern because it captures:</p><ul local-id=\"d6968ec85e54\"><li local-id=\"3ce1d1beff69\"><p local-id=\"1890a62bd954\">the loop period distribution</p></li><li local-id=\"7cbf6b132b80\"><p local-id=\"79c3fb03991d\">the compute-time distribution</p></li><li local-id=\"f5fe19e03792\"><p local-id=\"9c4a742da531\">the cumulative failure count</p></li><li local-id=\"cdb5b39eb591\"><p local-id=\"d2ffb4c356f3\">the recent health ratio</p></li></ul><p local-id=\"d36be9fea5a3\">That gives much more operational value than trying to continuously ship dense control internals.</p><h3 local-id=\"0f17734b46da\" id=\"RobotObservability-Example:hmnd_visioninstrumentation\">Example: <code>hmnd_vision</code> instrumentation</h3><p local-id=\"86f79010df70\"><code>hmnd_vision</code> uses the C++ metrics helpers and exposes on port <code>9201</code>.</p><p local-id=\"9bc7e1c818c5\">Relevant metrics include:</p><ul local-id=\"edff25682df9\"><li local-id=\"eee01496ca35\"><p local-id=\"76dc8e49a1ca\"><code>hmnd_vision_topic_published_total</code></p></li><li local-id=\"a94ca6078a6e\"><p local-id=\"c602d9128e79\"><code>hmnd_vision_topic_publish_rate_hz</code></p></li><li local-id=\"7481c7d53a7e\"><p local-id=\"5264922ca5b4\"><code>hmnd_vision_topic_publish_period_seconds</code></p></li><li local-id=\"edfe23116c0e\"><p local-id=\"25a11e41ea3f\"><code>hmnd_vision_poll_delay_seconds</code></p></li></ul><p local-id=\"ea3d114c5993\">Example from <code>hmnd_vision.cpp</code>:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"25e2b855-1198-4032-b00d-9e5c0c710960\" data-local-id=\"0b962e7bb608\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: cpp; gutter: false; theme: Confluence\" data-theme=\"Confluence\">static MetricsFamilies families{\n    .publish_counter = &amp;hmnd::metrics::CounterFamily(\n        &quot;hmnd_vision_topic_published_total&quot;,\n        &quot;Number of compressed image messages published per topic.&quot;),\n    .publish_rate = &amp;hmnd::metrics::GaugeFamily(\n        &quot;hmnd_vision_topic_publish_rate_hz&quot;,\n        &quot;Observed publish rate per topic.&quot;),\n    .publish_period = &amp;hmnd::metrics::HistogramFamily(\n        &quot;hmnd_vision_topic_publish_period_seconds&quot;,\n        &quot;Observed publish period per topic.&quot;),\n    .poll_delay = &amp;hmnd::metrics::HistogramFamily(\n        &quot;hmnd_vision_poll_delay_seconds&quot;,\n        &quot;Duration spent waiting for each frame.&quot;)\n};</pre>\n</div></div><p local-id=\"1acc93400167\">It then binds metrics per topic/device label pair and records observations for each stream.</p><p local-id=\"82fc6edc2f32\">This is another good pattern:</p><ul local-id=\"06ea339e69b5\"><li local-id=\"5c05aecec296\"><p local-id=\"be164fc1e5d7\">stable labels</p></li><li local-id=\"60664ec4833c\"><p local-id=\"a79498c20852\">bounded series count</p></li><li local-id=\"5d0b94c4560b\"><p local-id=\"de79eccafc73\">direct operator value</p></li><li local-id=\"c665eab5d7e0\"><p local-id=\"96144d4ad26d\">enough information to see rate collapse, jitter, and frame acquisition delay</p></li></ul><h2 local-id=\"54528d7bf176\" id=\"RobotObservability-LocalDevelopmentandTesting\">Local Development and Testing</h2><p local-id=\"78082a784408\">For local visualization, use the shared local observability stack in:</p><ul local-id=\"4881e0050ef6\"><li local-id=\"b7fb45832acf\"><p local-id=\"66bf508791d3\"><code>hmnd_infra/observability/local</code></p></li></ul><p local-id=\"d5922439f1a9\">Key files:</p><ul local-id=\"4f8c012f03db\"><li local-id=\"c08cddbe9cb2\"><p local-id=\"10371e25903f\"><code>hmnd_infra/observability/local/vector/vector.yaml</code></p></li><li local-id=\"71938b78fe08\"><p local-id=\"38f7c21fdf8e\"><code>hmnd_infra/observability/local/grafana/dashboard.json</code></p></li></ul><p local-id=\"5e23adbf8294\">The local setup mirrors the deployed structure:</p><ul local-id=\"a570501ecf04\"><li local-id=\"20972f64e8f4\"><p local-id=\"b8c6d65660a9\">Vector scrapes local endpoints</p></li><li local-id=\"af52894f288b\"><p local-id=\"39cb7c0ebf7f\">Vector remote-writes to local Mimir</p></li><li local-id=\"3af1c87b3445\"><p local-id=\"94ec851d6dfd\">Grafana queries local Mimir / Loki</p></li></ul><p local-id=\"36ecfe8a1e3a\">Useful local docs:</p><ul local-id=\"5a40ad8a4db1\"><li local-id=\"916b4896b254\"><p local-id=\"2181562349a3\"><code>ros/utils/hmnd_metrics/docs/LOCAL_METRICS_TESTING.md</code></p></li><li local-id=\"62da2964565e\"><p local-id=\"dca91e622be1\"><code>ros/utils/hmnd_metrics/docs/CONTROLLER_OVERRUN_MONITORING.md</code></p></li></ul><h2 local-id=\"e50dec5c6bbe\" id=\"RobotObservability-HowToAddMetricstoaNewNode\">How To Add Metrics to a New Node</h2><h3 local-id=\"02adab2eb985\" id=\"RobotObservability-1.Pickthesignalsthatmatter\">1. Pick the signals that matter</h3><p local-id=\"c6d722c0f37e\">Start from the operator question, not from the code structure.</p><p local-id=\"9083e7c3f756\">Ask:</p><ul local-id=\"68509bd25fd3\"><li local-id=\"b4b15add8ea1\"><p local-id=\"48c515523567\">what failure or degradation do we want to detect?</p></li><li local-id=\"31551eab2fa6\"><p local-id=\"17ba2b4cacc1\">what metric will move when that happens?</p></li><li local-id=\"960e497b8ad5\"><p local-id=\"a40f21fc8bb3\">do we care about current value, count, or distribution?</p></li><li local-id=\"1bab008b83a3\"><p local-id=\"0de3bbfcd64f\">what labels are truly needed to segment the issue?</p></li></ul><p local-id=\"47931bcc71a3\">A small, high-value set beats a large noisy set.</p><h3 local-id=\"67546178c5b9\" id=\"RobotObservability-2.Exposealocalexporter\">2. Expose a local exporter</h3><p local-id=\"108b8e39ea39\">In Python:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"2110eb9b-2c68-45fc-8466-7151f925ed88\" data-local-id=\"a915b4b6993d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">hmnd_metrics.initialize_exporter(&quot;0.0.0.0:92XX&quot;)</pre>\n</div></div><p local-id=\"5c845fff24a3\">In C++:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"fbb084f0-cce6-4c15-9d04-fa85890d5128\" data-local-id=\"2313a5f03b52\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: cpp; gutter: false; theme: Confluence\" data-theme=\"Confluence\">hmnd::metrics::InitializeExporter(&quot;0.0.0.0:92XX&quot;);</pre>\n</div></div><p local-id=\"5870b9b60c6d\">Use a unique <code>92xx</code> port.</p><h3 local-id=\"fe8f599195e9\" id=\"RobotObservability-3.Addmetricswithstablenamesandlabels\">3. Add metrics with stable names and labels</h3><p local-id=\"8e725f97a3a4\">Prefer:</p><ul local-id=\"7fd2776e0a93\"><li local-id=\"4fb66ab48584\"><p local-id=\"52365bb15d00\">counters for totals</p></li><li local-id=\"e0b54eaec664\"><p local-id=\"7eae4a54a604\">gauges for current state</p></li><li local-id=\"ea25c56cae1f\"><p local-id=\"43caeb057271\">histograms for timings</p></li></ul><p local-id=\"396ed4a8699a\">Be strict about labels.</p><h3 local-id=\"7c80045057e5\" id=\"RobotObservability-4.AddthescrapetargettoVector\">4. Add the scrape target to Vector</h3><p local-id=\"a949434b469c\">Update:</p><ul local-id=\"afb635a68b87\"><li local-id=\"9e143efb021a\"><p local-id=\"4763bea837c3\">local dev: <code>hmnd_infra/observability/local/vector/vector.yaml</code></p></li><li local-id=\"b4ec8e610875\"><p local-id=\"1d6585188eb4\">deployed robots: <code>platforms/common/hmnd-shipping-robot/etc/hmnd/vector/robot.yaml</code></p></li></ul><p local-id=\"92139da5af22\">Add a new endpoint line such as:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"1f74c9ad-4640-4e21-aeb8-dd6ee3d038c2\" data-local-id=\"42f5e33c8107\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">- &quot;http://127.0.0.1:9213/metrics&quot; # my_new_node</pre>\n</div></div><h3 local-id=\"8db2fafae432\" id=\"RobotObservability-5.Verifytherawendpoint\">5. Verify the raw endpoint</h3><p local-id=\"0d66a2be6fe5\">Check locally on the process host:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"ba48a132-b01c-451d-8f0e-f459f24ab589\" data-local-id=\"d7c5e19a7424\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">curl -s http://127.0.0.1:9213/metrics | head</pre>\n</div></div><p local-id=\"55f1761a6755\">If the metric is not present here, Grafana will never see it.</p><h3 local-id=\"6db44eef24ec\" id=\"RobotObservability-6.Verifyingestion\">6. Verify ingestion</h3><p local-id=\"c8abf9a85aa1\">Check in Grafana Explore or via the Prometheus API that the series exists.</p><p local-id=\"dc2677780198\">Simple queries:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"1a501ca0-d4fe-4ac6-9cb2-c964124efb92\" data-local-id=\"bf3c1c875222\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">hmnd_my_node_requests_total</pre>\n</div></div><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"fc3a7a6c-4951-4cbf-a605-c8ee3565c78e\" data-local-id=\"0d1bfb7a85ee\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">rate(hmnd_my_node_requests_total[5m])</pre>\n</div></div><h3 local-id=\"53b25c4eca54\" id=\"RobotObservability-7.Buildthedashboardpanel\">7. Build the dashboard panel</h3><p local-id=\"fca32dec00f6\">Once the metric is visible in Mimir, create Grafana panels with PromQL.</p><h2 local-id=\"838a0d38c585\" id=\"RobotObservability-DashboardPatternsThatWorkWell\">Dashboard Patterns That Work Well</h2><p local-id=\"30b471560f3c\">A few patterns are especially useful for robots.</p><h3 local-id=\"a7a2a755f276\" id=\"RobotObservability-Ratepanelsfromcounters\">Rate panels from counters</h3><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"e2a74914-2a4b-49b6-b6d2-051cd46554d3\" data-local-id=\"556a9262b1cd\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">rate(hmnd_wbc_command_missed_cycles_total[5m])</pre>\n</div></div><h3 local-id=\"f5661c93ec0a\" id=\"RobotObservability-Percentilepanelsfromhistograms\">Percentile panels from histograms</h3><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"0112b034-4d67-495a-b364-6718bc1104ff\" data-local-id=\"920bcab8dee7\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">histogram_quantile(0.95, sum by (le) (rate(hmnd_wbc_compute_time_seconds_bucket[5m])))</pre>\n</div></div><h3 local-id=\"587c1fb0a3dc\" id=\"RobotObservability-Heatmapsforloop-perioddistributions\">Heatmaps for loop-period distributions</h3><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"241643cf-dd1d-4106-a7ce-260b0a4ec2be\" data-local-id=\"9d573da13d13\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">sum by (le) (rate(hmnd_wbc_command_publish_period_seconds_bucket[$__rate_interval]))</pre>\n</div></div><h3 local-id=\"da3e96e45238\" id=\"RobotObservability-Per-robotfiltering\">Per-robot filtering</h3><p local-id=\"592426a03b24\">Use the metadata labels Vector adds:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"e2f7cfb7-2590-4f63-9554-2b7acedc0be6\" data-local-id=\"641043f35dcc\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">hmnd_wbc_compute_overrun_ratio{\n  hmnd_robot_id=&quot;$robot&quot;,\n  hmnd_robot_type=&quot;$platform&quot;,\n  hmnd_robot_target=&quot;$target&quot;\n}</pre>\n</div></div><p local-id=\"52c61eb4849b\">This is why the Vector enrichment layer matters so much. It gives consistent fleet-level filtering without requiring every exporter to know robot identity.</p><h2 local-id=\"47c006249daf\" id=\"RobotObservability-ExistingDashboardExamples\">Existing Dashboard Examples</h2><p local-id=\"f9e62d666fbd\">The local dashboard already contains practical examples for both vision and WBC.</p><p local-id=\"7e4501994993\">Examples include:</p><ul local-id=\"4f7515f56e86\"><li local-id=\"9dd1b4c17fdc\"><p local-id=\"dcd0db26ec8e\">vision poll delay heatmaps from <code>hmnd_vision_poll_delay_seconds_bucket</code></p></li><li local-id=\"f74687509b4f\"><p local-id=\"fd2ce4749772\">WBC period heatmaps from <code>hmnd_wbc_command_publish_period_seconds_bucket</code></p></li><li local-id=\"dc6ab18b1629\"><p local-id=\"66656def6067\">WBC percentile panels with <code>histogram_quantile(...)</code></p></li><li local-id=\"fbe638a50713\"><p local-id=\"2915d160bf33\">WBC rate panels from histogram <code>_count</code></p></li></ul><p local-id=\"04e432698a43\">Those queries are a good starting point when building new dashboards.</p><h2 local-id=\"fb4d2bf00b25\" id=\"RobotObservability-RecommendedInstrumentationPatterns\">Recommended Instrumentation Patterns</h2><h3 local-id=\"5c42d9759fe1\" id=\"RobotObservability-Goodpatterns\">Good patterns</h3><ul local-id=\"78465b877b1a\"><li local-id=\"ebdd861dedda\"><p local-id=\"35cd02c5d649\">instrument at process boundaries and health boundaries</p></li><li local-id=\"22f9ee81c59c\"><p local-id=\"5c845650e3d3\">record distributions for timing-sensitive paths</p></li><li local-id=\"a597b51bbed0\"><p local-id=\"27784253d3bb\">keep labels bounded and semantically useful</p></li><li local-id=\"a35076c5fe33\"><p local-id=\"5e125770aa9b\">expose one stable exporter per process</p></li><li local-id=\"61e538ba8571\"><p local-id=\"6fd7e517eaff\">let Vector handle shipping, buffering, and metadata</p></li><li local-id=\"43c4a257c279\"><p local-id=\"278cffd7a10e\">use logs for sparse explanations and metrics for ongoing health</p></li></ul><h3 local-id=\"9cc273ba8662\" id=\"RobotObservability-Patternstoavoid\">Patterns to avoid</h3><ul local-id=\"83ccd7be2401\"><li local-id=\"7c2bcaf85d6a\"><p local-id=\"187316ddebeb\">publishing dense high-rate control state as centralized metrics</p></li><li local-id=\"8f001ba23383\"><p local-id=\"fedd50df2435\">adding unbounded labels</p></li><li local-id=\"b372b4e02306\"><p local-id=\"65a69ad988b8\">emitting a separate metric name per entity when labels would do</p></li><li local-id=\"12a081c03131\"><p local-id=\"6af8aa33221f\">relying on raw cumulative counters without rate queries</p></li><li local-id=\"04a28e068813\"><p local-id=\"aaad22b9d1ad\">using gauges where a histogram is needed to understand jitter or tail latency</p></li></ul><h2 local-id=\"d6e561bc04f6\" id=\"RobotObservability-FileMap\">File Map</h2><p local-id=\"af3745091004\">Useful implementation references:</p><ul local-id=\"11ce1dacd957\"><li local-id=\"a88248fdc8a0\"><p local-id=\"3872362b4b21\"><code>hmnd_robot/ros/utils/hmnd_metrics/README.md</code></p></li><li local-id=\"04b7680a54dd\"><p local-id=\"b41cb981708a\"><code>hmnd_robot/ros/utils/hmnd_metrics/hmnd_metrics/__init__.py</code></p></li><li local-id=\"9bbdd5dc1fb9\"><p local-id=\"f20ea9c0bbda\"><code>hmnd_robot/ros/control/whole_body_controller/whole_body_controller/whole_body_controller_interface.py</code></p></li><li local-id=\"3b3110be9c55\"><p local-id=\"60289e638b84\"><code>hmnd_robot/ros/perception/hmnd_vision/src/hmnd_vision.cpp</code></p></li><li local-id=\"d12176783798\"><p local-id=\"e64db24b85cc\"><code>hmnd_robot/platforms/common/hmnd-shipping/etc/hmnd/vector/common.yaml</code></p></li><li local-id=\"a6dd7efe308a\"><p local-id=\"cd3c10da2338\"><code>hmnd_robot/platforms/common/hmnd-shipping-robot/etc/hmnd/vector/robot.yaml</code></p></li><li local-id=\"29e1f2a70996\"><p local-id=\"2e9c09e0d7ef\"><code>hmnd_infra/observability/local/vector/vector.yaml</code></p></li><li local-id=\"35143ccbfa52\"><p local-id=\"3fe7c0fbd6f2\"><code>hmnd_infra/observability/local/grafana/dashboard.json</code></p></li></ul><h2 local-id=\"e2eb06961964\" id=\"RobotObservability-BottomLine\">Bottom Line</h2><p local-id=\"5076d61b0d43\">The intended workflow is:</p><ol start=\"1\" local-id=\"bae5098ede31\"><li local-id=\"de46776bcf21\"><p local-id=\"149b13cd30ce\">instrument a node with <code>hmnd_metrics</code></p></li><li local-id=\"e880c2316769\"><p local-id=\"1d4e37eef4e7\">expose a local <code>/metrics</code> endpoint on a stable <code>92xx</code> port</p></li><li local-id=\"a247734827c0\"><p local-id=\"f72fa18998fc\">add that endpoint to the Vector scrape config in <code>hmnd-shipping</code></p></li><li local-id=\"fb9a7c04d43a\"><p local-id=\"cad23a4255da\">let Vector enrich with robot metadata and ship to Mimir/Loki</p></li><li local-id=\"e7a549596630\"><p local-id=\"9b61b136d90d\">build Grafana panels on top of the resulting series</p></li></ol><p local-id=\"025ff66314a1\">If we keep following that pattern, we get observability that is:</p><ul local-id=\"8bf7e26713d6\"><li local-id=\"96aa0eefc08a\"><p local-id=\"487b81f1e0c7\">always on</p></li><li local-id=\"8455e9198698\"><p local-id=\"b02da184aa99\">cheap enough to run fleet-wide</p></li><li local-id=\"7901fa2e6311\"><p local-id=\"9301d031dded\">rich enough to debug most operational problems</p></li><li local-id=\"9db43fcdd9de\"><p local-id=\"70c173f36e5f\">simple enough that adding new instrumentation stays routine</p></li></ul>"
        },
        {
          "id": "1819705397",
          "title": "Agent Substrate: Implementation Plan",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1819705397",
          "last_modified": "2026-04-01T10:23:05.855Z",
          "created_at": "2026-04-01T10:23:05.855Z",
          "body_html": "<h1 id=\"AgentSubstrate:ImplementationPlan-AgentSubstrate:ImplementationPlan\">Agent Substrate: Implementation Plan</h1><p><strong>Owner:</strong> Cody Griffin + Oleg Sinavski<br/><strong>Date:</strong> April 1, 2026<br/><strong>Status:</strong> Draft \u2014 for review</p><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-Goal\">Goal</h2><p>Enable engineers to hand off a task to a cloud coding agent via Slack or GitHub, have it run autonomously 24/7 in our own infrastructure (EKS DevPod with GPU + <code>/mnt/shared</code>), and steer it from Slack or GitHub review comments without needing to clone the repo or touch a terminal.</p><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-Architecture\">Architecture</h2><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"3125f1fa-cc56-4117-8656-3c7199cf8a65\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  ENTRY POINTS                                                    \u2502\n\u2502  Slack (@claude-agent do X)   \u2502   GitHub PR comment / CI fail   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                 \u2502                                  \u2502 webhook\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  CONTROLLER  (Alphaclaw on EKS \u2014 extend existing)                \u2502\n\u2502  \u2022 Parses task + context from Slack thread or GitHub event       \u2502\n\u2502  \u2022 Manages pod lifecycle (helm install \u2192 monitor \u2192 teardown)     \u2502\n\u2502  \u2022 Routes CI/review feedback back into running agent sessions    \u2502\n\u2502  \u2022 Persists session state (SQLite + markdown on /mnt/shared)     \u2502\n\u2502  \u2022 Exposes simple REST API for CloudCLI web UI                   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n       \u2502 helm upgrade --install                       \u2502 status / logs\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502  AGENT POD (EKS DevPod)       \u2502    \u2502  CloudCLI  (web UI)        \u2502\n\u2502  \u2022 Headless DevPod variant    \u2502    \u2502  \u2022 List / attach sessions  \u2502\n\u2502  \u2022 claude CLI (Agent SDK)     \u2502    \u2502  \u2022 View turn-by-turn log   \u2502\n\u2502  \u2022 /workspace (Longhorn PVC)  \u2502    \u2502  \u2022 Inject steering message \u2502\n\u2502  \u2022 /mnt/shared (FSx Lustre)   \u2502    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\u2502    \u2192 datasets, checkpoints    \u2502\n\u2502    \u2192 agent memory (markdown)  \u2502\n\u2502  \u2022 ANTHROPIC_API_KEY from k8s \u2502\n\u2502    secret                     \u2502\n\u2502  \u2022 Optional GPU (MIG slice)   \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500-\u2518</pre>\n</div></div><p><strong>Session identity:</strong> one Slack thread = one agent session = one pod. Replies in the thread steer the agent. The thread timestamp (<code>thread_ts</code>) is the primary key throughout.</p><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-WhatAlreadyExists\">What Already Exists</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Component</p></th><th class=\"confluenceTh\"><p>Status</p></th><th class=\"confluenceTh\"><p>Location</p></th></tr><tr><td class=\"confluenceTd\"><p>DevPod Helm chart</p></td><td class=\"confluenceTd\"><p>\u2705 Exists</p></td><td class=\"confluenceTd\"><p><code>hmnd_training/infra/helm/eks/</code></p></td></tr><tr><td class=\"confluenceTd\"><p><code>/mnt/shared</code> (FSx Lustre)</p></td><td class=\"confluenceTd\"><p>\u2705 Exists</p></td><td class=\"confluenceTd\"><p>PVC <code>fsx-lustre-shared-pvc</code> on EKS</p></td></tr><tr><td class=\"confluenceTd\"><p>Longhorn PVC workspace</p></td><td class=\"confluenceTd\"><p>\u2705 Exists</p></td><td class=\"confluenceTd\"><p>Per-release, auto-remounted</p></td></tr><tr><td class=\"confluenceTd\"><p>Alphaclaw controller</p></td><td class=\"confluenceTd\"><p>\u2705 Running on EC2, needs migration</p></td><td class=\"confluenceTd\"><p>PR #2996, <code>#agent-requests</code></p></td></tr><tr><td class=\"confluenceTd\"><p>Slack bot + session management</p></td><td class=\"confluenceTd\"><p>\u2705 In Alphaclaw</p></td><td class=\"confluenceTd\"><p><code>#agent-requests</code> channel</p></td></tr><tr><td class=\"confluenceTd\"><p>Multi-backend support (Claude/Codex)</p></td><td class=\"confluenceTd\"><p>\u2705 In Alphaclaw</p></td><td class=\"confluenceTd\"><p>PR #2996</p></td></tr><tr><td class=\"confluenceTd\"><p>ANTHROPIC_API_KEY (enterprise)</p></td><td class=\"confluenceTd\"><p>\u2705 Just activated</p></td><td class=\"confluenceTd\"><p>Karen/IT \u2014 needs k8s secret</p></td></tr></tbody></table></div><p><strong>What needs to be built:</strong> headless agent pod variant, pod lifecycle management in the controller, GitHub webhook handler, CloudCLI deployment.</p><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-ImplementationPlan\">Implementation Plan</h2><h3 id=\"AgentSubstrate:ImplementationPlan-Phase0\u2014Secrets&amp;Prerequisites\">Phase 0 \u2014 Secrets &amp; Prerequisites</h3><p><em>Owner: Mustafa / Karen | Est: ~1 day</em></p><p><strong>1. Create </strong><code>anthropic-api-key</code> k8s secret on EKS</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"9a469982-ef4e-454b-a089-1517b772f40e\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">kubectl create secret generic anthropic-api-key \\\n  --from-literal=ANTHROPIC_API_KEY=&lt;key&gt; \\\n  --namespace=agent-system</pre>\n</div></div><p><strong>2. Create </strong><code>github-token</code> k8s secret</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"e22ba27c-d4f8-4f9b-a3c6-6d819fa1f1ce\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">kubectl create secret generic github-token \\\n  --from-literal=GITHUB_TOKEN=&lt;pat-with-repo-scope&gt; \\\n  --namespace=agent-system</pre>\n</div></div><p><strong>3. Create </strong><code>agent-system</code> namespace (separate from <code>stray-dog</code> where Mustafa's monitoring agent lives).</p><hr/><h3 id=\"AgentSubstrate:ImplementationPlan-Phase1\u2014AgentPod:HeadlessDevPodVariant\">Phase 1 \u2014 Agent Pod: Headless DevPod Variant</h3><p><em>Owner: Mustafa (k8s) + Atindra (image) | Est: 2\u20133 days</em></p><p>The goal is a pod that starts, runs <code>claude</code> headlessly, and exits cleanly. It is a new Helm values profile on top of the existing DevPod chart \u2014 <strong>not</strong> a new chart.</p><p><strong>1a. New Docker image: </strong><code>hmnd-agent</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"5e801863-1deb-4086-b0b2-a7e1ba06601e\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">FROM hmnd-interactive-base:latest\n\n# Install Claude Code CLI\nRUN npm install -g @anthropic-ai/claude-code\n\n# Agent entrypoint \u2014 waits for task file, runs claude, exits\nCOPY agent-entrypoint.sh /usr/local/bin/agent-entrypoint\nRUN chmod +x /usr/local/bin/agent-entrypoint\n\nENTRYPOINT [&quot;/usr/local/bin/agent-entrypoint&quot;]</pre>\n</div></div><p><code>agent-entrypoint.sh</code>:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"b42cfde9-4829-4b9d-85ad-e2bcbe300651\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">#!/bin/bash\nset -e\n\nTASK_FILE=/workspace/task.json\nMEMORY_DIR=/mnt/shared/agents/${SESSION_ID}/memory\nTRANSCRIPT=/mnt/shared/agents/${SESSION_ID}/transcript.jsonl\n\nmkdir -p &quot;$MEMORY_DIR&quot;\n\ncd /workspace/hmnd\n\nclaude \\\n  --dangerously-skip-permissions \\\n  --output-format stream-json \\\n  --max-turns 100 \\\n  &quot;$(jq -r .prompt $TASK_FILE)&quot; \\\n  | tee -a &quot;$TRANSCRIPT&quot;</pre>\n</div></div><blockquote><p><strong>Note on repo freshness:</strong> The Docker image contains a clone at <code>main</code> at build time. For Phase 1 this is acceptable \u2014 the agent's first tool call can <code>git pull</code> to get latest. Incremental build caching comes in the Appendix.</p></blockquote><p><strong>1b. Helm values override: </strong><code>values-agent.yaml</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"915c99a9-99fe-4745-82cf-063afb375104\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">hmnd-interactive-base:\n  workload:\n    purpose: agent\n  image:\n    repository: &lt;ecr&gt;/hmnd-agent\n    tag: latest\n  gui:\n    enabled: false\n  ssh:\n    enabled: false\n  resources:\n    requests:\n      cpu: &quot;2&quot;\n      memory: &quot;8Gi&quot;\n    limits:\n      cpu: &quot;4&quot;\n      memory: &quot;16Gi&quot;\n  gpu:\n    count: 0\n  env:\n    - name: ANTHROPIC_API_KEY\n      valueFrom:\n        secretKeyRef:\n          name: anthropic-api-key\n          key: ANTHROPIC_API_KEY\n    - name: GITHUB_TOKEN\n      valueFrom:\n        secretKeyRef:\n          name: github-token\n          key: GITHUB_TOKEN\n  storage:\n    shared:\n      mountPath: /mnt/shared\n      pvcName: fsx-lustre-shared-pvc\n  lifecycle:\n    idleTimeoutSeconds: 7200</pre>\n</div></div><p><strong>Deploy a single agent pod:</strong></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"6641c9ed-d02a-4251-9433-819fb3f90a09\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">helm upgrade --install agent-&lt;session_id&gt; ./eks \\\n  -f values-agent.yaml \\\n  --set hmnd-interactive-base.user.name=agent-&lt;session_id&gt; \\\n  --set hmnd-interactive-base.env[0].value=$SESSION_ID \\\n  --namespace agent-system \\\n  --wait</pre>\n</div></div><p><strong>1c. Write task.json into the pod</strong></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"94d8b11c-8beb-4253-9f7b-b109bc078caa\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\">kubectl exec -n agent-system \\\n  $(kubectl get pod -l app.kubernetes.io/instance=agent-&lt;session_id&gt; \\\n    -n agent-system -o jsonpath='{.items[0].metadata.name}') \\\n  -- bash -c &quot;echo '$TASK_JSON' &gt; /workspace/task.json&quot;</pre>\n</div></div><hr/><h3 id=\"AgentSubstrate:ImplementationPlan-Phase2\u2014Controller:ExtendAlphaclawforCodingTasks\">Phase 2 \u2014 Controller: Extend Alphaclaw for Coding Tasks</h3><p><em>Owner: Atindra (Alphaclaw) + Mustafa (k8s) | Est: 3\u20135 days</em></p><p><strong>2a. Migrate Alphaclaw to EKS</strong></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"4b25b718-9634-4da9-bbcf-199c444246ed\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">apiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: alphaclaw\n  namespace: agent-system\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: alphaclaw-role\n  namespace: agent-system\nrules:\n  - apiGroups: [&quot;&quot;]\n    resources: [&quot;pods&quot;]\n    verbs: [&quot;get&quot;, &quot;list&quot;, &quot;watch&quot;, &quot;create&quot;, &quot;delete&quot;]\n  - apiGroups: [&quot;apps&quot;]\n    resources: [&quot;deployments&quot;]\n    verbs: [&quot;get&quot;, &quot;list&quot;]</pre>\n</div></div><p><strong>2b. New Slack commands</strong></p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Command</p></th><th class=\"confluenceTh\"><p>Behaviour</p></th></tr><tr><td class=\"confluenceTd\"><p><code>@claude-agent &lt;task description&gt;</code></p></td><td class=\"confluenceTd\"><p>Spawns new agent pod, returns thread with session link</p></td></tr><tr><td class=\"confluenceTd\"><p><code>@claude-agent status</code></p></td><td class=\"confluenceTd\"><p>Lists running agent pods + their Slack thread links</p></td></tr><tr><td class=\"confluenceTd\"><p><code>@claude-agent stop</code> (in thread)</p></td><td class=\"confluenceTd\"><p>Terminates the agent pod for this thread</p></td></tr><tr><td class=\"confluenceTd\"><p><code>@claude-agent steer: &lt;message&gt;</code> (in thread)</p></td><td class=\"confluenceTd\"><p>Injects message into the running claude session</p></td></tr><tr><td class=\"confluenceTd\"><p>Reply in thread</p></td><td class=\"confluenceTd\"><p>Same as steer \u2014 any reply is forwarded to the agent</p></td></tr></tbody></table></div><p><strong>2c. Session lifecycle (pseudocode)</strong></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"8e1c442b-5476-4d1c-b4e6-2588bf10875c\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">async def handle_slack_message(event):\n    thread_ts = event.get(&quot;thread_ts&quot;) or event[&quot;ts&quot;]\n    session_id = make_session_id(thread_ts)\n\n    if is_new_task(event):\n        task = parse_task(event[&quot;text&quot;])\n        pod_name = await spawn_agent_pod(session_id, task, gpu=needs_gpu(task))\n        db.create_session(session_id, thread_ts, event[&quot;channel&quot;], pod_name)\n        await slack.post(\n            channel=event[&quot;channel&quot;], thread_ts=thread_ts,\n            text=f&quot;\ud83e\udd16 Agent `{session_id}` starting on EKS...\n&quot;\n                 f&quot;View live: https://cloudcli.lan.thehumanoid.ai/sessions/{session_id}&quot;\n        )\n        asyncio.create_task(stream_agent_output(session_id, thread_ts, event[&quot;channel&quot;]))\n    elif is_steering_message(event):\n        await inject_into_agent(session_id, event[&quot;text&quot;])\n\n\nasync def stream_agent_output(session_id, thread_ts, channel):\n    transcript_path = f&quot;/mnt/shared/agents/{session_id}/transcript.jsonl&quot;\n    last_posted = 0\n    async for turn in tail_jsonl(transcript_path):\n        if turn[&quot;type&quot;] == &quot;assistant&quot; and turn[&quot;turn_index&quot;] - last_posted &gt;= 5:\n            summary = summarise_turns(turns_since(last_posted))\n            await slack.post(channel=channel, thread_ts=thread_ts, text=summary)\n            last_posted = turn[&quot;turn_index&quot;]\n        if turn[&quot;type&quot;] == &quot;result&quot;:\n            await post_completion(session_id, channel, thread_ts, turn)\n            await teardown_pod(session_id)</pre>\n</div></div><p><strong>2d. Session state on </strong><code>/mnt/shared</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"8aab45a2-9ab6-40cb-bda9-d3094c4ce62b\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">/mnt/shared/agents/\n  &lt;session_id&gt;/\n    task.json          \u2190 initial task written by controller\n    transcript.jsonl   \u2190 streaming claude output\n    memory/\n      context.md\n      progress.md\n    pr_url.txt         \u2190 written by agent when PR is opened</pre>\n</div></div><hr/><h3 id=\"AgentSubstrate:ImplementationPlan-Phase3\u2014GitHubIntegration:CI+ReviewLoop\">Phase 3 \u2014 GitHub Integration: CI + Review Loop</h3><p><em>Owner: Atindra | Est: 2\u20133 days</em></p><p><strong>3a. GitHub webhook receiver</strong></p><p>Register at <code>https://alphaclaw.lan.thehumanoid.ai/webhooks/github</code> for events: <code>Check suites</code>, <code>Pull request review comments</code>, <code>Pull request reviews</code>.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"96a90b3d-6fb4-4749-85e4-7332113d81b8\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">async def on_ci_complete(payload):\n    pr_number = payload[&quot;check_suite&quot;][&quot;pull_requests&quot;][0][&quot;number&quot;]\n    session_id = db.lookup_session_by_pr(pr_number)\n    if payload[&quot;check_suite&quot;][&quot;conclusion&quot;] == &quot;failure&quot;:\n        failed_logs = await fetch_failed_ci_logs(pr_number)\n        await inject_into_agent(session_id,\n            f&quot;CI failed on PR #{pr_number}:</pre>\n</div></div><p>{failed_logs}</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"15164bb4-d0f1-4d6d-ac1d-229290f928b2\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">Please fix and push.&quot;)\n\nasync def on_review_comment(payload):\n    pr_number = payload[&quot;pull_request&quot;][&quot;number&quot;]\n    session_id = db.lookup_session_by_pr(pr_number)\n    comment = payload[&quot;comment&quot;][&quot;body&quot;]\n    author = payload[&quot;comment&quot;][&quot;user&quot;][&quot;login&quot;]\n    path = payload[&quot;comment&quot;][&quot;path&quot;]\n    line = payload[&quot;comment&quot;][&quot;line&quot;]\n    await inject_into_agent(session_id,\n        f&quot;Review comment from @{author} on `{path}` line {line}:\n&gt; {comment}\n\nPlease address this.&quot;)</pre>\n</div></div><p><strong>3b. </strong><a href=\"http://AGENTS.md\" class=\"external-link\" rel=\"nofollow\"><strong>AGENTS.md</strong></a><strong> skill for coding agents</strong></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"768adce4-ab69-42f1-8126-0cb76fcdf87e\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\"># .agents/skills/agent-substrate/SKILL.md\n\nWhen working as a cloud coding agent:\n1. Always create a feature branch: git checkout -b agent/&lt;session_id&gt;/&lt;short-description&gt;\n2. Push and open a PR early (draft OK): gh pr create --draft --title &quot;...&quot; --body &quot;...&quot;\n3. Write the PR URL to /mnt/shared/agents/$SESSION_ID/pr_url.txt\n4. After each significant change, run: pixi run build &amp;&amp; pixi run test\n5. Address CI failures and review comments before marking PR ready for review\n6. When done, post summary to Slack and mark PR ready: gh pr ready</pre>\n</div></div><hr/><h3 id=\"AgentSubstrate:ImplementationPlan-Phase4\u2014WebUI:CloudCLI\">Phase 4 \u2014 Web UI: CloudCLI</h3><p><em>Owner: Anyone | Est: half a day</em></p><p>CloudCLI is open source (GPL-3, <a href=\"http://github.com/siteboon/claudecodeui\" class=\"external-link\" rel=\"nofollow\">github.com/siteboon/claudecodeui</a>) and deploys in one command.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"c89ca5be-79f3-408e-bdd5-b54cd8766008\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\"># Expose via existing internal ingress \u2192 https://cloudcli.lan.thehumanoid.ai\nkubectl apply -f cloudcli-deployment.yaml -n agent-system</pre>\n</div></div><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-MinimalScopeSummary\">Minimal Scope Summary</h2><p>At the end of Phase 4, you get:</p><ul><li><p><strong>Hand off work from Slack:</strong> <code>@claude-agent implement the feature described in JIRA-1234</code> \u2192 agent pod spins up on EKS, implements, opens a PR</p></li><li><p><strong>Steer via Slack thread:</strong> reply in the same thread to redirect, provide context, or stop the agent</p></li><li><p><strong>CI/review loop:</strong> when CI fails or a reviewer comments, the agent fixes automatically</p></li><li><p><strong>Access to your infra:</strong> <code>/mnt/shared</code> (FSx Lustre \u2014 datasets, checkpoints), optional GPU via <code>--set gpu.count=1</code></p></li><li><p><strong>Web UI:</strong> live session view at <code>cloudcli.lan.thehumanoid.ai</code></p></li><li><p><strong>Parallel agents:</strong> no limit \u2014 each Slack thread is an independent pod</p></li></ul><p><strong>Not yet (see Appendix):</strong> build caching, Codex as alternative harness, IsaacLab access from agent pods.</p><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-Owners&amp;RoughTimeline\">Owners &amp; Rough Timeline</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Phase</p></th><th class=\"confluenceTh\"><p>Work</p></th><th class=\"confluenceTh\"><p>Owner(s)</p></th><th class=\"confluenceTh\"><p>Days</p></th></tr><tr><td class=\"confluenceTd\"><p>0</p></td><td class=\"confluenceTd\"><p>Secrets, namespace, service account</p></td><td class=\"confluenceTd\"><p>Mustafa + Karen</p></td><td class=\"confluenceTd\"><p>1</p></td></tr><tr><td class=\"confluenceTd\"><p>1a</p></td><td class=\"confluenceTd\"><p><code>hmnd-agent</code> Docker image + entrypoint</p></td><td class=\"confluenceTd\"><p>Atindra</p></td><td class=\"confluenceTd\"><p>1\u20132</p></td></tr><tr><td class=\"confluenceTd\"><p>1b/c</p></td><td class=\"confluenceTd\"><p>Helm values override + pod deploy/task</p></td><td class=\"confluenceTd\"><p>Mustafa</p></td><td class=\"confluenceTd\"><p>1\u20132</p></td></tr><tr><td class=\"confluenceTd\"><p>2a</p></td><td class=\"confluenceTd\"><p>Migrate Alphaclaw to EKS</p></td><td class=\"confluenceTd\"><p>Atindra + Mustafa</p></td><td class=\"confluenceTd\"><p>1\u20132</p></td></tr><tr><td class=\"confluenceTd\"><p>2b/c</p></td><td class=\"confluenceTd\"><p>Slack commands + session lifecycle</p></td><td class=\"confluenceTd\"><p>Atindra</p></td><td class=\"confluenceTd\"><p>2\u20133</p></td></tr><tr><td class=\"confluenceTd\"><p>2d</p></td><td class=\"confluenceTd\"><p><code>/mnt/shared</code> session state layout</p></td><td class=\"confluenceTd\"><p>Atindra</p></td><td class=\"confluenceTd\"><p>0.5</p></td></tr><tr><td class=\"confluenceTd\"><p>3a</p></td><td class=\"confluenceTd\"><p>GitHub webhook receiver</p></td><td class=\"confluenceTd\"><p>Atindra</p></td><td class=\"confluenceTd\"><p>1\u20132</p></td></tr><tr><td class=\"confluenceTd\"><p>3b</p></td><td class=\"confluenceTd\"><p><a href=\"http://AGENTS.md\" class=\"external-link\" rel=\"nofollow\">AGENTS.md</a> additions</p></td><td class=\"confluenceTd\"><p>AI Captains</p></td><td class=\"confluenceTd\"><p>0.5</p></td></tr><tr><td class=\"confluenceTd\"><p>4</p></td><td class=\"confluenceTd\"><p>CloudCLI deployment</p></td><td class=\"confluenceTd\"><p>Anyone</p></td><td class=\"confluenceTd\"><p>0.5</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>Total</strong></p></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p /></td><td class=\"confluenceTd\"><p><strong>~2 weeks</strong></p></td></tr></tbody></table></div><p>Phases 0\u20132 can run in parallel (Mustafa on infra, Atindra on controller).</p><hr/><h1 id=\"AgentSubstrate:ImplementationPlan-Appendix:FutureImprovements\">Appendix: Future Improvements</h1><h2 id=\"AgentSubstrate:ImplementationPlan-A1.BuildCaching\">A1. Build Caching</h2><p><strong>Problem:</strong> Every agent pod runs <code>pixi run build</code> from a fresh clone. For the hmnd monorepo this is slow \u2014 C++ compilation, pixi env setup \u2014 and wastes GPU runner capacity.</p><p><strong>Solution: Bazel Remote Cache on S3</strong></p><p>The Q2 plan already calls for a Bazel migration (Ricardo + Tobias). The agent substrate is a strong forcing function to prioritise this.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"8e5272a1-df83-458f-8d04-ee720aaa9843\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\"># In .bazelrc\nbuild --remote_cache=https://cache.lan.thehumanoid.ai\nbuild --remote_cache_compression=zstd\nbuild --jobs=AUTO</pre>\n</div></div><p>Backend options (ordered by effort):</p><ol start=\"1\"><li><p><strong>S3 bucket + nginx proxy</strong> \u2014 simplest, ~1 day to set up</p></li><li><p><strong>BuildBuddy OSS</strong> \u2014 open source, dashboard showing cache hits/misses, Helm chart available</p></li><li><p><strong>Bazel Remote Execution on EKS</strong> \u2014 longer term; agents submit build actions to an RBE cluster</p></li></ol><p>For non-Bazel builds during transition: <code>sccache</code> with S3 backend works today with zero code changes.</p><p><strong>Expected impact:</strong> ~5\u201310\u00d7 speedup on repeated builds. Agents on different pods share the same cache.</p><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-A2.IncrementalRepoSnapshots\">A2. Incremental Repo Snapshots</h2><p><strong>Problem:</strong> The Docker image contains a clone at <code>main</code> at build time. Agents always start slightly behind <code>main</code> and have to <code>git pull</code>, which on the hmnd monorepo (LFS, submodules) is slow and fragile.</p><p><strong>Solution:</strong> Pre-bake a daily snapshot image in CI, triggered at 3am daily and on pushes to <code>main</code>. The controller always uses <code>:latest</code> \u2014 agents start with a repo at most 24 hours behind <code>main</code>.</p><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-A3.CodexCLIasAlternativeHarness\">A3. Codex CLI as Alternative Harness</h2><p>Parameterize the harness in the Helm values:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"08c7368a-9b76-45e6-acc5-856541d2dbff\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\"># values-agent-codex.yaml\nenv:\n  - name: AGENT_HARNESS\n    value: &quot;codex&quot;\n  - name: OPENAI_API_KEY\n    valueFrom:\n      secretKeyRef:\n        name: openai-api-key\n        key: OPENAI_API_KEY</pre>\n</div></div><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"58c2aa8d-eee2-4520-a630-c68deae3730e\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: bash; gutter: false; theme: Confluence\" data-theme=\"Confluence\"># agent-entrypoint.sh\ncase &quot;$AGENT_HARNESS&quot; in\n  claude) claude --dangerously-skip-permissions --output-format stream-json ... ;;\n  codex)  codex --approval-mode full-auto ... ;;\nesac</pre>\n</div></div><p>The session state layout is harness-agnostic. <strong>Pre-requisite:</strong> OpenAI contract.</p><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-A4.Simulation/IsaacLabAccessfromAgentPods\">A4. Simulation / IsaacLab Access from Agent Pods</h2><p>Wire up the <a href=\"/wiki/spaces/ROBOT/pages/1501626408/Spec+Kubernetes+Simulation+Service\" data-linked-resource-id=\"1501626408\" data-linked-resource-version=\"10\" data-linked-resource-type=\"page\">Sim-as-a-Service spec</a> as an MCP server. Rather than running sim inside the agent pod, the agent submits a sim job via MCP and polls for results:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"588b5963-97ce-4bfa-a1b9-23e9cc424d53\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">@mcp.tool()\nasync def submit_sim_job(branch: str, config: str) -&gt; dict:\n    response = await httpx.post(&quot;http://sim-service.lan.thehumanoid.ai/jobs&quot;,\n                                json={&quot;branch&quot;: branch, &quot;config&quot;: config})\n    return {&quot;job_id&quot;: response.json()[&quot;job_id&quot;]}\n\n@mcp.tool()\nasync def get_sim_results(job_id: str) -&gt; dict:\n    response = await httpx.get(f&quot;http://sim-service.lan.thehumanoid.ai/jobs/{job_id}&quot;)\n    return response.json()</pre>\n</div></div><p>The agent never needs a GPU in its own pod for sim-validation tasks.</p><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-A5.Benchmark/EvalAccessfromAgentPods\">A5. Benchmark / Eval Access from Agent Pods</h2><p>Same pattern as sim: expose Prefect training jobs and academic benchmark runs (Libero, IsaacLab evals) as MCP tools. Oleg's Agentification project has already validated this pattern. Standardise MCP tool signatures across sim, training, and evals so agents use a consistent interface regardless of backend.</p><hr/><h2 id=\"AgentSubstrate:ImplementationPlan-A6.KubernetesWorkloadPriorityforAgentPods\">A6. Kubernetes Workload Priority for Agent Pods</h2><p>Agent pods should sit between interactive DevPods and batch training in the <a href=\"/wiki/spaces/ROBOT/pages/1722744873/Spec+K8S+-+Priorities+and+Resource+Management\" data-linked-resource-id=\"1722744873\" data-linked-resource-version=\"13\" data-linked-resource-type=\"page\">Kubernetes Workload Priorities spec</a>:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"081e2c61-1d43-4936-9291-65cdb5163a0c\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">priorityClassName: agent-workload   # new class, between devpod and training</pre>\n</div></div><p>This ensures agent pods don't starve human DevPod users, and can be preempted by training jobs if GPU contention spikes.</p>"
        },
        {
          "id": "1818624031",
          "title": "Cloud Agents: Options Analysis",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1818624031",
          "last_modified": "2026-04-01T10:21:48.440Z",
          "created_at": "2026-04-01T10:21:48.440Z",
          "body_html": "<h1 id=\"CloudAgents:OptionsAnalysis-CloudAgentsforHumanoid:OptionsAnalysis\">Cloud Agents for Humanoid: Options Analysis</h1><p><strong>Prepared for:</strong> Cody Griffin | <strong>Date:</strong> April 1, 2026</p><hr/><h2 id=\"CloudAgents:OptionsAnalysis-Context:WhereWeAreToday\">Context: Where We Are Today</h2><p>Based on conversations across #agentic-ai-practices, #team_eng-software, the Agentification project doc, and Q2 planning notes, the team is at an inflection point. Several parallel threads are converging:</p><p><strong>What's working well:</strong></p><ul><li><p>Cursor Cloud Agents are in active use (Atindra set up snapshot environments, Andy is using Graphite/Cursor agents for PR generation and review)</p></li><li><p>Alphaclaw (Atindra's agent framework, spun off from nanoclaw) is running on a data-flywheel EC2 instance, supporting Codex, Claude Code, and OpenCode backends with Slack integration</p></li><li><p>Oleg's Agentification project has MVPs for overnight agents doing multi-hour training cycles, dataset analysis, and eval runs</p></li><li><p>DevPods on EKS are operational with PVC-backed persistent volumes (Longhorn), unison-based sync, and Cursor remote development</p></li><li><p><a href=\"http://AGENTS.md\" class=\"external-link\" rel=\"nofollow\">AGENTS.md</a> and Skills are standardized across Cursor/Claude/Codex with cross-agent compatibility</p></li><li><p>AI Captains program is established with monthly syncs</p></li><li><p>Claude Enterprise account just activated; Anthropic contract signed; OpenAI coming next</p></li></ul><p><strong>Key pain points identified in Slack:</strong></p><ul><li><p>No self-hosted cloud runner pool yet \u2014 &quot;single workers are buggy&quot; (Oleg)</p></li><li><p>Cursor Cloud Agents don't use our Anthropic API keys</p></li><li><p>GPU runner contention on EKS (9 \u2192 30 MIG partitions, still hitting I/O limits)</p></li><li><p>Build caching is missing \u2014 Boris noted &quot;a good straightforward fix will be a distributed build cache&quot;</p></li><li><p>Submodules and LFS cause constant friction with agents</p></li><li><p>No persistent data access (no mnt/shared, HF rate limits, confused agents)</p></li><li><p>Review remains the bottleneck (200+ open PRs in hmnd)</p></li></ul><p><strong>Requirements:</strong></p><ol start=\"1\"><li><p>Cursor Cloud Agent-like experience (background tasks, Slack integration, steering/monitoring)</p></li><li><p>Hosted on your infra (EKS cluster with GPUs and NFS)</p></li><li><p>Build caching</p></li><li><p>Review/steering capabilities</p></li><li><p>Documentation/speccing and planning</p></li><li><p>BYOK: at minimum Anthropic + OpenAI model support</p></li></ol><hr/><h2 id=\"CloudAgents:OptionsAnalysis-Option1:CursorSelf-HostedCloudAgents\">Option 1: Cursor Self-Hosted Cloud Agents</h2><p><strong>What it is:</strong> Cursor's official self-hosted offering. Workers run on your infra (outbound HTTPS to Cursor's cloud for orchestration). Cursor provides a Helm chart and Kubernetes operator for fleet management.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Requirement</p></th><th class=\"confluenceTh\"><p>Coverage</p></th></tr><tr><td class=\"confluenceTd\"><p>Cloud Agent experience</p></td><td class=\"confluenceTd\"><p>Native \u2014 same UX as Cursor Cloud Agents</p></td></tr><tr><td class=\"confluenceTd\"><p>Self-hosted on your infra</p></td><td class=\"confluenceTd\"><p>Yes \u2014 workers run in your k8s, code never leaves your network</p></td></tr><tr><td class=\"confluenceTd\"><p>Build caching</p></td><td class=\"confluenceTd\"><p>Not built-in</p></td></tr><tr><td class=\"confluenceTd\"><p>Review/steering</p></td><td class=\"confluenceTd\"><p>Slack integration, attach to running agent from Cursor desktop, PR creation</p></td></tr><tr><td class=\"confluenceTd\"><p>Documentation/planning</p></td><td class=\"confluenceTd\"><p>Skills, <a href=\"http://AGENTS.md\" class=\"external-link\" rel=\"nofollow\">AGENTS.md</a>, rules all supported</p></td></tr><tr><td class=\"confluenceTd\"><p>BYOK API keys</p></td><td class=\"confluenceTd\"><p>Partial \u2014 Cursor controls model routing</p></td></tr></tbody></table></div><p><strong>Tradeoffs:</strong></p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Pro</p></th><th class=\"confluenceTh\"><p><span class=\"inline-comment-marker\" data-ref=\"2301c614-8fdc-412d-ae60-0e206f8d2237\">Con</span></p></th></tr><tr><td class=\"confluenceTd\"><p>Fastest path \u2014 team is already on Cursor</p></td><td class=\"confluenceTd\"><p>Cursor controls inference layer \u2014 limited BYOK flexibility</p></td></tr><tr><td class=\"confluenceTd\"><p>Helm chart + k8s operator handles scaling</p></td><td class=\"confluenceTd\"><p>Vendor lock-in to Cursor's orchestration plane</p></td></tr><tr><td class=\"confluenceTd\"><p>Slack integration works out of the box</p></td><td class=\"confluenceTd\"><p>Oleg found it &quot;clumsy and buggy&quot;</p></td></tr><tr><td class=\"confluenceTd\"><p>Skills/rules/AGENTS.md all carry over</p></td><td class=\"confluenceTd\"><p>Cost: Cursor Pro/Business per seat + infra</p></td></tr><tr><td class=\"confluenceTd\"><p>Graphite integration for stacked PRs</p></td><td class=\"confluenceTd\"><p>Doesn't solve the build cache problem natively</p></td></tr></tbody></table></div><p><strong>Best for:</strong> Getting to a working state fast with minimal new tooling.</p><hr/><h2 id=\"CloudAgents:OptionsAnalysis-Option2:ClaudeAgentSDKonYourInfra\">Option 2: Claude Agent SDK on Your Infra</h2><p><strong>What it is:</strong> Anthropic's Agent SDK lets you build and host your own agent infrastructure. You control everything \u2014 the orchestration, sandboxing, model selection, and tooling.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Requirement</p></th><th class=\"confluenceTh\"><p>Coverage</p></th></tr><tr><td class=\"confluenceTd\"><p>Cloud Agent experience</p></td><td class=\"confluenceTd\"><p>You build the UX \u2014 SDK handles agent lifecycle, tool execution, sessions</p></td></tr><tr><td class=\"confluenceTd\"><p>Self-hosted on your infra</p></td><td class=\"confluenceTd\"><p>Full control \u2014 runs in containers on your k8s</p></td></tr><tr><td class=\"confluenceTd\"><p>Build caching</p></td><td class=\"confluenceTd\"><p>You integrate it</p></td></tr><tr><td class=\"confluenceTd\"><p>Review/steering</p></td><td class=\"confluenceTd\"><p>Build custom review flows, PR bots, Slack integration via MCP</p></td></tr><tr><td class=\"confluenceTd\"><p>Documentation/planning</p></td><td class=\"confluenceTd\"><p>Full control over prompt engineering, skills, context management</p></td></tr><tr><td class=\"confluenceTd\"><p>BYOK API keys</p></td><td class=\"confluenceTd\"><p>Native Anthropic support; OpenAI via their compatible API endpoint</p></td></tr></tbody></table></div><p><strong>Tradeoffs:</strong></p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Pro</p></th><th class=\"confluenceTh\"><p>Con</p></th></tr><tr><td class=\"confluenceTd\"><p>Full BYOK \u2014 use any model via API keys you control</p></td><td class=\"confluenceTd\"><p>Significant build effort to reach Cursor-like DX</p></td></tr><tr><td class=\"confluenceTd\"><p>No vendor lock-in on orchestration</p></td><td class=\"confluenceTd\"><p>You own maintenance and upgrades</p></td></tr><tr><td class=\"confluenceTd\"><p>Alphaclaw is already a working prototype</p></td><td class=\"confluenceTd\"><p>Atindra is the primary maintainer \u2014 <span class=\"inline-comment-marker\" data-ref=\"2636bad2-f07d-4e30-85b7-0b88132fd3be\">bus factor concern</span></p></td></tr><tr><td class=\"confluenceTd\"><p>Works with your existing NFS/PVC setup</p></td><td class=\"confluenceTd\"><p>Need to build monitoring/observability</p></td></tr></tbody></table></div><p><strong>Best for:</strong> Maximum flexibility and control. Ideal if you want agents deeply integrated with your specific workflows.</p><hr/><h2 id=\"CloudAgents:OptionsAnalysis-Option3:Netclode(Open-SourceSelf-HostedPlatform)\">Option 3: Netclode (Open-Source Self-Hosted Platform)</h2><p><strong>What it is:</strong> A fully open-source self-hosted remote coding agent platform built on k3s + Kata Containers + Cloud Hypervisor microVMs + Tailscale.</p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Requirement</p></th><th class=\"confluenceTh\"><p>Coverage</p></th></tr><tr><td class=\"confluenceTd\"><p>Cloud Agent experience</p></td><td class=\"confluenceTd\"><p>iOS app + web interface, session pause/resume</p></td></tr><tr><td class=\"confluenceTd\"><p>Self-hosted on your infra</p></td><td class=\"confluenceTd\"><p>100% self-hosted, open source</p></td></tr><tr><td class=\"confluenceTd\"><p>Build caching</p></td><td class=\"confluenceTd\"><p>Not built-in</p></td></tr><tr><td class=\"confluenceTd\"><p>Review/steering</p></td><td class=\"confluenceTd\"><p>Basic \u2014 agents run in sandboxed microVMs</p></td></tr><tr><td class=\"confluenceTd\"><p>BYOK API keys</p></td><td class=\"confluenceTd\"><p>Yes \u2014 direct Anthropic SDK integration + Ollama for local models</p></td></tr></tbody></table></div><p><strong>Tradeoffs:</strong></p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Pro</p></th><th class=\"confluenceTh\"><p>Con</p></th></tr><tr><td class=\"confluenceTd\"><p>Fully open source \u2014 no vendor dependency</p></td><td class=\"confluenceTd\"><p>Young project \u2014 less battle-tested</p></td></tr><tr><td class=\"confluenceTd\"><p>MicroVM isolation is best-in-class security</p></td><td class=\"confluenceTd\"><p>k3s-native; adapting to EKS may be nontrivial</p></td></tr><tr><td class=\"confluenceTd\"><p>Snapshot/restore is powerful for agent experimentation</p></td><td class=\"confluenceTd\"><p>No Slack integration built-in</p></td></tr><tr><td class=\"confluenceTd\"><p>Session pause/resume saves compute</p></td><td class=\"confluenceTd\"><p>Requires nested virtualization support</p></td></tr></tbody></table></div><p><strong>Best for:</strong> Teams that want maximum isolation and open-source control, and are willing to invest in customization.</p><hr/><h2 id=\"CloudAgents:OptionsAnalysis-Option4:Hybrid\u2014CursorSelf-Hosted+ClaudeAgentSDK(Recommended)\">Option 4: Hybrid \u2014 Cursor Self-Hosted + Claude Agent SDK (Recommended)</h2><p><strong>What it is:</strong> Use Cursor Self-Hosted Cloud Agents as the primary developer-facing coding agent, while running Claude Agent SDK-based agents (via Alphaclaw) for specialized workflows that need deeper integration (training pipelines, overnight eval loops, robot mock runs, documentation generation).</p><p>This is essentially what's already emerging organically: Cursor Cloud Agents for day-to-day coding + Alphaclaw/Oleg's agents for overnight training/eval loops + the #agent-requests Slack channel for on-demand tasks.</p><p><strong>What you'd need to do:</strong></p><ul><li><p>Deploy Cursor self-hosted (Phase 1 \u2014 fast)</p></li><li><p><span class=\"inline-comment-marker\" data-ref=\"464b9b89-0178-400d-82e9-0be3de4b9101\">Productionize Alphaclaw on EKS with NFS (Phase 2 \u2014 medium effort)</span></p></li><li><p>Add shared build cache layer (Phase 2)</p></li><li><p>Build unified monitoring dashboard (Phase 3)</p></li><li><p>Standardize the agent-request interface across both systems</p></li></ul><p><strong>Tradeoffs:</strong></p><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Pro</p></th><th class=\"confluenceTh\"><p>Con</p></th></tr><tr><td class=\"confluenceTd\"><p>Meets devs where they are (Cursor) while unlocking specialized agents</p></td><td class=\"confluenceTd\"><p>Two systems to maintain</p></td></tr><tr><td class=\"confluenceTd\"><p>BYOK for specialized agents (training, eval, planning)</p></td><td class=\"confluenceTd\"><p>Model routing still Cursor-controlled for coding tasks</p></td></tr><tr><td class=\"confluenceTd\"><p>Incremental \u2014 ship Cursor self-hosted fast, iterate on SDK agents</p></td><td class=\"confluenceTd\"><p>Potential UX fragmentation</p></td></tr><tr><td class=\"confluenceTd\"><p>Leverages existing work (Alphaclaw, DevPods, skills)</p></td><td class=\"confluenceTd\"><p>Need clear ownership boundaries</p></td></tr></tbody></table></div><hr/><h2 id=\"CloudAgents:OptionsAnalysis-Recommendation\">Recommendation</h2><p><strong>Start with Option 4 (Hybrid), phased:</strong></p><p><strong>Phase 1 (This week):</strong> Enable Cursor Self-Hosted Cloud Agents on your EKS cluster. Atindra has already requested dashboard access, Mustafa volunteered for k8s setup.</p><p><strong>Phase 2 (Next 2\u20134 weeks):</strong> Productionize the Claude Agent SDK path. Merge and harden Alphaclaw on EKS with NFS mounts for shared state. This covers overnight agents, training loops, and full BYOK needs.</p><p><strong>Phase 3 (Q2):</strong> Add the shared infrastructure layer \u2014 distributed build cache, unified monitoring, and a Slack-based steering interface that works across both systems.</p><hr/><h2 id=\"CloudAgents:OptionsAnalysis-QuickReference:PlatformComparison\">Quick Reference: Platform Comparison</h2><div class=\"table-wrap\"><table data-layout=\"default\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Dimension</p></th><th class=\"confluenceTh\"><p>Cursor Self-Hosted</p></th><th class=\"confluenceTh\"><p>Claude Agent SDK</p></th><th class=\"confluenceTh\"><p>Netclode</p></th><th class=\"confluenceTh\"><p>Hybrid (Recommended)</p></th></tr><tr><td class=\"confluenceTd\"><p>Time to production</p></td><td class=\"confluenceTd\"><p>Days</p></td><td class=\"confluenceTd\"><p>Weeks</p></td><td class=\"confluenceTd\"><p>Weeks</p></td><td class=\"confluenceTd\"><p>Days (P1) + Weeks (P2)</p></td></tr><tr><td class=\"confluenceTd\"><p>BYOK (Anthropic)</p></td><td class=\"confluenceTd\"><p>Limited</p></td><td class=\"confluenceTd\"><p>Full</p></td><td class=\"confluenceTd\"><p>Full</p></td><td class=\"confluenceTd\"><p>Full (via SDK layer)</p></td></tr><tr><td class=\"confluenceTd\"><p>BYOK (OpenAI)</p></td><td class=\"confluenceTd\"><p>Limited</p></td><td class=\"confluenceTd\"><p>Via API</p></td><td class=\"confluenceTd\"><p>Via Ollama/API</p></td><td class=\"confluenceTd\"><p>Full (via SDK layer)</p></td></tr><tr><td class=\"confluenceTd\"><p>Build caching</p></td><td class=\"confluenceTd\"><p>BYO</p></td><td class=\"confluenceTd\"><p>BYO</p></td><td class=\"confluenceTd\"><p>BYO</p></td><td class=\"confluenceTd\"><p>BYO (shared)</p></td></tr><tr><td class=\"confluenceTd\"><p>Review/steering</p></td><td class=\"confluenceTd\"><p>Good</p></td><td class=\"confluenceTd\"><p>Build your own</p></td><td class=\"confluenceTd\"><p>Basic</p></td><td class=\"confluenceTd\"><p>Best of both</p></td></tr><tr><td class=\"confluenceTd\"><p>IDE integration</p></td><td class=\"confluenceTd\"><p>Native (Cursor)</p></td><td class=\"confluenceTd\"><p>None</p></td><td class=\"confluenceTd\"><p>App-based</p></td><td class=\"confluenceTd\"><p>Cursor for coding</p></td></tr><tr><td class=\"confluenceTd\"><p>Vendor lock-in</p></td><td class=\"confluenceTd\"><p>Medium</p></td><td class=\"confluenceTd\"><p>Low</p></td><td class=\"confluenceTd\"><p>None</p></td><td class=\"confluenceTd\"><p>Low-Medium</p></td></tr><tr><td class=\"confluenceTd\"><p>Fits existing workflow</p></td><td class=\"confluenceTd\"><p>High</p></td><td class=\"confluenceTd\"><p>Medium</p></td><td class=\"confluenceTd\"><p>Low</p></td><td class=\"confluenceTd\"><p>High</p></td></tr></tbody></table></div><hr/><h2 id=\"CloudAgents:OptionsAnalysis-Sources\">Sources</h2><p>Internal discussions: #agentic-ai-practices, #team_eng-software, #team_data-and-compute-platform</p><p>Key Slack threads: Self-hosted cloud agents (Mar 25\u201331), AI Captains sync (Mar 2), Agent framework selection (Mar 16), Claude Enterprise activation (Mar 31)</p><p>Google Drive docs: Agentification project (Oleg Sinavski), 2026 Q2 planning notes, Agentic Development Workflow Proposal (Andy Park)</p>"
        },
        {
          "id": "1803386953",
          "title": "Potential Deployment MVP for Symphony",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1803386953",
          "last_modified": "2026-03-26T19:53:43.004Z",
          "created_at": "2026-03-26T18:38:53.924Z",
          "body_html": "<p local-id=\"7b7a7e66667b\">This is a rough attempt to get some level of actionable scope for the <a href=\"https://docs.google.com/document/d/15hRaVqTAW0m69CgOuDr0anjdzPh8z_Nfp4zgHT7t86g\" class=\"external-link\" rel=\"nofollow\">Symphony demo</a>, which I believe the core premise is this iterative specification of a workflow.  There is a lot of ancillary scope in this document, various objects, capabilities, behaviors - but the real guts is being able to build up complicated workflows incrementally by natural language.  First, some realities:</p><ul local-id=\"c9b11e343b31\"><li local-id=\"50c9c7db433d\"><p local-id=\"804f86f699bf\">The map/demo area is chaotic - this is because we will be doing maintenance, people around, data collection, and everyone will be fiddling with the \u201cset\u201d up until the last moment</p></li><li local-id=\"795fe313d3cb\"><p local-id=\"e1a36cc1d519\">The policy isn\u2019t as good as we want it to be - there will be limitations about posing, locations, etc and we will be unlikely to get sufficient reliability on the behaviors covered in the scope doc on day 1</p></li><li local-id=\"f7a151741dba\"><p local-id=\"2fdf13a6e53b\">The UI will not be very friendly and the experience won\u2019t be very smooth</p></li></ul><p local-id=\"3cd434528bb6\">So given this - what do we do?</p><p local-id=\"9e92989df7a4\"><strong>Single Shot Deployment </strong></p><p local-id=\"590ea12e3c6c\">I think <a href=\"/wiki/spaces/ROBOT/pages/1485275162/Spec+Single-Shot+Deployment+MVP\" data-linked-resource-id=\"1485275162\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">single shot deployment</a> can address the first point above by making it trivial to deal with changes to the environment.  But this isn\u2019t enough.  This operation can give us a set of interesting tags and some default \u201chappy path\u201d behaviors to get started immediately, but it falls short in some serious ways:</p><ul local-id=\"507c6149c271\"><li local-id=\"99ff4fa35b7c\"><p local-id=\"06b1b82dbf43\">Making a robust workflow in a single shot is much harder for the operator than for the robot (though the solution is fairly unreliable even for the robot if the instruction is good)</p></li><li local-id=\"1ff0d14b34f9\"><p local-id=\"fd7c330b6d25\">The inferred map tags are not at all semantically relevant.  It knows you ran some policy at some point, but it doesn\u2019t know that its the conveyor or whatever</p></li><li local-id=\"2d69c2aece39\"><p local-id=\"5db8b09c3c11\">With a single trace you can\u2019t do anything other than trivial sequences/loops - no branches or conditions</p></li><li local-id=\"2c48667cd1ee\"><p local-id=\"db720c807bf8\">With a demonstration, your workflow can\u2019t easily be impacted by \u201cunobservable\u201d stuff - like \u201cwaiting for a webhook\u201d or similar</p></li></ul><p local-id=\"c9171289091f\">What single shot deployment DOES do is break the need to launch with a fixed workflow.  You can launch empty, and then have the robot doing something autonomously.  Localization is a challenge with this runtime reloading though\u2026 A major issue with the current scheme is that because it re-uses the slam_toolbox used for our normal mapping stack, it requires data to be replayed through the stack.  This was done \u201coffline\u201d from recorded mcap files for analysis and rapid iteration, but this also complicates things a bit and may not be necessary for the goals we have here. </p><p local-id=\"da26a2d1b9e6\"><strong>Incremental Loop</strong></p><p local-id=\"b00a047214a0\">Given some baseline, we want to be able to make edits to the workflow - at runtime.  So not only do we need to load a workflow at runtime, we need to be able to reload that workflow at runtime.  And we need to be able to do this while maintaining execution state (ideally) for rapid iteration.  It isn\u2019t well-understood just how \u201cbig\u201d these edits can reliably be (or what the tradeoffs are between small edits maybe modifying a transition or inserting a new state vs larger edits which rework significant portions of the workflow).  It may also be necessary to extend the map with new tags, which sort of blurs the line between what\u2019s done with the workflow and what\u2019s done with the map.  This further bolsters the idea of potentially moving to a more \u201conline\u201d mapping system, but it could be challenging to reliably place tags if the map shifts or if localization is unreliable - especially in environments that can rapidly change over time.</p><p local-id=\"fbb5ff9c2d2a\">So - we want to be able to get some baseline workflow (call it the 80% deployment), and then iterate the rest of the way incrementally via the agent loop using high-level intent/natural language.  We don\u2019t care about the interface at this point - just this core loop.  We could \u201clock\u201d the workflow or have some \u201cscene graph\u201d provided a priori, but this could be frustrating as the environment evolves, and its likely that this data will be stale.  On the other hand, single shot deployment has its own downsides (tag names, unreliability, extending tags, etc).</p><p local-id=\"470a42a64da3\"><strong>Example Scenario</strong></p><p local-id=\"24a55c71e5e7\">I\u2019m thinking something like we create a looping workflow for moving a stack of totes to the conveyor.  This is easy to do with a looped single shot:</p><ul local-id=\"5ad15ffdb0d2\"><li local-id=\"38806b633358\"><p local-id=\"41bc88db6e4a\">idle</p></li><li local-id=\"994dcb601843\"><p local-id=\"d1dd13ad0c2b\">navigate to stack</p></li><li local-id=\"380ac3603e9d\"><p local-id=\"b3ab1a7beed5\">pick tote</p></li><li local-id=\"84f54b98fa63\"><p local-id=\"47326229f338\">navigate to conveyor</p></li><li local-id=\"f7fd5bdd7882\"><p local-id=\"c82e4c650691\">place tote</p></li><li local-id=\"42556edb3ac8\"><p local-id=\"5d58735d4834\">&lt;loop&gt;</p></li></ul><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"1604\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1803386953/Untitled%20Diagram-1774554199665.drawio.png?api=v2&amp;version=2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1803386953/Untitled%20Diagram-1774554199665.drawio.png?api=v2&amp;version=2\" loading=\"lazy\"></span><p local-id=\"194ffedbc960\">Obviously this has a flaw - at some point the stack is empty and the robot gets stuck.  We should be able to communicate something like: \u201cwhen you get a Destack work item, it will contain the total number of totes expected to move.  stop after that many totes\u201d (or something like this).   The robot can wait in some idle position, until this work item is injected into the workflow (via agent or cmdline or whatever) and then the robot will attempt to move that many pallets from the stack.</p><p local-id=\"7a7d436319d4\">The good:</p><ul local-id=\"04c38c3ca104\"><li local-id=\"39cd850bf8d8\"><p local-id=\"9f26bb11b04e\">clear \u201cMVP\u201d for single-shot deployment that demonstrates the weaknesses of that approach</p></li><li local-id=\"d3dd8dd8b6d4\"><p local-id=\"feef89dcf3aa\">avoids need for perception or a priori knowledge of the scene (fragile) - instead we can inject this via a work-item/token in the coordinator (as we\u2019ve done for all our previous PoCs)</p></li><li local-id=\"2052153f345e\"><p local-id=\"c90c7955c1e7\">shows incremental addition of unobservable stuff</p></li></ul><p local-id=\"6e98852aab67\">The bad:</p><ul local-id=\"5961f3c8d89b\"><li local-id=\"a8700b9d11f8\"><p local-id=\"1e05805b66ec\">need some way to trigger the workflow / inject the work</p><ul local-id=\"0f08e0af3b48\"><li local-id=\"75f9dbb7a13a\"><p local-id=\"e89933cef450\">in \u201cediting mode\u201d it would be awesome if the agent could just trigger stuff for us.  \u201chey, there\u2019s a stack of 5 totes on the pallet - time to move\u201d \u2192 injects Destack { count: 5 } to PendingStacks (or whatever)</p></li></ul></li><li local-id=\"3cfdc86be3d2\"><p local-id=\"c2a2b00237fc\"><span class=\"inline-comment-marker\" data-ref=\"34df9f27-63f6-4b92-b3de-a4105e71e146\">need to keep track of counts as facts in the blackboard</span></p><ul local-id=\"1300f8f2a270\"><li local-id=\"ef066707c121\"><p local-id=\"565b076d2ad2\"><span class=\"inline-comment-marker\" data-ref=\"34df9f27-63f6-4b92-b3de-a4105e71e146\">new workflow extensions to decrement counters could make this pretty slick and easy/validate</span></p></li></ul></li><li local-id=\"b0a50635b851\"><p local-id=\"f39440bb2420\"><span class=\"inline-comment-marker\" data-ref=\"30bb49a0-662b-426a-b61f-d7f9d0cdd28b\">map tags will be unintuitive/meaningless unless we have some way to re-name things</span></p><ul local-id=\"0803e4094279\"><li local-id=\"65bc53d4fc8b\"><p local-id=\"dfabde415cea\"><span class=\"inline-comment-marker\" data-ref=\"30bb49a0-662b-426a-b61f-d7f9d0cdd28b\">this is something we can cheat on a bit.  for example, when we run policy we could provide a semantic label or something to back-channel this into the workflow/map as a tag name</span></p></li></ul></li></ul><p local-id=\"5920a7a668c0\">The ugly:</p><ul local-id=\"6fc39858cb55\"><li local-id=\"6325e059c51b\"><p local-id=\"dd6438b9eed0\">we need to somehow patch the workflow and get the robot into some idle state online during/after editing - possible, but definitely challenging</p></li></ul><p local-id=\"be0a9ba548a2\">I think this is a relatively simple loop that exposes the \u201cheart\u201d of Symphony without any major risk on the policy side.  You can rapidly get some baseline given a configuration of the environment, and then iterate through the edge-cases to get a more sophisticated workflow.  Over time as we get more capabilities, we can extend. this to get more and more complexity, but I think this is a good viable target for an initial integrated deliverable.</p><p local-id=\"abc3a3a6086f\"><strong>Anti-Goals</strong></p><p local-id=\"9cdfd0c5d3ec\">The above, even though its relatively simple, is probably going to be very difficult and full of weird shit making it harder than expected (beyond the more obvious stuff I\u2019ve identified).  We\u2019ll want to maximize the amount of time we have to identify these issues without getting caught up in things that we don\u2019t need to address right now.  For example, this minimal scenario is a single robot - so we don\u2019t need to worry about the cloud instances of these services, nor do we really need to persist things to disk.  Having to redeploy repeatedly when we wipe switchboard could be annoying and frustrating, but its also a great forcing function to focus on the end-to-end loop and get many many many iterations trying this out.</p><p local-id=\"232757f39e11\">We should resist temptation to address the details until all this scenario starts to come together.  Once we can SOMETIMES make the above scenario work, we can start looking at the major challenges and prioritize a backlog to address.  There are a number of improvements to agentic editing captured in <a href=\"/wiki/spaces/ROBOT/pages/1715994636/Studio+Agentic+Workflow+Updates\" data-linked-resource-id=\"1715994636\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Studio: Agentic Workflow Updates</a>  that could improve undo/history, context management, traceability of intent and the generation of human-level SOPs.  These items too should all take a backseat to getting the basic loop above in place.  Its 100 times easier to iterate on a working system than an incomplete system.   </p><p local-id=\"194bd85fe9ab\">There will be some tough calls.  I\u2019ll use the offline mapping as an example - its a big source of problems, but it <em>kinda</em> works.  During the course of this, we may determine that a better approach is to use the slam toolbox lifelong mapping and just do tagging as we navigate in a map for deployment (rather than offline slam).  Totally viable - many benefits.  But it could be a 2-steps-back-3-steps-forward situation that we may not have time for.  If we can get something working ASAP, we have plenty of time for these improvements.  If we try and frontload these improvements, we risk not addressing unknown blockers and we may have enormous amounts of schedule crunch resulting in even MORE tech debt.  On the other hand, if the offline mapping proves to be a blocker (like a real, nothing is going to happen, no workaround, no retry a few times) - then it must of course be addressed immediately in pursuit of the goal.</p><p local-id=\"9befb0b97917\"><strong>We all want a VERY reliable system - trust that these improvements will be prioritized.  But the primary goal is to demonstrate something like the above scenario as soon as possible.</strong></p>"
        },
        {
          "id": "1637417000",
          "title": "AI Proxy",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1637417000",
          "last_modified": "2026-03-23T10:23:27.567Z",
          "created_at": "2026-02-12T13:56:05.684Z",
          "body_html": "<h2 id=\"AIProxy-ProblemStatement\">Problem Statement</h2><p>Robots need controlled access to LLM APIs without carrying provider API keys on-device. The right shape is a single HMND endpoint that robots can call with the same device certificate they already use for Backbone, while the service itself holds provider credentials centrally and attaches usage to a concrete <code>device_id</code>. We do not need a billing platform in the first version, but we do want enough attribution and observability to understand how shared upstream keys are being used across devices.</p><h2 id=\"AIProxy-RecommendedDirection\">Recommended Direction</h2><p>The simplest useful design is to build a separate AI proxy service as a sibling to Backbone and use <code>lm-proxy</code> as the provider translation layer inside it. The service should live under <code>hmnd_services/ai_proxy</code>, and the corresponding deployment should live under <code>hmnd_infra/modules/ai_proxy_stack</code>. It should sit behind the same ALB mTLS pattern already used for Backbone device endpoints, reuse the same SPIFFE-based device identity extraction logic, and authorize requests against the existing <code>devices</code> table.</p><p>This is a better fit than a heavier gateway solution because it stays close to the shape of the current HMND stack. We already have the hard identity and certificate lifecycle pieces. What we need is a small, understandable egress layer for model traffic. <code>lm-proxy</code> is a good fit for that because it is lightweight, Python-native, OpenAI-compatible, and supports the provider set we care about without bringing in a much larger control plane.</p><h2 id=\"AIProxy-WhyThisShouldBeSeparateFromBackbone\">Why This Should Be Separate From Backbone</h2><p>Backbone should stay the control plane for device identity, enrollment, renewal, and authorization data. The AI proxy should be a separate service because LLM traffic has different operational behavior. Requests are larger, slower, and more failure-prone than enrollment or session heartbeats. Provider-specific outages, timeouts, and streaming edge cases should not threaten the device control plane. Splitting the services keeps rollout and scaling independent while still reusing the same identity model.</p><p>This also keeps the architecture honest. Backbone answers &quot;who is this device and is it allowed.&quot; The AI proxy answers &quot;how do I safely forward this model request and measure what happened.&quot; If we blur those roles, we turn Backbone into both a control-plane service and a data-plane service, which is not a good trade.</p><h2 id=\"AIProxy-ExternalAPIShape\">External API Shape</h2><p>The proxy should expose an OpenAI-compatible HTTP surface at <code>https://ai.core.&lt;env&gt;.hmnd.ai/v1/...</code>. The first version should support <code>POST /v1/chat/completions</code>, <code>POST /v1/responses</code>, <code>POST /v1/embeddings</code>, and <code>GET /v1/models</code>. That matches the main HTTP patterns already used in the repo and gives robot applications a stable contract even when the upstream provider changes.</p><p>OpenAI Realtime WebSocket support should not be part of the initial scope. The repo does contain Realtime usage today, but Realtime is a different transport and a different portability problem. Trying to solve it in the first delivery would make the whole project harder and slower. The HTTP path should land first, and Realtime should be considered separately if it remains necessary.</p><h2 id=\"AIProxy-Whylm-proxy\">Why <code>lm-proxy</code></h2><p><code>lm-proxy</code> is attractive here because it is smaller and simpler than LiteLLM while still covering the essential requirement: an OpenAI-compatible interface over multiple providers such as OpenAI, Anthropic, and Google/Gemini. It is easier to inspect, easier to embed, and less likely to push the design toward a full-featured gateway platform than a larger tool would.</p><p>The tradeoff is that it does not bring the same breadth of built-in spend management, policy controls, or ecosystem depth that LiteLLM does. That is real, but it is not the main requirement here. HMND already has a stronger notion of client identity than most general-purpose AI gateways because our clients are robots authenticated by mTLS device certificates. The important thing is not whether the proxy has a sophisticated tenant-key system of its own. The important thing is that the HMND edge can attach <code>device_id</code> to every request, keep provider credentials off the robot, and emit enough structured usage data to be operationally useful.</p><h2 id=\"AIProxy-RobotCertificateReuse\">Robot Certificate Reuse</h2><p>The AI path should reuse the existing Backbone client certificate, private key, and chain. We should not invent a second robot credential or a second renewal mechanism. <code>hmnd-backboned</code> already manages the certificate lifecycle and stores the artifacts locally. The AI proxy should simply consume the same artifacts.</p><p>To make that practical, the robot side should get a small shared mTLS client helper. That helper should know the standard cert, key, chain, and server trust paths, construct an HTTP client with mTLS enabled, and reload credentials after renewal. Since the current AI callers are Python, a Python helper is enough for the first version. Without that helper, each application will end up reimplementing the certificate-loading problem differently.</p><p>Some OpenAI-style SDKs still expect an <code>api_key</code> argument even when real authentication is done with mTLS. That is manageable. Those clients can be given a placeholder value while the server ignores bearer auth entirely and relies on mTLS as the real credential. The important point is that no provider API key should live on the robot.</p><h2 id=\"AIProxy-Authorization\">Authorization</h2><p>The AI proxy should authorize requests by reading the Backbone <code>devices</code> table directly rather than calling Backbone on every request. Once <code>device_id</code> is extracted from the client certificate, the service should perform a direct lookup in the device registry. If the device exists, the request proceeds. If it does not, the service returns <code>403</code> and does not call the upstream provider.</p><p>This keeps the hot path simple and avoids turning Backbone into a dependency on every model request. The AI proxy should receive its own database credentials with only the permissions it needs. In the first version, that likely means read access to the <code>devices</code> table and optional insert access if we later decide to persist usage events in SQL.</p><h2 id=\"AIProxy-ProviderCredentials\">Provider Credentials</h2><p>Provider credentials should live in AWS Secrets Manager and be scoped per provider. The service should load them through its task role, cache them in memory, and never expose them in logs or responses. The first version should focus on OpenAI and Anthropic. Gemini can be added once the basic path is stable, which avoids forcing an early decision about whether to start with Gemini API keys or go directly to Vertex AI credentials.</p><h2 id=\"AIProxy-UsageVisibilityandMetrics\">Usage Visibility and Metrics</h2><p>We do want to understand how shared upstream keys are being used across devices, but we do not need a full billing engine to get there. The best split is structured logs for per-request detail and low-cardinality metrics for service health.</p><p>Each request should emit a structured log event containing <code>device_id</code>, <code>robot_id</code>, <code>robot_type</code>, provider, requested model, resolved upstream model, status code, latency, request size, and token usage if the provider returns it. That is enough to answer the main operational question: which devices are using which provider and model, and with what error and latency profile.</p><p>Metrics should stay aggregate. Prometheus counters and histograms should record request counts, latency, token totals, and error totals by provider and coarse model family. We should not put <code>device_id</code> into metric labels because that creates unnecessary cardinality. If queryable historical usage becomes important later, that is the point to introduce a small <code>ai_usage_events</code> table keyed by <code>device_id</code>. Logs plus aggregate metrics are enough for the first version.</p><h2 id=\"AIProxy-MainLimitations\">Main Limitations</h2><p>The biggest limitation of this design is that <code>lm-proxy</code> is smaller and less feature-rich than LiteLLM. That is why it is attractive for this use case, but it also means we should not expect a full platform\u2019s worth of built-in spend tracking, policy controls, or broad provider edge-case handling. If the system eventually grows into a very wide AI gateway, the simpler choice may stop being the better one.</p><p>The second limitation is that OpenAI compatibility is practical rather than perfect. The common HTTP paths can be normalized well enough for day-to-day use, but provider-specific features will still leak through at the edges. The third limitation is that Realtime remains out of scope for the first version. The fourth is that cert reuse only becomes easy if we actually ship the shared robot-side client helper. Without that helper, the design remains sound but adoption becomes awkward.</p><h2 id=\"AIProxy-RolloutPlan\">Rollout Plan</h2><p>The first pass should stand up the new <code>ai_proxy</code> service and Terraform stack, wire the ALB mTLS edge, authorize against the <code>devices</code> table, and forward OpenAI-compatible HTTP requests to OpenAI first. That proves the core identity, secret custody, and attribution model.</p><p>The second pass should add Anthropic through <code>lm-proxy</code>, introduce simple model aliasing, and start emitting the structured usage logs and aggregate metrics we want. Gemini can follow once the team still wants it and the basic path is stable.</p><p>The third pass should introduce the shared robot-side mTLS client helper and migrate the existing robot-side HTTP AI callers to the proxy. At that point, the design is not only correct but also easy for application code to consume.</p><p>The fourth pass should harden the service with request-size limits, model allowlists, and coarse rate limiting. If queryable historical usage by device becomes important after that, we can add a dedicated SQL usage table.</p><h2 id=\"AIProxy-BottomLine\">Bottom Line</h2><p>The specific plan is to build a separate AI proxy service that sits behind the existing ALB mTLS device plane, reuses the Backbone certificate path on the robot, exposes an OpenAI-compatible HTTP contract, and uses <code>lm-proxy</code> internally as the provider adapter. This is simpler than a LiteLLM-centered design, better aligned with the current HMND Python and ECS stack, and still gives us the important properties we care about: centralized credential custody, per-device attribution, and useful visibility into how shared provider keys are being used.</p>"
        },
        {
          "id": "1718878287",
          "title": "Mapping and Tagging",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1718878287",
          "last_modified": "2026-03-09T17:49:49.411Z",
          "created_at": "2026-03-09T17:26:29.003Z",
          "body_html": "<p local-id=\"f65670ddfc96\">Right now, mapping and tagging are done \u201con the side\u201d, separate from our normal data collection or workflow execution.  The <a href=\"/wiki/spaces/ROBOT/pages/1485275162/Spec+Single-Shot+Deployment+MVP\" data-linked-resource-id=\"1485275162\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">Spec: Single-Shot Deployment MVP</a>  spec outlines a way to resolve this a bit in the context of inferring a workflow, but here we can also think more broadly about this problem in particular.</p><p local-id=\"15fe233f61a5\">When we start up our mapping stack, we will begin building a map (via slam_toolbox/nav2) immediately.  During this time, we can save map poses as \u201ctags\u201d.  When we save the map, we get an occupancy and some metadata describing the transform from pixel to map space, along with some map space tags.  In the MVP above, we assume we will generate a tag for any policies we infer via sockpuppet.</p><p local-id=\"4fb837627fc8\">We\u2019ll assume we have an initial map + tags from something like the single-shot MVP above.</p><p local-id=\"1d09ddd64828\"><strong>Incremental Mapping and Tagging</strong></p><p local-id=\"8ea0afab71f0\">Once you have an initial workflow, you have a map and some tags.  How do we evolve these over time?  We should be able to put the robot back into \u201cdeployment mode\u201d for example.  Do we just bring up SLAM and allow modification and save if they look good?  Or do we re-record and re-generate maps?  With the former, we need to run quite a bit of stuff at runtime that we haven\u2019t typically been running, and this could interfere with efforts to run only localization.  If we do the latter, we risk major issues with the origin shifting around depending on how the data is collected.</p><p local-id=\"9dfb271bde60\">We also need to support adding new tags, shifting tags or re-naming tags.  New tags would be needed if we added a new station or step to an existing workflow for example.  We can shift or move tags by simply saving a new tag with the same name.  Renaming tags is a bit trickier\u2026</p><p local-id=\"6e44f2f7a1d2\">We may want to rename tags if we want to support a voice-based deployment.  An auto-generated tag during workflow inference like \u201c<code>run_policy:place_2</code>&quot; is a pretty shitty identifier to have to speak.  The challenge with a rename is that there is an ambiguity around creating a new tag vs renaming an existing tag.  We can resolve this with a large-scale map editor or a list view of the tags - but this can be confusing if users have a poor grasp on the workflow or map.  Another way to do this would be to have sockpuppet\u2019s deployment interface show a list of \u201ccurrent tags\u201d which could be renamed.</p><p local-id=\"0394d85fd349\"><strong>Saving and Reloading</strong></p><p local-id=\"0cae186a520c\">In the event that we update the map or tags, we need to persist this.  And reload it.  Right now, this is frightful since the map + tags are stored in version control.  So you have to actually make a PR, check the code in, re-release, re-deploy - then you can restart the mapping stack to get the new map.  Of course we can simplify slightly for single-robot iteration in a dev context, but this scales horribly.</p><p local-id=\"151bc0840e51\">What we need to do is shift maps, workflows and tags from code to data.  A robot should be able to publish an updated version of this data, and other robots should be able to poll for this data, pull the new map/tags and reload on the fly - without being delocalized.</p>"
        },
        {
          "id": "1533018204",
          "title": "Spec: Data Recording and Upload",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1533018204",
          "last_modified": "2026-03-09T15:34:52.422Z",
          "created_at": "2026-01-20T15:10:46.362Z",
          "body_html": "<p local-id=\"898c2764-219c-4898-918c-6096ece5b320\"><strong>Owner</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a></p><p local-id=\"71fc6f96-c0f8-4902-8627-6d3940643d7f\"><strong>Date</strong>: <time datetime=\"2026-01-20\" class=\"date-past\">20 Jan 2026</time></p><p local-id=\"1d0d69ca-f93d-4c6d-8f83-b717b83fea40\"><strong>Approvers</strong>:</p><p local-id=\"97dfc473-e3ca-4909-841a-e8f82db3414b\"><strong>Informed</strong>:</p><p local-id=\"10d909ab-ab49-48e7-b9a3-34054b5b1c61\"><strong>Related</strong>: \n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-2820\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1533018204_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"7ea853a6-86dd-4ce6-9196-0797c50a09d6\" data-local-id=\"042a98ea9a4c\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-2820\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-2820</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p><h2 local-id=\"bca33384-f6a5-42e0-a6d2-d26403519659\" id=\"Spec:DataRecordingandUpload-Problem\">Problem</h2><p local-id=\"eff877e0-86e7-4444-a5f0-464f562aa684\">Today we run a \u201cdata_collection\u201d node along-side sockpuppet, which acts on user input to manage our recordings.  These recordings are organized into packages/episodes, uploaded via rclone to S3 and then can be viewed or annotated with Console and used for training models.</p><p local-id=\"14e8f16a-1095-48de-88d2-f79ef9565944\">With deployment by demonstration, we will need to introduce the ability to record mapping data during deployment, and there is also talk about uploading data from interventions (teleop) or even just while the demos are running.</p><p local-id=\"6406cc6d-c479-40b8-b04a-4f098ee41ea8\">The biggest issue with our current scheme is that its very stateful.  If we have all these various components managing the state of recording, we run into two significant issues:</p><ul local-id=\"f62f4c00-e128-45ff-b1b4-f5f23a4d64f5\"><li local-id=\"cc984b5e-67f7-42c1-962c-cb83f444bdb8\"><p local-id=\"2d538421-31ee-4414-9d62-ff9e94f16a5d\">It will be easy to introduce performance regressions if we test while NOT recording data</p></li><li local-id=\"f9cf7032-90e1-4f1b-8e17-5604c00134d1\"><p local-id=\"d9e88e14-70c8-4adf-b4e0-f0e3101d34fa\">It will be easy to have multiple components in the system disagreeing about the recording state or having issues if someone else currently holds the \u201caction goal\u201d</p></li></ul><p local-id=\"aa48c934-425b-4a21-af16-32d33ee19fdc\">This system was largely based on what existed for Pre-Alpha, but moving forward we should think about data collection slightly differently.  The goal here would be to:</p><ul local-id=\"dfe315cf-57f9-43f4-9b13-12c28a687457\"><li local-id=\"126a9aee-1172-4cf2-8709-c30d3e0820b8\"><p local-id=\"71f6ada4-f78e-4dec-9738-6c6de8576a76\">Constantly record data in 1 minute chunks (with some upper bound on size just in case) <span class=\"inline-comment-marker\" data-ref=\"56aedb17-1855-4935-bef8-7958a380e1b8\">to disk</span></p></li><li local-id=\"b549ff55-6d5e-4254-9c7d-26bd287255a5\"><p local-id=\"16d50d95-6b60-4110-91df-2b9f02c064d4\">Bound the storage on disk so we have a rotating buffer of the last N minutes of data</p></li><li local-id=\"791ab7e3-d7ac-4c8e-9883-1df14121942f\"><p local-id=\"2c6c1983-25ab-43e8-829b-b5a817eb88eb\">Upload events to the cloud to effectively index this data</p></li></ul><h2 local-id=\"a3e852d1-d16a-4627-959d-6f61dfdc2d78\" id=\"Spec:DataRecordingandUpload-Scope\">Scope</h2><h3 local-id=\"0e0bf34b-0996-412e-9be0-81cedcdd2e01\" id=\"Spec:DataRecordingandUpload-InScope\">In Scope</h3><ul local-id=\"1099e5ce-8c77-4069-b7d1-39d959c7814e\"><li local-id=\"6b32d6e8-9b80-419b-bd90-1f55fbef3760\"><p local-id=\"7361b23b-5e65-454b-9f7d-5f5f6cc76674\"><span class=\"inline-comment-marker\" data-ref=\"1374ed88-3781-477f-a74d-98cb9ca1682b\">Recording data constantly</span></p></li><li local-id=\"3f78ca64-5bee-418f-8613-fa755b307dd8\"><p local-id=\"4b55d7ad-ec57-46a9-8314-a4bfc05950c9\">How we partition/organize mcaps</p></li><li local-id=\"b3f71486-eb1a-46d9-85b1-bbb03a5006d8\"><p local-id=\"49e2c783-6217-4706-ae54-49e60103dcdd\">Scheduling uploads</p></li><li local-id=\"04c98849-29c9-4c1f-8f22-8ab9b5acc102\"><p local-id=\"7f2cd729-1d7d-4d16-bed7-ab649f432616\">Trace logs</p></li></ul><h3 local-id=\"1e8265d1-e784-4b5d-9412-8dc196df8e96\" id=\"Spec:DataRecordingandUpload-OutofScope\">Out of Scope</h3><ul local-id=\"c9450059-2eba-441a-a4c3-87ddc4b7ece8\"><li local-id=\"346bb763-cb8d-4ec0-92d2-c71316a91839\"><p local-id=\"8f551f4b-1bec-4b20-bb40-0c7f30ec6135\">Video compression (see <a href=\"/wiki/spaces/ROBOT/pages/1501986854/Spec+Video+Compression+for+Cameras\" data-linked-resource-id=\"1501986854\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Spec: Video Compression for Cameras</a>) </p></li></ul><h2 local-id=\"b4c4e624-9140-4ccf-ae4e-5eb5894349ce\" id=\"Spec:DataRecordingandUpload-DesignOverview\"><span class=\"inline-comment-marker\" data-ref=\"b94c1e74-74e9-41ce-af3c-200094d7afe6\">Design Overview</span></h2><p local-id=\"66bc9635-0988-4c41-b594-3defa408182c\">The main idea here is that we want to collect events from our robot applications, either during deployment or during execution.  These are effectively \u201cTempo\u201d traces that we can view in Grafana, and form the \u201cbackbone\u201d of our collected data.  What these trace spans do is describe what\u2019s happening during <span class=\"inline-comment-marker\" data-ref=\"7bc57b24-e761-4ea3-8f89-2ea6c8554de3\">specific time intervals</span> on the robot (hierarchically).</p><p local-id=\"e91ff7b2-55eb-422d-be31-608e3e144d30\" /><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"825\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1533018204/Untitled%20Diagram-1768922309178.drawio.png?api=v2&amp;version=2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1533018204/Untitled%20Diagram-1768922309178.drawio.png?api=v2&amp;version=2\" loading=\"lazy\"></span><p local-id=\"50736727-e351-4bdc-9684-1920cff5f03b\">MCAP data, on the other hand, is just dumped flat into a directory on the robot where we keep the last N minutes of data.  This will likely require a slightly custom version of the ros2 bag recording node (which isn\u2019t a bad thing since we could benefit from more control/monitoring here).</p><p local-id=\"3ed40920-7f72-4896-a650-70ce4f374daf\">Our trace spans effectively point to 1 or more of these MCAP files - meaning we can easily associate robot data with the event stream.  Instead of needing to manage the recording state or manually annotate packages or uploaded data, we simply upload events as we record.</p><p local-id=\"04e1c99f-a71f-4f66-8149-a4403cc854c5\"><strong><span class=\"inline-comment-marker\" data-ref=\"b27230ce-e05d-431e-b801-f110555a2ebe\">Uploading</span> Robot Data</strong></p><p local-id=\"22e2853f-c2c1-4feb-969c-4a899664379a\">Obviously we need to upload data sometimes.  With finite storage on the robot, we have some period of time (N minutes - depends almost entirely on how we encode video) to schedule and complete uploads before data is potentially overridden by newer data.</p><p local-id=\"a996c87f-099e-4e52-83f1-71c144529b79\"><span class=\"inline-comment-marker\" data-ref=\"72c18d7f-9491-4517-8636-878e084fe60e\">Data can be triggered or marked for upload from the robot itself (data collection via sockpuppet or interventions), or by request from some Console-based interface (perhaps to upload an interesting demo). </span>   </p><p local-id=\"da4d077fd464\"><u>Prod and cons of uploading all data:</u></p><p local-id=\"0313b8b38da2\">Argument for all uploading:<br/>1.  Debugging/troubleshooting.</p><p local-id=\"fc12421bd2ce\">Argument for filtering out data on the edge / device before uploading:</p><ol start=\"1\" local-id=\"84e1c66c2855\"><li local-id=\"59c04f52b6f9\"><p local-id=\"2751e4f89a9e\">Storage costs. </p></li><li local-id=\"83daf6db584f\"><p local-id=\"a87a76bc3bd8\">(Potential) Increased complexity of data infra (i.e. raw layer and cleaned data)</p></li><li local-id=\"0dfbdacf1a3a\"><p local-id=\"b2ce34358ee3\">Increased Data Annotation Effort. At the moment, all data we collect, we collect to train manipulation policies. These policies expect data to be sliced on episodes. </p></li></ol><p local-id=\"2f065b50-e42c-4b36-a0cd-060e0fa2f26c\"><strong>Trimming MCAP Data</strong></p><p local-id=\"8e82b351-b30c-4ef7-affa-1947e9e3a848\">One downside of this approach is that the MCAP writer doesn\u2019t know or care about the more granular boundaries of our data.  So while we can identify the 5 minute range of MCAP data which overlaps with the interesting span, it will potentially have some extra data at the beginning or end.  Do we trim this on the robot before uploading (requires more processing/buffering on the robot), or do <span class=\"inline-comment-marker\" data-ref=\"13813a3d-ec6c-45d5-9221-636d15eb0ec5\">we trim these in the cloud?</span>  My preference would be cloud-side since we aren\u2019t as resource-constrained there.</p><p local-id=\"303250dc-c440-4776-91e7-4b9039ce5206\"><strong>Event Delivery Guarantees</strong></p><p local-id=\"cf42d80e-2a20-4a0f-84cd-a29f492b8238\">At least once semantics would be required here.  Note that there are specific challenges around handling power-off, since we can\u2019t guarantee that we\u2019ll send an event for this.  For this reason each \u201csession\u201d (where we boot the robot) should be uniquely identified in the events so we may infer reboots later.  </p><h2 local-id=\"0f8bb0bc-379d-45fa-8dc1-45e756547e44\" id=\"Spec:DataRecordingandUpload-UseCases\">Use Cases</h2><h3 local-id=\"3e524c08-0f7b-4ca0-8d4c-36969199265b\" id=\"Spec:DataRecordingandUpload-DataCollectionwithSockpuppet\"><strong>Data Collection with Sockpuppet</strong></h3><p local-id=\"93dfbcc6-295a-4b12-99af-0a0b048289a8\">Operators start Sockpuppet, and emit trace spans for each episode we wish to record, annotated by the success/failure, package and any other relevant metadat.  The current scheme records selectively, but it uploads everything that\u2019s recorded.  This new scheme would flip this - we record everything but we\u2019re more selective about what\u2019s updated.</p><h3 local-id=\"30cd48f1-4dca-4d69-90ff-66219beb92b5\" id=\"Spec:DataRecordingandUpload-DeploymentwithSockpuppet(Spec:Single-ShotDeploymentMVP)\"><strong>Deployment with Sockpuppet (</strong><a href=\"/wiki/spaces/ROBOT/pages/1485275162/Spec+Single-Shot+Deployment+MVP\" data-linked-resource-id=\"1485275162\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">Spec: Single-Shot Deployment MVP</a> )</h3><p local-id=\"ba8450f8-56c6-4342-a5d9-203e197843d3\">Here we toggle some deployment mode to emit a deployment event, perform the deployment work (potentially with more data collection for specific policies), and then emit a final event when we are done.  We can then upload all the mapping data corresponding to the deployment span, and the policy data corresponding to any episodes collected while deploying for capability development and model training.</p><h3 local-id=\"fdc52edb-f50f-4966-8ff7-30aa2f8c6a11\" id=\"Spec:DataRecordingandUpload-ProductSupportandPoCs\"><strong>Product Support and PoCs</strong></h3><p local-id=\"8a18eba8-e7be-41c2-9e3b-252dd29f3039\">Sometimes we may experience something weird during a demo or PoC.  If we can\u2019t reliably reproduce the issue, its nearly impossible to catch.  But if we can identify the time window from logs fast enough, we can simply mark the MCAP data for upload because we\u2019re always recording.</p><h3 local-id=\"c63585d6-9440-4bea-8c13-96799ce90cdd\" id=\"Spec:DataRecordingandUpload-Interventions\"><strong>Interventions</strong></h3><p local-id=\"fb424e48-0c3c-4c16-b2fb-99df2d18ab52\">Any time we fail to teleop during execution, we can emit a span and upload the resulting data.</p><p local-id=\"f127ff17-377a-46dd-b858-b4dc87d492ff\" />"
        },
        {
          "id": "1715994636",
          "title": "Studio: Agentic Workflow Updates",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1715994636",
          "last_modified": "2026-03-07T17:58:13.480Z",
          "created_at": "2026-03-07T14:02:59.213Z",
          "body_html": "<h2 local-id=\"097607fe2eaf\" id=\"Studio:AgenticWorkflowUpdates-ProblemStatement\">Problem Statement</h2><p local-id=\"f13fb40ca11f\">While deployment from demonstration is a convenient way to infer simple workflows and anchor workflow states to key points on a map, it does have a few major drawbacks.  Many aspects of a complex robot workflow are unobservable or only partially observable.  Real robot workflows will also have many branching points to deal with exceptions or normal variation.  Most critically, its not obvious how to update or edit them over time.</p><p local-id=\"959ed317fe5e\">What makes deployment-by-demonstration so powerful is that it directly links the operator\u2019s intent to the resulting workflow.  You don\u2019t need to think about Petri nets, graphs, states or guard statements.  You can simply show the robot what you mean directly.  Fortunately, AI gives us additional means to translate user intent into robot action.  Here we will explore the idea of using AI to allow users to incrementally evolve complex workflows in a stable, predictable and interpretable/auditable way.  Operators won\u2019t need to worry about modifying complex workflow representations.  They can simply make updates in natural language by expressing the intent of their change, which can be reflect in one or both of a textual SOP document (for humans) and a structured workflow representation (for robots and other system 3 agents).</p><p local-id=\"d42c6b0fdc2e\">The naive approach to something like this is to simply take some old document, and apply the intent to get a new version of the document.  You could do this for each of the documents separately, or you could update one and then from it regenerate the other.  This does update the workflow and SOP, but it loses a lot of information in the process, reducing robustness and  predictability.  </p><p local-id=\"6cfa9dd75e73\">Instead, we will keep an intent log from the user, from which we will generate patches against our documents and workflow representation, while also re-generating snapshots.  The core agent loop here takes an older snapshot, the most recent patches and the most recent intents, and then generates a new patch.  The model may make use of tools to make this process more reliably (validating the resulting workflow via analysis for example.</p><div class=\"confluence-information-macro confluence-information-macro-information conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"info\" data-macro-id=\"aecf6f1b-0c5e-467c-85fe-56580bcbff48\" data-local-id=\"e41ba5f4a2c3\"><span class=\"aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon\"> </span><div class=\"confluence-information-macro-body\"><p local-id=\"117d11f180ab\">The Martur Fompak, Bosch and Robostore workflows were all developed through multi-turn conversations with Codex or Claude Code, providing some early signal about the viability of this overall approach.</p></div></div><h2 local-id=\"1466c6e6711a\" id=\"Studio:AgenticWorkflowUpdates-Scope\">Scope</h2><p local-id=\"69f8706b1279\"><strong>In Scope</strong></p><ul local-id=\"7ba0966a8d8a\"><li local-id=\"8d0801155478\"><p local-id=\"a90d5bda2586\">Intent log via text</p></li><li local-id=\"e5286175913e\"><p local-id=\"830af6c806d6\">Patch generation (the agentic part)</p></li><li local-id=\"4f014c413a54\"><p local-id=\"6e29b95bfbe2\">Snapshots generation from patches (deterministic)</p></li><li local-id=\"c48b870f60a7\"><p local-id=\"82a01d297f9b\">Undo</p></li><li local-id=\"fdb19229af35\"><p local-id=\"4b782407b529\">Simple debug UI or CLI (possibly built on demo monitor or sockpuppet)</p></li><li local-id=\"0c7b985ced38\"><p local-id=\"5783bff3ad25\">System 3 integrations (partially observable stuff)</p></li></ul><p local-id=\"e79de9ead48c\"><strong>Out of Scope</strong></p><ul local-id=\"ea84dcab62c7\"><li local-id=\"d41d315b5bd8\"><p local-id=\"626bda9af01e\">Multimodal intent (audio, images or video would be possible as a next step)</p></li><li local-id=\"e21ace5c4261\"><p local-id=\"06a3abcba001\">Polished Web UI (a separate spec once we validate the model here)</p></li><li local-id=\"f2360e745f7a\"><p local-id=\"f69ef7733fca\">Mapping or navigation</p></li><li local-id=\"6dd201789d08\"><p local-id=\"4837394a8b94\">Policy development</p></li></ul><h2 local-id=\"dddb63b8f9b7\" id=\"Studio:AgenticWorkflowUpdates-HighLevelDesign\">High Level Design</h2><p local-id=\"e3c49c9a21df\"><span class=\"inline-comment-marker\" data-ref=\"7fcbc559-dea9-4a67-ab45-0f623e2955dc\">The architecture here is built around a persistent intent log which can be versioned and branched.  As new intents are addeded to the log, our agent context is updated to generate the next patches, and then the patch is applied to update our snapshot.  The full history of intent, generated patches and snapshots are kept, and full traceability is established across all of these.  Meaning given the state of the workflow (the snapshot), we can see exactly which patches and thus which operator intents were used to generate it.</span></p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"706\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1715994636/Untitled%20Diagram-1772893348471.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1715994636/Untitled%20Diagram-1772893348471.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p local-id=\"281e3ca2d951\">When a patch is generated, the resulting snapshot should be validated to ensure that the workflow remains valid.  Because the workflow is built incrementally, it provides stability to the workflow over time, limiting surprises when changes are requested later when the workflow is more complex.  Asking an agent to simply modify some workflow can work (at least Codex is more than capable of doing this), but without the persistent history it becomes difficult to experiment and undo changes.  By including recent intent and patches, the agent can have some context about not just the state of the workflow but how that workflow has been evolving.</p><p local-id=\"96d4abdbf34e\">It should also be possible to converse with the agent without actually modifying the workflow (meaning we never call the \u201cnew patch\u201d tool).  To support this usage, a small conversation history is probably included in the context as well, but the agent context will need to be managed carefully to support higher-complexity workflows in the future.</p><p local-id=\"a6daa7610a96\">Initial work here should focus on the tools required to apply patches, generate snapshots and validate workflows via existing harnesses like Codex or Claude Code.  This will allow rapid iteration in a full-featured agent which can also help to identify gaps in tooling.  Once the role of the general purpose agent has been reduced to simple tool-use to manipulate our workflows, then a custom harness can be created (since deploying Claude Code or Codex into a larger system could be challenging for a number of reasons given the existing interfaces).</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20260307-175200.png\" width=\"647\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1715994636/image-20260307-175200.png?version=1&amp;modificationDate=1772905921723&amp;cacheVersion=1&amp;api=v2&amp;width=647&amp;height=385\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1715994636/image-20260307-175200.png?version=1&amp;modificationDate=1772905921723&amp;cacheVersion=1&amp;api=v2\" data-height=\"566\" data-width=\"949\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1715339453\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20260307-175200.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1715994636\" data-linked-resource-container-version=\"2\" data-media-id=\"102f2093-4c9b-430e-a885-0ab7b3515af2\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1715994636/image-20260307-175200.png?version=1&amp;modificationDate=1772905921723&amp;cacheVersion=1&amp;api=v2&amp;width=949&amp;height=566 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1715994636/image-20260307-175200.png?version=1&amp;modificationDate=1772905921723&amp;cacheVersion=1&amp;api=v2&amp;width=647&amp;height=385 1x\"></span><p local-id=\"7e203c464f85\" /><p local-id=\"2ff8f2fa2ecf\">In addition to updating the agent, some care needs to be given to how Switchboard will actually handle these updates.  The easiest thing to do is simply reset the workflow on any change.  But the smart thing would be to allow some sort of live migration.  This could be looked at as a \u201cpatch\u201d to the existing petri marking and facts within Switchboard, though this could be fragile without a ton of validation and additional tooling.</p><p local-id=\"527d36f8e221\"><strong><span class=\"inline-comment-marker\" data-ref=\"7178025c-9042-4a7a-b92b-35afab642d44\">Experience</span> With Prior Workflows</strong></p><p local-id=\"d8b3e36e4d5e\">AI-assisted workflow editing with prior PoCs allowed us to learn some tricks that help considerably:</p><ol start=\"1\" local-id=\"88b4f2e15d8a\"><li local-id=\"dd21061bd109\"><p local-id=\"6b2f762f6772\">Provide tools for inspecting the current state of the workflow (via Switchboard API calls).  This allows asking questions about why certain transitions were taken or why transitions may be blocked.</p></li><li local-id=\"6692d4b1ec63\"><p local-id=\"365896f136ad\">Provide tools for modifying the workflow arbitraryil.  In cases where you want the robot to do something slightly different, you sometimes need to \u201cundo\u201d a transition or to allow rapid exploration of the workflow without needing to reset the whole thing.</p></li><li local-id=\"9f76361c764a\"><p local-id=\"2c8a606248d3\">Provide explicit context about what you expect the robots to do, and the resulting outcomes.  Our agent here should be sure to prompt for more information and to avoid making workflow edits that are ambiguous or unclear.</p></li><li local-id=\"dd71e009d66a\"><p local-id=\"719b58b74b6a\">We should build up a suite of \u201ccanonical traces\u201d to serve as regression tests we can backtest changes against.  Otherwise we risk slight regressions.  A recent example of this was the issue with basket swap prioritization with the robostore and handling two items of the same time.  We saw that these two features are coupled in surprising ways via the guard statements and priorities of items being dispatched, resulting in a series of regressions that could have been avoided with some testing/validation against previous \u201cgood\u201d runs.</p></li></ol><p local-id=\"8a7997d03eda\"><strong>Supporting Interfaces</strong></p><p local-id=\"b09fafeb3e7c\">While out of scope for this doc, it is important that this data model support visualization and multi-modal editing.  For example, how do we render a response from a suggested patch to explain the changes to the operator?  How do we show the evolution of the workflow, the snapshots, each delta.  How do we rewind or fast-forward through history?</p><p local-id=\"32ebbef2e028\">The better these interfaces are, the better our UIs and voice interfaces will be.</p><h2 local-id=\"d4a5ef00cfbf\" id=\"Studio:AgenticWorkflowUpdates-AppendixFutureExtensions\">Appendix<br/>Future Extensions</h2><h3 local-id=\"7d9a10cc7473\" id=\"Studio:AgenticWorkflowUpdates-ConformanceChecking\">Conformance Checking</h3><p local-id=\"a94fdefb3293\">Once workflows are deployed, observed execution traces can be compared against the expected workflow model. Conformance checking identifies where observed behavior diverges from the intended process.</p><p local-id=\"683b9403d322\">Because workflow versions are tied to the operation log, conformance analysis can reference the exact workflow state that produced a given trace. Deviations can therefore be traced back to specific workflow changes.</p><h3 local-id=\"f75ef7c2433e\" id=\"Studio:AgenticWorkflowUpdates-AdaptiveWorkflows\">Adaptive Workflows</h3><p local-id=\"8a4082124f80\">In addition to transforming user intent directly into workflow patches, we could also infer the intent from any deviations in the trace logs.  As the robot executes these workflows, we can trace the robot\u2019s actions and compare them with the workflow.  If the robot is deviating often (either because system 2 decides to improvise or because of human intervention or tele-operation), workflow conformance scores will decrease.  If the score drops far enough, we could automatically trigger a process which takes the recent trace events and infers some workflow update (intent) to make the workflow more conformant.</p><p local-id=\"13f87802a343\">Think of a scenario where an operator gets an alert about workflow conformance, and potentially a handful of possible actions that could be taken to reduce non-comformance in the future (suggested changes to the SOP and workflow).  </p><h3 local-id=\"38cebfe6133a\" id=\"Studio:AgenticWorkflowUpdates-LivenessandBehavioralValidation\">Liveness and Behavioral Validation</h3><p local-id=\"47e6c16d9022\">Beyond simple syntax checks, workflows must satisfy structural and behavioral properties. These include detecting deadlocks, identifying unreachable states, enforcing resource constraints, and validating safety policies.</p><p local-id=\"2eb282f9882d\">Future validation passes can analyze workflow graphs and execution semantics to detect these conditions automatically. Validation results become attached to the operation history so that workflow evolution remains observable and auditable.</p><p local-id=\"9470f5cef28d\">Consider the scenario where a process has been carefully deployed to support 6 robots operating in parallel.  Someone could make a change to the workflow which inadvertently reduces workflow parallelism, even if the overall workflow looks correct.  These changes should be detected early, and one of the key benefits to a petri-net-based workflow representation is that analysis can be used to detect these scenarios. </p><h3 local-id=\"e5598ea8782a\" id=\"Studio:AgenticWorkflowUpdates-AuditingandOperationalProvenance\">Auditing and Operational Provenance</h3><p local-id=\"798c12fab5e6\">The operation log forms a natural audit trail of workflow evolution. Each modification records its causal origin and the artifact changes it produced. This enables operators to understand why workflows changed and what operational consequences followed.</p><p local-id=\"dbb3a39c363d\">Future tools may visualize workflow evolution as a timeline of operations and artifact projections. This allows teams to review how workflows evolved and to relate operational incidents to the workflow modifications that preceded them.  Or workflows could be visualized in purpose-built simulators or map renderings as they are editing. </p><h3 local-id=\"e3fbafae8674\" id=\"Studio:AgenticWorkflowUpdates-AdditionalArtifactTypes\">Additional Artifact Types</h3><p local-id=\"3e9c2b50c39f\">While the initial system focuses on SOP documents and workflow YAML definitions, the architecture supports additional artifact projections. These may include environment maps, simulation models or scenarios, robot configuration and more.</p><p local-id=\"9faca9b5ad22\">Each artifact type becomes another projection derived from the operation log. Special agents calls are used to interpret operations relevant to that artifact and update its representation. Over time the system can become a unified framework for managing operational knowledge relevant to the fleet across documentation, simulation, and runtime behavior.</p><p local-id=\"6dae984b2eea\" />"
        },
        {
          "id": "1485275162",
          "title": "Spec: Single-Shot Deployment MVP",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1485275162",
          "last_modified": "2026-03-06T15:38:07.467Z",
          "created_at": "2026-01-08T14:02:35.206Z",
          "body_html": "<p local-id=\"f77ec21b-e427-4eee-94fa-5be1cac47c3b\"><strong>Owner</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a></p><p local-id=\"c3dc77b9-75ab-4358-b3ca-48120f47c873\"><strong>Date</strong>: <time datetime=\"2026-01-08\" class=\"date-past\">08 Jan 2026</time></p><p local-id=\"66b5c9ed-fdf0-47a1-abab-f3b0554e039a\"><strong>Approvers</strong>:</p><p local-id=\"4a47422b-5ad2-4308-9afb-98bd83a1168e\"><strong>Informed</strong>:</p><p local-id=\"0eb072a2-2549-42e7-8e21-1634786cfc0f\"><strong>Related</strong>: <a href=\"https://miro.com/app/board/uXjVIjzyrI0=/?moveToWidget=3458764652888984570&amp;cot=14\" local-id=\"b57c7a13-0c4c-4137-9d1e-18d39b4111f6\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://miro.com/app/board/uXjVIjzyrI0=/?moveToWidget=3458764652888984570&amp;cot=14</a> , <a href=\"/wiki/spaces/ROBOT/pages/1170341889/Spec+HMND+Fleet+Control+Plane\" data-linked-resource-id=\"1170341889\" data-linked-resource-version=\"16\" data-linked-resource-type=\"page\">Spec: HMND Fleet Control Plane</a> </p><h2 local-id=\"73e29589-2e32-41ac-946d-c97f331515a7\" id=\"Spec:Single-ShotDeploymentMVP-ProblemStatement\">Problem Statement</h2><p local-id=\"a47cdbf5-8a83-4f3b-b91a-adb9ab1589e8\">Deploying a robot today is a chore.  You must:</p><ul local-id=\"d550d4a1-832e-4a12-8733-11ad25f2bf22\"><li local-id=\"ae6500d9-e4c8-4811-9e29-76a7343b6e1d\"><p local-id=\"337b9bdd-cdb8-486e-9dc6-6f2dd2691ecb\">manually map the space and tag important locations as keypoints</p></li><li local-id=\"db8e1111-1e38-4b80-b459-2772b216ae60\"><p local-id=\"ae2a8a14-86c6-4a07-9643-b23d93645d7e\">collect data (100s of examples) to train policies</p></li><li local-id=\"1804f2de-b823-4828-82dc-d5ebd3493730\"><p local-id=\"0f784fd3-c35f-43a6-b6f4-e8e48dda8b68\">hand-code behavior trees</p></li></ul><p local-id=\"74e9ea42-f2ff-426d-92ba-529ecee5e769\">This approach is painful and doesn\u2019t scale.  Its extremely difficult to adjust to changes in the environment, or to modify the behavior of the robot.  Any changes to the deployment require a new software release.</p><p local-id=\"be5b1e36-1f6f-4366-a012-90e3a0cfb34d\">Additionally, we have another integration point where customer systems like ERP or WMS need to tell our system about new work that may be arriving - so now there is another module of code that may need to be written/deployed/maintained to translate this work request into some specific sequence of actions.</p><p local-id=\"f8ec812f-84ff-40df-addc-a71ec78f0b17\">Even if we could build 100 robots a day, we\u2019d only be able to deploy 1 robot every few weeks at this rate.  This is a massive burden for our engineering, deployment and test teams and a show-stopper for any commercial ambitions.</p><h2 local-id=\"3783f5a8-fdc6-49c2-b45a-381633762193\" id=\"Spec:Single-ShotDeploymentMVP-Scope\">Scope</h2><p local-id=\"165d22ac-a57a-463a-b9c7-eb0daf300131\"><strong>In Scope:</strong></p><ul local-id=\"dc097737-60f5-4116-b678-23b4d5addc77\"><li local-id=\"f9f59874-8982-492b-9342-5f4a2d1435c6\"><p local-id=\"19c74065-4905-4282-b50b-e2c7f5e6deb9\">Inferring simple linear/looping workflows from Sockpuppet demonstrations</p><ul local-id=\"2574f54f-1fcf-4cbd-b3c7-19950e2225a0\"><li local-id=\"e9218d1a-eb86-4055-be7f-095cbee208ec\"><p local-id=\"40b54335-7380-4854-b5b6-6835cb8826bd\">Navigation</p></li><li local-id=\"9622e7f1-c4e5-4e2f-85f0-e8fe3866d9fd\"><p local-id=\"9004dad8-e952-43bb-b906-18e86d718c07\">Policy Execution</p></li><li local-id=\"958bb7f5-dccf-410b-a82f-f099deca8423\"><p local-id=\"579f8df6-0331-4a42-80ce-b93d8f893d91\">Posing/Recovery</p></li></ul></li><li local-id=\"73112bf3-d92a-472d-b8a6-21372367c41f\"><p local-id=\"80362e59-3003-4b02-a742-fe788fc00a3b\">Executing these workflows on any robot without a software release</p><ul local-id=\"0202fc1b-0e1c-4a8b-9b40-dd206f00552b\"><li local-id=\"9fb2bb4a-8090-44b3-b631-4f9f57bd781c\"><p local-id=\"998ccac1-37d5-4976-82ed-50f057b2d9ec\">Fetching map</p></li><li local-id=\"400f81f1-e26f-4b75-88da-e835c8044284\"><p local-id=\"bcc97b65-03d9-4b2f-9353-1341906250c4\">Hard-coded URLs for fleet endpoints</p></li></ul></li></ul><p local-id=\"da90082b-3b27-4a82-9407-bfecd9ad0367\"><strong>Out of Scope</strong></p><ul local-id=\"f7a4b204-859f-4ddf-a01d-a3f1060d363c\"><li local-id=\"913f2f34-beb6-4598-9a17-cfb416a84aae\"><p local-id=\"c6afbc46-4f47-4dd2-ac00-6ce1d8b66fdf\">Any 3D mapping</p></li><li local-id=\"f8ed3709-75b9-4bfb-a097-e81cf28ec1b4\"><p local-id=\"41bc119c-5a53-4f1c-813a-1583715f72cc\">Semantics</p></li><li local-id=\"07000e40-0e62-43a7-96e2-eee756a40677\"><p local-id=\"e4dc7a73-2f5e-4b96-be46-30c3fd30ffba\">Branching/Conditions</p></li><li local-id=\"fc25db6d-e415-4912-b81e-6aad2238daf5\"><p local-id=\"5aa0d201-f6e5-4be3-94b0-bc56a06dce08\">Updates from teleop</p></li><li local-id=\"2b4c65f0-af98-4245-888e-0fe913a9cc0a\"><p local-id=\"ef0a2ca8-2056-4198-b1b1-5fe9e02ecae7\">Multi-robot coordination (capacity/choke points/etc)</p></li></ul><h2 local-id=\"13a64ed4-ed97-4226-a865-782dff6b8754\" id=\"Spec:Single-ShotDeploymentMVP-DesignOverview\">Design Overview</h2><p local-id=\"be3064db-9570-4107-b691-05595b2e79b1\">Currently, we have Sockpuppet working for data collection and tele-operation, simple hard-coded behavior tree-based applications executing our workflows and not much else.  Coming online shortly we have some simple workflow coordination in the cloud and a new workflow execution app.</p><p local-id=\"18541aa0-5354-4899-938d-a4fc5b15fb54\">In the future, being able to physically push the robot around to demonstrate the workflow would be even better, as it would require less setup friction (and you can probably push a robot physically safer than you could teleoperate).</p><p local-id=\"e84fe1f7-c446-40bc-bdf7-6137acf13577\">We can likely repurpose Sockpuppet to serve as a means to demonstrate workflows, in which case we are mostly missing the \u201cStudio\u201d component here, responsible for taking log data from Sockpuppet or Reverb and generating workflows which can be executed autonomously.</p><p local-id=\"a84120d9-9d6d-48f3-9593-fa554af89549\" /><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"693\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1485275162/Untitled%20Diagram-1767883738137.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1485275162/Untitled%20Diagram-1767883738137.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p local-id=\"54b9ab01-ffca-409b-b98e-c441ee8b7bbc\">There are two pieces necessary for this right now:</p><ul local-id=\"5a4a5429-7920-4e1c-aa7d-e70dfbdac022\"><li local-id=\"05f8099e-926a-4a20-aa0e-9b3362dba0cf\"><p local-id=\"62e6ddd5-2cb2-4dba-a4f2-0deddd61709f\">Generating our map</p></li><li local-id=\"6aa4f7d9-84fb-4297-bd57-f1e1e0b4d590\"><p local-id=\"87b4cdc8-c986-44d5-ba75-d74022db83ab\">Inferring the workflow YAML</p></li></ul><p local-id=\"6bc07610-d50a-4023-9039-366b1c5e303f\">In the future, this process could be much more involved, including iterating on the workflow within simulation or leveraging sophisticated agentic setup processes which can semantically break down the workflow to better capture user intent.  This MVP is not that.</p><p local-id=\"4dcd3d11-21d2-4028-9e39-9affab01ffc8\"><strong>Simple Workflow</strong></p><p local-id=\"19b73de8-e391-41f2-9db5-db992bc1ec84\">Let\u2019s consider a simple tote-moving workflow where:</p><ul local-id=\"fa6422b6-b46e-4d7b-93f0-cd2f346feb24\"><li local-id=\"e607eefe-bab7-4e8d-bca2-1357b3a6f448\"><p local-id=\"1d666838-52e0-4a02-80f1-5654a0cc9dbc\">robot starts in some origin position</p></li><li local-id=\"bed51422-c15a-4b8e-88f0-a18b8b3ef776\"><p local-id=\"006a4064-e3f4-4fcd-bc01-ba0b6c2d04b1\">navigates to a table A</p></li><li local-id=\"077f4f98-2abc-499b-adbf-f217ae5ce10a\"><p local-id=\"8e79152c-766a-452e-9862-e489a81b0c10\">picks up a tote</p></li><li local-id=\"55ec8771-08af-4133-a39f-d9ec564a17f8\"><p local-id=\"5538ba1d-a34c-4399-8453-a5ebd6288bfe\">navigates to table B</p></li><li local-id=\"9b0c4ff2-c0a8-4c59-8667-ffbc2e9c96a1\"><p local-id=\"56d9c135-6ea4-4897-9041-2cb88e70e041\">puts down tote</p></li><li local-id=\"3c0b58e0-8ada-4882-86d2-285249a22735\"><p local-id=\"0991a790-af6c-4704-b54c-84bb44d5e04d\">returns to origin position</p></li></ul><p local-id=\"31429ac3-4f2f-4ce2-8b7e-1a7b59ec8d6f\">As mentioned earlier, the current means of deploying even this trivial workflow is pretty involved.  We need to map the space.  We need, while mapping, label explicitly these \u201ctags\u201d for the points of interest, we then need to remember these tag names and code up a behavior tree, and then we can maybe attempt to run the behavior tree autonomously and see the robot execute the workflow.  This can take days.</p><p local-id=\"a581d3c9-be9c-43a8-859c-cea67268d6b8\"><strong>Demonstration</strong></p><p local-id=\"e5f9f70f-c98c-4a59-9053-739cefdb7043\">So we will power on the robot and boot into Sockpuppet.  We can then navigate to the origin position and enable our \u201cdeployment mode\u201d.  Note that the user never needs to tag the location - its done implicitly here.  The user then teleoperates the robot to table A, and then uses the Sockpuppet policy tab to run \u201cpick up tote\u201d.  The robot will execute this policy, or if there is an issue (perhaps due to insufficient data collection), the operator can teleoperate the robot to pick the tote up and move things along.  Similar to the origin, we automatically save the point where we run the policy as a tag - the user doesn\u2019t need to do this.  Then we navigate to the other table, and run the \u201cplace tote\u201d policy.  Then we navigate back to the origin and we \u201csave\u201d the workflow, closing the loop.</p><p local-id=\"ccb2487f-c6f9-46b4-8a76-b6b7b2520469\"><strong>Logging</strong></p><p local-id=\"41757de9-e351-4dc4-82e2-508eacc2f103\">During the demonstration above, we need to log some data.  To support mapping, we need to collect the lidar and odometry data necessary to generate a map offline.  Sockpuppet can emit trace logs of the various tools being used (navigating, running policy, setting a pose), which can then be aligned with our odometry (by time) and placed into the generated map.  These trace logs effectively become our points of interest - freeing our operator from the burden of naming these points themselves.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"971\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1485275162/Untitled%20Diagram-1767900808095.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1485275162/Untitled%20Diagram-1767900808095.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p local-id=\"67363ee6-237b-460c-b6aa-ac74b36a70d6\"><strong>Inference</strong></p><p local-id=\"aba8f9d0-2ef4-4046-babe-2ed59a61405a\"><span class=\"inline-comment-marker\" data-ref=\"68c0a2e4-838b-4447-8336-16b89687aa9c\">Now the fun - we need to take our lidar + odometry data and generate a map offline, and then we need to locate our Sockpuppet logs on this map to generate keypoints.  Then we can run some very simple \u201cprocess mining\u201d to infer a petri-net from the logs.  This is a relatively standard procedure in the world of data science, though it is old-fashioned and a bit crusty.  In the future, this inference step is likely to be done by an LLM directly - but we can start with something much simpler for now.</span></p><p local-id=\"29536016-d029-460a-9e46-ece4c53c9e63\">The resulting workflow.yaml, occupancy grid map and mapping metadata (our inferred keypoints) can all be bundled up and saved to S3 as a workflow package.  </p><p local-id=\"0cc355d4-86cc-42b6-a6f6-0b9aa4d6aad4\"><strong>Execution</strong></p><p local-id=\"9f4228ff-b038-4a7a-b302-66a5b16fcbf7\">Our coordinator can be loaded with a selected workflow package, and serve task assignments and map data to the robots.  The robot\u2019s execution agent (reverb) can then progress through the workflow autonomously, moving from point to point and executing policies as specified.</p><p local-id=\"5e2ec865-7d67-4f9c-ba8a-bdede2a53726\">Like with Sockpuppet, these logs are also kept and, in cases where operator intervention is needed, capture deviations or alternatives in the workflow.  Given enough of these examples, we can potentially re-infer more complex workflows, this this \u201cupdate\u201d is out of scope for this MVP.  The primary purpose of these logs will be for checking Workflow conformance (how well are we following the workflow).</p><h2 local-id=\"815cd793-9101-4b94-aceb-186b40ce64ce\" id=\"Spec:Single-ShotDeploymentMVP-Milestones\">Milestones</h2><ol start=\"1\" local-id=\"092cdb28-d67c-43aa-b122-b90247584cc6\"><li local-id=\"b0184b12-3515-4086-9385-6d04979f455e\"><p local-id=\"696ce677-1afe-4465-a2f7-25e89b431ae3\">SAP/MF PoC (done)</p><ol start=\"1\" local-id=\"dd8eb48b-31ac-4c1a-ba7d-b0e11f1fd5ac\"><li local-id=\"484d6cbc-38e0-44a5-982a-aee8e8de6d66\"><p local-id=\"7a0b10c9-c2d1-469a-b945-6021302d9c6d\"><strong>Coordinator:</strong> hard-coded workflow</p></li><li local-id=\"ab85ffa8-81b4-4732-b76a-4e00b1e53d08\"><p local-id=\"9f50c5c4-41fb-4cef-bf4f-55dd60c6e751\"><strong>Execution</strong>: fixed or agentic workflow \u201capp\u201d on robot</p></li></ol></li><li local-id=\"d0ddbfc4-5287-464a-a406-b927653aeaec\"><p local-id=\"61d1a024-b252-47ec-b890-289336b19ed1\">Offline mapping via Sockpuppet and Studio (tested in sim)</p><ul local-id=\"2d64942b-793a-4b69-9eb0-3bf47c89496e\"><li local-id=\"5835df59-6ead-4de1-af9c-588b8f005338\"><p local-id=\"514def53-cdb5-45a8-a132-ab60728e924f\"><strong>Deployment Mode: </strong>Record mapping data (lidars, odom) to mcap while tele-operating</p></li><li local-id=\"a84c9d0c-1362-4a6d-a212-2abe46adb68f\"><p local-id=\"862f42c4-5f34-49dd-a717-30a92cce00f0\"><strong>Offline Mapping:  </strong>Generate occupancy grid with origin tag and store in Studio</p></li></ul></li><li local-id=\"89727e3e-685f-4bd6-9152-f9ad06938f95\"><p local-id=\"76afa0aa-8682-4e49-a296-41cc43b5208a\">Workflow inference (tested in sim)</p><ol start=\"1\" local-id=\"bd5f4898-7761-45b9-8d9a-dcff1372f741\"><li local-id=\"8c72f408-e590-483a-875b-da411e9fbc7c\"><p local-id=\"522060f0-689a-4836-9b04-927de8b0d047\"><strong>Sockpuppet Logs: </strong>Record logs from sockpuppet for various actions taken during deployment mode</p></li><li local-id=\"59e1d326-b66d-49aa-9d58-34f7261ec592\"><p local-id=\"b70f9fac-c607-4313-9c8e-a5afc4505f43\"><strong>Alignment</strong>: Use timestamps/odometry to place logs on the map for inferred keypoints</p></li><li local-id=\"3204f55f-aefe-445a-9e0d-489a247a6287\"><p local-id=\"3419fb4c-2943-4cd6-b494-aef539d792e3\"><strong>Workflow Package</strong>: Infer a workflow.yaml, combine with map data and metadata as a workflow package</p></li></ol></li><li local-id=\"3032e0aa-7e83-4624-915a-db1af0d33636\"><p local-id=\"84a8f48d-ffca-4fd1-9ee6-e1e89c23ef49\">Workflow execution (mostly tested in sim)</p><ol start=\"1\" local-id=\"583106dd-7ff5-4d83-a341-e69f0dc3f98d\"><li local-id=\"246a0a38-d04a-4a9e-a65c-54687a438540\"><p local-id=\"de625928-bd9f-4cac-a3cd-a0fa6dc9182d\"><strong>Workflow Selection</strong>: Choose which workflow package should be used by which robots, and download package (map/metadata specifically) to the robot.</p></li><li local-id=\"7d398a9e-39b1-40e5-a709-f128fbec48b7\"><p local-id=\"661bd898-1858-4708-b281-d8e1a91dab1c\"><strong>Reverb Logs</strong>: Similar to Sockpuppet - should be same infrastructure, just tagged differently </p></li><li local-id=\"238d4bde-34fa-4540-add4-cc6fbcf93a19\"><p local-id=\"3453f810-0f74-4ab3-aee4-d827609925c9\"><strong>Conformance</strong>: Check how closely workflow is being followed </p></li></ol></li></ol><h2 local-id=\"f48ffaea-85c4-44e4-8469-44dd1aeab934\" id=\"Spec:Single-ShotDeploymentMVP-SOPs\">SOPs</h2><ol start=\"1\" local-id=\"353ae352-6430-47dd-9ef7-756e89d42cde\"><li local-id=\"fcded825-77c7-4702-842d-f47b0c11eb1c\"><p local-id=\"98beb565-901f-4c8b-86f0-0a67cd225bd5\"><strong>Deployment</strong></p><ol start=\"1\" local-id=\"c28a3fdd-0b4e-4823-9c43-801b1ca76a5b\"><li local-id=\"1d1a5b79-8361-41e0-9cac-7556e920ce94\"><p local-id=\"d59396bd-1ac4-470c-842e-e2c9608a9db4\">Start up sockpuppet</p></li><li local-id=\"25ec496a-bfb9-466e-b81f-08ed4ca414f3\"><p local-id=\"e5869f9b-93d5-46dc-bde5-f4ac3dcb58b2\">Toggle \u201cdeployment mode\u201d to enable extra logging</p></li><li local-id=\"3f60e8df-75aa-43b5-b6a7-7fa9f72ae704\"><p local-id=\"52d042d6-f0ba-4994-a60f-a190ffc36196\">Perform the workflow via teleoperation</p></li><li local-id=\"2040fb3f-1b7f-4be5-b50c-f9d793fe6c20\"><p local-id=\"f280825d-9d38-433c-aa06-b098d5c1cfa5\">Save it.</p></li></ol></li><li local-id=\"00b96be4-4fdc-4935-8451-e2ba2bf75fcf\"><p local-id=\"c6b57a2a-a996-4b65-8ce1-2056c94cdd7f\"><strong>Execution</strong></p><ol start=\"1\" local-id=\"cfbc7efb-7e48-4506-acb6-fe1c8a4ccd21\"><li local-id=\"aaf1defc-7836-4b34-9c2b-31e1d55205a5\"><p local-id=\"50699c65-3703-4d04-bfc1-4de322031a2c\">Select workflow package ID when we start the fleet coordinator (Switchboard)</p></li><li local-id=\"ce2c641d-e190-4ca7-a34e-b005914cf68f\"><p local-id=\"4de1b7d5-0e41-4f9d-8af9-85c7bc552e34\">Point reverb at Switchboard to begin autonomous execution</p></li></ol></li></ol><h2 local-id=\"061261d3-1ae4-4a2d-8e0e-7ff4e9a62c29\" id=\"Spec:Single-ShotDeploymentMVP-NextSteps\">Next Steps</h2><p local-id=\"1e6d2ed5-6ed3-406e-88fa-38fc4ac27352\"><strong>Incremental Updates</strong></p><p local-id=\"e72fc2fe-c937-4f77-96c0-41dde2de8822\">The procedure here is great for the simplest workflows and can reliably handle simple linear sequences or \u201cloops\u201d of tasks.  But to scale to more complex workflows, we need to be able to adjust things incrementally.  There are two possibilities here we will likely be exploring later if this initial MVP works as-intended.</p><p local-id=\"62be0be4-0d1b-4494-a8e1-d33a5fede17a\">First, we can use additional data collected via teleoperation to allow the workflow to grow more complex over time.  This would be enough to get us some simple branching logic perhaps.  Second, we can use an editor within \u201cStudio\u201d to get more sophisticated editing capabilities, along with allowing Sockpuppet to incrementally edit the workflow sequence.</p><p local-id=\"9dc357b5-5ec8-4b3a-9fe4-8b1edefc9e4d\"><strong>Multiple Robots</strong></p><p local-id=\"e338d6ca-0cd4-4b08-9ac7-e298ef9a1c4a\">The coordinator should handle this, but I expect we may need to make further adjustments here (detecting other robots, handling congestion locally via policy).</p><p local-id=\"1fda16a2-43d8-4a2f-8aaa-fcd54bbb078c\"><strong>Agentic Dispatch</strong></p><p local-id=\"64dcc15c-3447-40cf-9ca3-007c5443d766\"><span class=\"inline-comment-marker\" data-ref=\"ce754885-8a3a-4c19-b9a3-1df9db7b820f\">Writing code to translate some incoming webhook or outgoing events to integrate with some 3rd party is also going to be an integration headache.  In a perfect world, we have enough weight in the market to set standards and we just force them to integrate.  We need to grow to get that weight though, and until then this is a major drag.</span></p><p local-id=\"6d66370e-92f3-4997-87b7-c9c8bb469a3a\">One idea here is to just use AI.  We could have a prompt defined for a particular integration (\u201cYou\u2019ll receive a webhook looking like X, make sure to peel out fields A, B and C, and make sure to blah blah\u201d).  Even with the rapid improvements in instruction following, its unlikely that this will be reliable enough - so after an initial deployment with this, we can collect enough data for the AI to effectively write a plugin - almost like a JIT.  </p><h1 local-id=\"1ded09fb-bda6-4639-b923-2c2cbe7101f2\" id=\"Spec:Single-ShotDeploymentMVP-Appendix\">Appendix </h1><p local-id=\"10c252a0-6bb5-44d3-b75f-87133447a30f\" />"
        },
        {
          "id": "1713373231",
          "title": "Robot Posing and Deployment",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1713373231",
          "last_modified": "2026-03-06T15:36:14.788Z",
          "created_at": "2026-03-06T15:21:51.624Z",
          "body_html": "<h2 local-id=\"8cffec858e4e\" id=\"RobotPosingandDeployment-ProblemStatement\">Problem Statement</h2><p local-id=\"883e106de67b\">The \u201cpose \u2192 run policy \u2192 reset \u2192 run next policy\u201d has been useful to de-risk data collection, policy development and our ongoing PoCs, but its starting to become a liability.</p><p local-id=\"c685d5c57479\">Right now each policy assumes a carefully staged starting configuration: <em>robostore_table</em>, <em>robostore_shelf</em>, and so on. Humans reset the robot to those configurations so the policy doesn\u2019t have to deal with the messy reality of arbitrary state. That simplifies training and debugging in the short term, there are some unfortunate downsides.</p><p local-id=\"41fd13fe89e8\">Every reset is a discontinuity in motion. The robot freezes, shifts into some canonical pose, then resumes policy or navigation. From a demo perspective it looks clumsy and stilted. From a systems perspective it is even worse: it encodes hidden operational knowledge into the deployment process. Someone has to know which pose corresponds to which policy and when to apply it.  If they are wrong, the policy will fail or the robot may collide with the environment.</p><p local-id=\"f34025068ddf\">The robot only works because an engineer with intimate familiarity with the system scripted the right motion sequences.  A scalable robotics product cannot rely on this process.</p><h2 local-id=\"cdcfd682e137\" id=\"RobotPosingandDeployment-ProposedSolution\">Proposed Solution</h2><div class=\"confluence-information-macro confluence-information-macro-note conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"note\" data-macro-id=\"7520e864-92b0-407e-aa48-59289b95bfd0\" data-local-id=\"66a8c7b163e0\"><span class=\"aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon\"> </span><div class=\"confluence-information-macro-body\"><p local-id=\"ff13667adebe\">I am not the AI guy.  This needs to be digested by the AI team as I suspect there are many intricacies here that are not being purposefully trivialized.</p></div></div><p local-id=\"e40cd03ab16d\">A more robust approach is to make policies responsible for their own approach. Instead of assuming a perfect starting pose, the policy learns how to move from the current configuration into a configuration where the policy can succeed (ideally while avoiding obstacles).</p><p local-id=\"def6e7baf081\">This \u201csmall\u201d (lol) tweak has major benefits:</p><p local-id=\"dd54a2839a7d\">First, motion becomes continuous. The robot flows from one behavior to the next instead of halting for resets. The result is smoother, more natural movement and dramatically better demonstrations of capability.</p><p local-id=\"34a1f5edc230\">Second, deployment becomes simpler. Instead of a fragile sequence of manually curated poses, the operator triggers a task and the robot figures out how to get into position. The system carries its own assumptions rather than requiring humans to remember them.</p><p local-id=\"0e8ed35ae64b\">Third, and most important, policies begin to generalize. When a policy can only operate from a narrow starting configuration, its effective operating envelope is tiny. The moment reality deviates (a slightly different arm position, a small disturbance, a prior task ending differently) the policy fails. Teaching policies to navigate into workable states expands that envelope. Over time the robot becomes tolerant of variation rather than allergic to it.</p><p local-id=\"ea825930b9ca\">How does this compound?</p><p local-id=\"78ec6feb6b09\">We trade time spent toiling away in deployment, orchestrating poses and sequencing actions carefully for time spent in data collection.  I think this is the correct trade - since we can re-use the trained policy over and over.  Put another way, policy scales better than deployment.  There are scaling laws for polices - get better at many tasks to get better at any task.  There is no such scaling law for deployments.</p><p local-id=\"9b2b58efdebd\">Given the compounding nature of this work, the earlier we start making progress, the earlier we can start taking back time and re-investing into the product.</p>"
        },
        {
          "id": "1711571015",
          "title": "Spec: Dev vs Release Images",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1711571015",
          "last_modified": "2026-03-06T11:35:32.675Z",
          "created_at": "2026-03-06T11:05:57.515Z",
          "body_html": "<p local-id=\"28acf3d2823e\"><strong>Owner</strong>: </p><p local-id=\"218287146c3b\"><strong>Date</strong>: <time datetime=\"2026-03-06\" class=\"date-past\">06 Mar 2026</time></p><p local-id=\"71b5467868aa\"><strong>Approvers</strong>:</p><p local-id=\"77f292f62568\"><strong>Informed</strong>:</p><p local-id=\"b50ec829cbf8\"><strong>Related</strong>: Other OS-image-related docs?</p><h2 local-id=\"e2128116aab5\" id=\"Spec:DevvsReleaseImages-ProblemStatement\">Problem Statement</h2><p local-id=\"af90a07f0c70\">We need one robot OS artifact that can behave like two different machines:</p><p local-id=\"b02105a720b5\"><strong>Release mode</strong> is for demos and data collection. It must be deterministic and self-healing. Any accidental system drift should evaporate on reboot.</p><p local-id=\"b81afe79a502\"><strong>Development mode</strong> is for engineering. Drift is allowed, expected, and persistent. Engineers need a live repo, mutable deps, and a controlled on-device workflow.</p><p local-id=\"f0c5dc3e6f74\"><span class=\"inline-comment-marker\" data-ref=\"ba7fd10e-7045-4b70-9334-5ac663d865c1\">We will ship a single immutable base image. Mode is chosen at boot via a bootloader \u201cdirty bit.\u201d Converting </span><strong>release \u2192 dev</strong> is allowed. Converting <strong>dev \u2192 release</strong> is not allowed except via destructive reset that wipes dev state.</p><p local-id=\"6adcb8c771d5\">The key invariant is blunt:</p><p local-id=\"a6422fa55047\">A robot in release mode cannot retain root filesystem drift across reboot.</p><h2 local-id=\"e375208cbf45\" id=\"Spec:DevvsReleaseImages-Terminology\"><span class=\"inline-comment-marker\" data-ref=\"cbb4de1c-67e5-4b84-9b3d-006cccb50ad3\">Terminology</span></h2><h3 local-id=\"288115d34065\" id=\"Spec:DevvsReleaseImages-Modes\">Modes</h3><p local-id=\"c443328aeed4\"><code>CLEAN</code> means release mode.<br/><code>DIRTY</code> means development mode.</p><h3 local-id=\"45beaeea3090\" id=\"Spec:DevvsReleaseImages-Serviceprofiles\">Service profiles</h3><p local-id=\"a879f0fc1462\">Release services are the system-installed stack, launched by systemd units shipped with the image.</p><p local-id=\"eb6c0e54829e\">Dev services are repo-backed services, launched by systemd units that point into <code>/data/dev/repo/...</code>.</p><h2 local-id=\"a8910ab07b28\" id=\"Spec:DevvsReleaseImages-FilesystemLayout\">Filesystem Layout</h2><h3 local-id=\"d706cd2487f9\" id=\"Spec:DevvsReleaseImages-Standardpaths\">Standard paths</h3><p local-id=\"a96cac001a29\">We standardize all robot-owned configuration and state under consistent prefixes:</p><ul local-id=\"c0c6793d-a678-4352-a606-f960b1404301\"><li local-id=\"de3a6db8-9a52-4ae6-88d6-3ddb7f499e8b\"><p local-id=\"e336be6ee728\"><code>/etc/hmnd/</code> \u2014 configuration (shipped + runtime config overlays)</p></li><li local-id=\"8b8c46d4-925e-4bd7-9a75-347f96b2446e\"><p local-id=\"566aba6845ae\"><code>/var/lib/hmnd/</code> \u2014 persistent state (identity, provisioning state, databases, caches that must survive reboot)</p></li><li local-id=\"9f8cf9ff-11b0-4f94-86da-ce9b3f8d5b70\"><p local-id=\"6c11cc669c85\"><code>/var/log/hmnd/</code> \u2014 logs (persistent in both modes)</p></li><li local-id=\"d135460d-0017-41f9-b87d-d6dc82c7337d\"><p local-id=\"c00c24fb3557\"><code>/run/hmnd/</code> \u2014 runtime scratch (tmpfs)</p></li><li local-id=\"26cc9c28-6e07-4ebc-80e1-84128005860d\"><p local-id=\"7ceafd739f2a\"><code>/opt/hmnd/</code> \u2014 installed release binaries/assets (if not in <code>/usr</code>)</p></li><li local-id=\"3cf7d0fc-76d6-4e4e-880d-7a80c21e6c2b\"><p local-id=\"9e95c3a648e3\"><code>/data/</code> \u2014 persistent data volume (partition). Contains dev state when DIRTY.</p></li></ul><p local-id=\"e17cc9bd2293\">This avoids the \u201crandom junk in /etc and /var\u201d entropy spiral.</p><h3 local-id=\"4bf4ecb20f85\" id=\"Spec:DevvsReleaseImages-Persistentmounts(bothmodes)\">Persistent mounts (both modes)</h3><p local-id=\"831b8ec4f9a2\">These are required in both modes and must survive reboot:</p><ul local-id=\"67799725-44d2-484b-9827-9c71d7eab3a1\"><li local-id=\"f67bb70d-2e4d-4118-adf7-568b67e6cb62\"><p local-id=\"bb0e1f2e7c7f\"><code>/var/lib/hmnd/</code> (identity, provisioning, small DBs)</p></li><li local-id=\"469fc664-04a6-41c5-9d9b-a0ab6b5a69c3\"><p local-id=\"0c1d7c298648\"><code>/var/log/hmnd/</code> (logs)</p></li><li local-id=\"48ab4e34-fc19-477d-a917-8d0c999d6893\"><p local-id=\"bfdd46576134\"><code>/etc/hmnd/certs/</code> (cert bundle and device keys; or a symlink into <code>/var/lib/hmnd/certs</code>\u2014pick one and stick to it)</p></li><li local-id=\"f1d941db-6085-44e8-833b-b13e889a7b6d\"><p local-id=\"63085e39b6fd\"><code>/data/</code> (always mounted; used heavily in DIRTY)</p></li></ul><p local-id=\"1cdaa7aba25f\">Release mode is stateless for <em>root drift</em>, not for identity/logs.</p><h3 local-id=\"cc324eee3537\" id=\"Spec:DevvsReleaseImages-Developmentstorage(DIRTYonly)\">Development storage (DIRTY only)</h3><p local-id=\"4d592d339657\">Development state lives under:</p><ul local-id=\"a2048ab4-48fa-4b89-8b01-fa6fafa5d354\"><li local-id=\"98a5cb39-de67-4be2-9a71-2ac378bbd055\"><p local-id=\"56e34b23b933\"><code>/data/dev/upper</code> \u2014 overlayfs upperdir</p></li><li local-id=\"3f76fa03-6b02-4372-b5d5-23dfdf4797ad\"><p local-id=\"c4527e0d5d4d\"><code>/data/dev/work</code> \u2014 overlayfs workdir</p></li><li local-id=\"ee074816-1ec1-4eca-9a32-ed805077b499\"><p local-id=\"96df4c56f078\"><code>/data/dev/repo/&lt;project&gt;</code> \u2014 git checkout</p></li><li local-id=\"d819855a-9318-4995-8c1b-fd70a98d125f\"><p local-id=\"c7eecb2fb445\"><code>/data/dev/build/</code> \u2014 build outputs (if needed)</p></li><li local-id=\"da170dd2-2c3e-43f2-9bfc-d7f4b8ebf067\"><p local-id=\"3584585c4744\"><code>/data/dev/state/</code> \u2014 stamps (last built rev, last good rev, dependency stamp)</p></li></ul><hr local-id=\"c5b659cc-dc5e-455b-84dd-ae2dc48b893a\"/><h2 local-id=\"065581594c43\" id=\"Spec:DevvsReleaseImages-RootFilesystemandOverlay\">Root Filesystem and Overlay</h2><h3 local-id=\"1a55c8c2d5fa\" id=\"Spec:DevvsReleaseImages-4Baseroot\">4Base root</h3><p local-id=\"b7eca0ffd119\">The root filesystem is an immutable image (e.g., SquashFS) mounted read-only and layered with overlayfs.</p><h3 local-id=\"ed40f6ee0c9c\" id=\"Spec:DevvsReleaseImages-Overlaypolicy\">Overlay policy</h3><p local-id=\"ba1cbe641d9f\"><strong>CLEAN (release mode)</strong><br/>The overlay upperdir is tmpfs. Root drift cannot persist.</p><ul local-id=\"cf6f3bed-d56e-4e21-8fa2-6f9943764c96\"><li local-id=\"3d45f18e-f237-414b-a1be-a306d08323fa\"><p local-id=\"cba93caee087\">upperdir: <code>/run/hmnd/overlay/upper</code> (tmpfs)</p></li><li local-id=\"5a6f2aab-9548-4c8a-b615-a6278f3aa6bb\"><p local-id=\"e91a52399945\">workdir: <code>/run/hmnd/overlay/work</code> (tmpfs)</p></li></ul><p local-id=\"bd6d22574da5\"><strong>DIRTY (development mode)</strong><br/>The overlay upperdir is persistent disk at <code>/data/dev</code>.</p><ul local-id=\"117b09c9-ba2e-47c3-b9b5-176b2b04eaf7\"><li local-id=\"2c2bfaac-fd04-4933-8e4c-7df570f5bf88\"><p local-id=\"dbb58397fe1a\">upperdir: <code>/data/dev/upper</code></p></li><li local-id=\"997c6cc0-ff68-4155-9fb9-f5e3db206be3\"><p local-id=\"1425ee5df1f9\">workdir: <code>/data/dev/work</code></p></li></ul><h3 local-id=\"29eadb832aab\" id=\"Spec:DevvsReleaseImages-Whythismatters\">Why this matters</h3><ul local-id=\"38763178-c9ef-4636-8930-f41dc38f87dc\"><li local-id=\"4156c11e-1986-43bf-b1c9-2076e71b59ca\"><p local-id=\"4ee8912e7040\">In CLEAN: <code>apt install</code> might \u201cwork\u201d temporarily, but it dies on reboot. Good. That\u2019s the point.</p></li><li local-id=\"bb7ee2bd-0a44-4268-893a-d885c8595519\"><p local-id=\"5e8d37ccbfd5\">In DIRTY: any mutation persists, and the box is explicitly non-release.</p></li></ul><hr local-id=\"00ad1183-c759-4f20-b2d9-21577d229c1b\"/><h2 local-id=\"956fa5242035\" id=\"Spec:DevvsReleaseImages-DirtyBitSemantics\">Dirty Bit Semantics</h2><p local-id=\"1a6f614f5d21\">A bootloader-controlled flag determines mode at boot.</p><ul local-id=\"5cf5836e-599b-4936-ad4b-b79f82221d9e\"><li local-id=\"5ab89129-0669-43fb-acc9-179c1ef3113d\"><p local-id=\"d095c639008e\"><code>CLEAN</code> boots release overlay and release services.</p></li><li local-id=\"3b335722-3ecd-4a78-b2aa-9bd6e49f3f05\"><p local-id=\"c1406208970c\"><code>DIRTY</code> boots dev overlay and allows dev services.</p></li></ul><p local-id=\"ca8c760ec67d\">Export mode to userspace early (initramfs) as:</p><ul local-id=\"781ca1c7-9d03-44e8-86ff-e939fc5031b8\"><li local-id=\"b41ddc90-e252-4396-a342-5c315826f43a\"><p local-id=\"85cc6e9328bb\"><code>/run/hmnd/mode</code> containing <code>CLEAN</code> or <code>DIRTY</code></p></li></ul><p local-id=\"0d90b6167d0a\">Mode must be reported to the control plane in device heartbeat.</p><h3 local-id=\"f265b5b23a21\" id=\"Spec:DevvsReleaseImages-One-wayrule\">One-way rule</h3><p local-id=\"88b6967b24b2\">Clearing DIRTY (returning to CLEAN) is only permitted if dev state is wiped. That means <code>/data/dev</code> is erased successfully.</p><p local-id=\"6a70ad9eb526\">No exceptions. No \u201cbut I uninstalled the packages.\u201d</p><hr local-id=\"622f4a0f-3015-43f0-8e76-89ea61972f1b\"/><h2 local-id=\"c88221f06c88\" id=\"Spec:DevvsReleaseImages-systemdServiceModel\">systemd Service Model</h2><h3 local-id=\"57de6df7323c\" id=\"Spec:DevvsReleaseImages-Targets\">Targets</h3><p local-id=\"2a57b0f0c5d2\">Define two top-level targets:</p><ul local-id=\"de3b9638-372b-42e9-8267-e8b10ab94cf1\"><li local-id=\"eb5e1236-8877-40e5-bf9a-dabafce341aa\"><p local-id=\"465ce70b71da\"><code>hmnd-release.target</code> \u2014 pulls in release services</p></li><li local-id=\"d5b45fed-156b-468d-814d-9fc02e95e796\"><p local-id=\"5b4c7a4f91ba\"><code>hmnd-dev.target</code> \u2014 pulls in dev services</p></li></ul><p local-id=\"14af09340a39\">CLEAN boots into <code>hmnd-release.target</code>.<br/>DIRTY may run either, but dev switching is explicit (see below).</p><h3 local-id=\"ad317ee6d97b\" id=\"Spec:DevvsReleaseImages-Unitnamingconventions\">Unit naming conventions</h3><p local-id=\"b3414099a9f0\">Release units:</p><ul local-id=\"36a11a16-99cf-4e67-ba62-e1f85cf6808b\"><li local-id=\"7ab061a4-f982-4683-a65a-6fcf01b164d9\"><p local-id=\"59b8aa4d00e3\"><code>hmnd-&lt;svc&gt;.service</code></p></li></ul><p local-id=\"cac3112f7004\">Dev units:</p><ul local-id=\"32520eb1-9060-48bd-963b-c2bc172b88b5\"><li local-id=\"378a615f-5737-4a42-a304-772900ee2ef2\"><p local-id=\"4b84b25f523e\"><code>hmnd-&lt;svc&gt;-dev.service</code></p></li></ul><p local-id=\"3549e36d7f28\">They must be disjoint. No unit should \u201csometimes\u201d run repo code. That\u2019s how lies happen.</p><h3 local-id=\"3bf21897c2f5\" id=\"Spec:DevvsReleaseImages-Releaseservices(CLEANdefault)\">Release services (CLEAN default)</h3><p local-id=\"3fedc8f81607\">Release services are shipped with the image and point to installed paths:</p><ul local-id=\"01c76ec0-439b-488a-bbeb-0593161849ee\"><li local-id=\"f91c73c9-c537-49ac-9e7a-8b94e7598ca7\"><p local-id=\"ecd3bf31e677\">binaries in <code>/usr/bin</code> or <code>/opt/hmnd/bin</code></p></li><li local-id=\"767fcece-7e28-4168-ad03-278814bcafe2\"><p local-id=\"8f35673d1d27\">config in <code>/etc/hmnd/</code></p></li><li local-id=\"b408526d-9bf6-444c-9cca-92417c75e03a\"><p local-id=\"7b07f027c4ca\">state in <code>/var/lib/hmnd/</code></p></li><li local-id=\"a28a2439-196a-4647-bf99-987ed92ceba0\"><p local-id=\"d1ecc0011375\">logs in <code>/var/log/hmnd/</code></p></li></ul><p local-id=\"157c57154622\">Release services must be reproducible from the image build.</p><h3 local-id=\"89ab9562d953\" id=\"Spec:DevvsReleaseImages-Devservices(DIRTYonly)\">Dev services (DIRTY only)</h3><p local-id=\"eacced29abed\">Dev services point into the repo checkout:</p><ul local-id=\"1888a9fc-1acb-40df-a7b9-28dcfd9f060c\"><li local-id=\"4b51566c-7070-49bc-826b-be1d137410cc\"><p local-id=\"85beeee1c37a\">repo root: <code>/data/dev/repo/&lt;project&gt;</code></p></li><li local-id=\"6ac47b31-4874-4cc3-a3df-db1ae03ce001\"><p local-id=\"3de124d9a84c\">config: typically <code>/data/dev/repo/&lt;project&gt;/config/...</code> (or still <code>/etc/hmnd</code>, but keep a clean story)</p></li><li local-id=\"50affc13-8ff9-426e-9741-1f4c2e24518c\"><p local-id=\"554a2b723cf1\">build outputs: <code>/data/dev/build/...</code> if applicable</p></li></ul><p local-id=\"a4b092df291c\">Dev services are enabled/disabled by tooling, not by hand-editing symlinks.</p><hr local-id=\"842d34dc-aa05-436e-a43a-923735ee626c\"/><h2 local-id=\"e26b64e0a746\" id=\"Spec:DevvsReleaseImages-ToolingandWorkflows\">Tooling and Workflows</h2><h3 local-id=\"cd9d86c5a5e3\" id=\"Spec:DevvsReleaseImages-robotctlresponsibilities\"><code><span class=\"inline-comment-marker\" data-ref=\"281033b7-c6ab-441a-b0bc-c554136d486a\">robotctl</span></code> responsibilities</h3><p local-id=\"b6b10ae12959\"><code>robotctl</code> is the only supported mechanism for changing mode and switching service profile.</p><p local-id=\"64bd3e8978fb\">Required commands:</p><ul local-id=\"74354c1f-c141-4915-9110-12728f4192ee\"><li local-id=\"0415983d-d9a6-45c3-bd62-afb958fc6411\"><p local-id=\"bc3cded9a7e3\"><code>robotctl enter-dev-mode</code></p></li><li local-id=\"d6b0bd2c-8ae8-4b6c-b937-6a75e7a05bfd\"><p local-id=\"2cb0fd46bfde\"><code>robotctl factory-reset</code></p></li><li local-id=\"a57ba237-f6bc-43bf-a8ca-a6e55dfa2c75\"><p local-id=\"959d49538ac1\"><code>robotctl dev-sync</code></p></li><li local-id=\"afb34387-1ed1-4585-8979-9022df3cb945\"><p local-id=\"bfdf9950be3e\"><code>robotctl dev-build</code></p></li><li local-id=\"4bf5580f-0be2-470f-aca7-0f64be5a37c4\"><p local-id=\"ef9175c875a4\"><code>robotctl dev-switch</code></p></li><li local-id=\"570e4202-fc70-4dcc-ae7e-70684ae29f40\"><p local-id=\"83f6376c1989\"><code>robotctl status</code></p></li></ul><h3 local-id=\"d6a39d833b83\" id=\"Spec:DevvsReleaseImages-Release\u2192Devconversion\">Release \u2192 Dev conversion</h3><p local-id=\"80ac5e7b4d9c\"><code>robotctl enter-dev-mode</code> performs:</p><ol start=\"1\" local-id=\"7d14a1aa-2f77-496d-a2ed-d4da118fd4b8\"><li local-id=\"876949a9-a51a-4ad5-91a0-e926c38792cf\"><p local-id=\"c57df79f3748\">Set bootloader dirty bit to <code>DIRTY</code>.</p></li><li local-id=\"f1325f8d-966a-4be0-8fba-3d5b8be36687\"><p local-id=\"bec381469203\">Ensure <code>/data</code> exists and create <code>/data/dev/{upper,work,repo,build,state}</code>.</p></li><li local-id=\"08fe6011-7bf3-4cdd-9371-8d2b4deb34d3\"><p local-id=\"07a32329db69\">Reboot.</p></li></ol><p local-id=\"c657efb4feda\">After reboot (now DIRTY), the operator runs:</p><ul local-id=\"b5c32e86-9669-4b91-9f3f-57403e21bfd5\"><li local-id=\"ede9ca13-f7b0-4b47-af99-74f286692c65\"><p local-id=\"96a5863d1383\"><code>robotctl dev-sync</code> \u2014 fetch/clone repo quickly</p></li><li local-id=\"7d348f2d-3b18-42b2-88c6-d405b8891897\"><p local-id=\"bba4f5fc1e7a\"><code>robotctl dev-build</code> \u2014 build/install deps</p></li><li local-id=\"b65778d5-eac1-46b5-ad68-98ecbdcb8471\"><p local-id=\"66238c76789d\"><code>robotctl dev-switch</code> \u2014 disable release services, enable dev services, isolate <code>hmnd-dev.target</code></p></li></ul><p local-id=\"dbcb101f3e1d\">This is intentionally a 2-step human-visible transition. You want a deliberate \u201cI am now leaving release land.\u201d</p><h3 local-id=\"c7a66131d585\" id=\"Spec:DevvsReleaseImages-Dev\u2192Releasereset\">Dev \u2192 Release reset</h3><p local-id=\"bd8b381914bb\"><code>robotctl factory-reset</code> performs:</p><ol start=\"1\" local-id=\"afc9106d-6e3f-483b-b345-150a31dfeae4\"><li local-id=\"2283d515-fa82-46f1-ac6c-70e2bb0310f8\"><p local-id=\"9cccc8fcef79\">Stop targets and kill dev processes.</p></li><li local-id=\"e14a97b7-7d30-4623-afd2-102c8baf8b44\"><p local-id=\"09aaa3aa1e6d\">Wipe <code>/data/dev</code> (or wipe whole <code>/data</code> per policy).</p></li><li local-id=\"c9e9cf8f-2899-45a4-8f1e-c27e41d26470\"><p local-id=\"6093e9fe1fd1\">Clear bootloader dirty bit to <code>CLEAN</code>.</p></li><li local-id=\"a9504020-adc5-4cc9-9796-b2679affc507\"><p local-id=\"63c39e3463db\">Reboot.</p></li></ol><p local-id=\"f4c2e87dd479\">Clearing dirty bit without wipe is forbidden.</p><hr local-id=\"3a0bae92-705a-48b9-82a8-d16c90729f55\"/><h2 local-id=\"9e0dd1269718\" id=\"Spec:DevvsReleaseImages-ControlledSSHExperience(tmuxconsole)\">Controlled SSH Experience (tmux console)</h2><h3 local-id=\"a5bdbfdb824d\" id=\"Spec:DevvsReleaseImages-Whytmuxismandatoryindevmode\">Why tmux is mandatory in dev mode</h3><p local-id=\"2f8a5c19be1d\">In DIRTY mode, we want a controlled \u201cconsole\u201d experience because:</p><ul local-id=\"2af4b7a6-e4a2-44f5-92ea-a526a3b87fb0\"><li local-id=\"b7309510-4410-4a24-8de4-d027154b2367\"><p local-id=\"47edeaead9ff\">it standardizes debugging,</p></li><li local-id=\"2c1fc63c-8ce0-4e74-a0af-53f20ec2255c\"><p local-id=\"89d883aff83a\">it makes it obvious what\u2019s running,</p></li><li local-id=\"3ea8c648-d1c3-4e1c-8a8e-3a364ad9afcc\"><p local-id=\"c7bc143e0c29\">it lets automation manage panes and watchers without playing whack-a-mole with user shells.</p></li></ul><p local-id=\"4cd330b105ed\">So: tmux is not optional in DIRTY.</p><h3 local-id=\"4b0992a0373a\" id=\"Spec:DevvsReleaseImages-Single-sessionpolicy\">Single-session policy</h3><p local-id=\"9ee40e1426b9\">In DIRTY mode, all SSH logins attach to the same tmux session (per user or per device\u2014choose one; per user is usually saner).</p><p local-id=\"e09915d21a8e\">Policy:</p><ul local-id=\"7d6494c8-7804-412b-917e-803307bbe2f0\"><li local-id=\"ed984a65-e507-49da-ab9f-4136447c2f6b\"><p local-id=\"f20852958176\">If a session exists: attach.</p></li><li local-id=\"978dd02d-cc2b-4544-b4b8-0899a99df665\"><p local-id=\"dd22e7c66ade\">If not: create it with the standard layout.</p></li><li local-id=\"7f450776-49cf-4e37-9d7c-20f22fc4c981\"><p local-id=\"8f5bcfc209f9\">Prevent creating additional sessions by default (users can still do it if they\u2019re root and determined, but the \u201chappy path\u201d is one session).</p></li></ul><p local-id=\"183cfa9f1502\">Implementation is done via <code>/etc/profile.d/hmnd-tmux.sh</code> (DIRTY-gated) plus a thin wrapper <code>hmnd-console</code>.</p><p local-id=\"2682d8b9a468\">Example gating:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"a4307e34-1428-4d85-8e23-e90ef0a4a9f0\" data-local-id=\"e6c80602-9504-4c6c-a396-3bf9a8a77a5a\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\"># /etc/profile.d/hmnd-tmux.sh\nif [ -n &quot;$SSH_CONNECTION&quot; ] &amp;&amp; [ -f /run/hmnd/mode ] &amp;&amp; grep -qx DIRTY /run/hmnd/mode; then\n  exec /usr/bin/hmnd-console\nfi</pre>\n</div></div><h3 local-id=\"c1c5093f9037\" id=\"Spec:DevvsReleaseImages-Defaulttmuxlayout\">Default tmux layout</h3><p local-id=\"9058e3cadcf1\">The console session should have multiple shells; Codex is one of them.</p><p local-id=\"9e5185d5b83f\">Example layout:</p><ul local-id=\"92aecb33-8073-4ac0-bd3a-88a599b0bc0d\"><li local-id=\"db57ae7d-9808-4c34-acd3-8e244cd1a7e2\"><p local-id=\"bc335013b113\">Window 0: \u201cops\u201d \u2014 tail dev target logs + status</p></li><li local-id=\"b72f9d9d-1da2-4d2a-b6ba-fcd221259435\"><p local-id=\"6673eb16b93e\">Window 1: \u201crepo\u201d \u2014 shell in <code>/data/dev/repo/&lt;project&gt;</code></p></li><li local-id=\"d3cc34f4-4d48-4e9b-bf15-359390e32e2c\"><p local-id=\"996ceea9bb99\">Window 2: \u201ccodex\u201d \u2014 Codex CLI shell (interactive)</p></li><li local-id=\"0c47cb72-be42-4ec1-9bf7-294efa31b8ce\"><p local-id=\"0540dfbe54ca\">Window 3: \u201cbuild\u201d \u2014 build/watch output</p></li></ul><p local-id=\"67ed8a29b4cb\">Codex is present, but not worshipped.</p><hr local-id=\"3d50f796-4bec-48b5-8b6d-ed5fe24aaf29\"/><h2 local-id=\"97f4bed62bb0\" id=\"Spec:DevvsReleaseImages-AutoUpdate,Rebuild,Restart(DIRTY)\">Auto Update, Rebuild, Restart (DIRTY)</h2><p local-id=\"fc776f3eb654\">When repo changes, dev services should refresh automatically. Whether you do hot reload or rebuild+restart depends on the stack; the contract is that the running system converges toward repo HEAD without manual babysitting.</p><h3 local-id=\"a7ddbb712cb4\" id=\"Spec:DevvsReleaseImages-Sourceoftruth\">Source of truth</h3><p local-id=\"bb25b8bbff4e\">Repo checkout at:</p><ul local-id=\"bcc11849-baf7-445c-9f66-34d0dbae8c2d\"><li local-id=\"7f3c92de-6140-4994-bb14-8602e434dc65\"><p local-id=\"60183addddc4\"><code>/data/dev/repo/&lt;project&gt;</code></p></li></ul><h3 local-id=\"a6aa31e08760\" id=\"Spec:DevvsReleaseImages-Watchmechanism\">Watch mechanism</h3><p local-id=\"430088791ba3\">Prefer systemd <code>PathChanged=</code> units over bespoke background daemons.</p><ul local-id=\"c9cb6c6b-f425-4597-932d-9b57eeba4094\"><li local-id=\"fde19cef-93d6-4d3b-bc34-ceae5e4eb959\"><p local-id=\"0f12e1d02411\"><code>hmnd-dev-sync.path</code> watches:</p><ul local-id=\"1cbe978e-7adc-4400-b4f2-f1185db59eed\"><li local-id=\"41872b84-371f-4425-aefc-3cbb75c95e38\"><p local-id=\"a278f4df2ebe\"><code>/data/dev/repo/&lt;project&gt;/.git/HEAD</code></p></li><li local-id=\"4c2ffd02-b126-4866-b923-e6bb566ec3aa\"><p local-id=\"90fd81fadf49\"><code>/data/dev/repo/&lt;project&gt;/.git/refs/</code></p></li><li local-id=\"7e3bf5a3-2983-432a-9a15-2a2e15a1d71e\"><p local-id=\"498b474b3bf4\">or a <code>REVISION</code> stamp file written by <code>robotctl dev-sync</code></p></li></ul></li><li local-id=\"19d8b7d7-4f0c-4c17-ab7d-f6fe1a4e2b83\"><p local-id=\"53f13cefdc85\"><code>hmnd-dev-sync.service</code> runs:</p><ul local-id=\"0ed80d1a-921a-4195-8876-64872a2b98b3\"><li local-id=\"0d43b157-8359-4ace-818e-cbd546279612\"><p local-id=\"9dcdc3385342\"><code>robotctl dev-build</code></p></li><li local-id=\"44101943-1db3-4b2b-97ea-2c5aec65bdbe\"><p local-id=\"5477df64f91b\"><code>robotctl dev-restart</code> (or <code>systemctl restart hmnd-dev.target</code>)</p></li></ul></li></ul><p local-id=\"fa8d416729c1\">Rules:</p><ul local-id=\"b1290001-fa33-46d8-a19f-614d18f3540c\"><li local-id=\"52b8d95c-f7ba-43ff-9ba6-2de332b8b0e4\"><p local-id=\"71e5c3e3d252\">Debounce updates (avoid restarting 30 times during a rebase).</p></li><li local-id=\"26596adc-f86f-4c84-925c-dc1354171177\"><p local-id=\"ba944c647979\">If build fails: do not restart into failure; keep last good services running.</p></li><li local-id=\"f47c6779-455f-4100-8e51-27d1b41d3e4f\"><p local-id=\"23545b7f276f\">Write \u201clast good rev\u201d to <code>/data/dev/state/last_good_rev</code>.</p></li></ul><hr local-id=\"ffec00eb-2eec-4f30-a0e6-22e0dda9113e\"/><h1 local-id=\"7882c751bd19\" id=\"Spec:DevvsReleaseImages-AppendixA\u2014ConcreteShellInterfaces\">Appendix A \u2014 Concrete Shell Interfaces</h1><p local-id=\"cec19d95dfa0\">This is the \u201cdo the thing\u201d layer.</p><h3 local-id=\"0d7224ba9b0c\" id=\"Spec:DevvsReleaseImages-A.1Modeinspection\">A.1 Mode inspection</h3><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"75d9681c-a20c-4c49-b437-d887d4eec12f\" data-local-id=\"f26243cc-0476-4e9b-92b9-05241af91f34\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">cat /run/hmnd/mode         # CLEAN or DIRTY\nrobotctl status            # includes mode, target, repo rev, last good rev</pre>\n</div></div><h3 local-id=\"162fa547946e\" id=\"Spec:DevvsReleaseImages-A.2Enterdevmode\">A.2 Enter dev mode</h3><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"f3401e94-9b98-40c9-b57c-94e57e76b3fe\" data-local-id=\"e40d57f8-329f-4608-87b0-18c0b3a1b48a\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">robotctl enter-dev-mode\n# reboots\nrobotctl dev-sync --ref main\nrobotctl dev-build\nrobotctl dev-switch</pre>\n</div></div><h3 local-id=\"59b065b6c3b4\" id=\"Spec:DevvsReleaseImages-A.3Resettorelease\">A.3 Reset to release</h3><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"b7620936-ae9d-4ef1-a676-3abc37ac8e19\" data-local-id=\"43656274-225d-43e1-8a8c-08f511544293\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">robotctl factory-reset\n# wipes /data/dev, clears DIRTY, reboots into CLEAN + hmnd-release.target</pre>\n</div></div><h3 local-id=\"24d0b5886844\" id=\"Spec:DevvsReleaseImages-A.4Reposyncstrategy(fast)\">A.4 Repo sync strategy (fast)</h3><p local-id=\"4940431ab3e1\">Recommended defaults:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"6c050911-7a39-4e5b-a6a9-30ba29c09daf\" data-local-id=\"290dc9e4-1fc4-4408-8c0b-51bd9e583895\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">git clone --depth=1 &lt;remote&gt; /data/dev/repo/&lt;project&gt;\n# or maintain a mirror under /data/git-mirror and clone from file:// for speed</pre>\n</div></div><h3 local-id=\"30c2464c5d9c\" id=\"Spec:DevvsReleaseImages-A.5Dependencyinstallstrategy\">A.5 Dependency install strategy</h3><p local-id=\"c8c95224fa2d\"><code>robotctl dev-build</code> runs repo-owned, idempotent scripts, e.g.:</p><ul local-id=\"b9c02d81-1f1d-4fa6-93f8-2b49dba417ff\"><li local-id=\"92d86b1b-e917-496a-9d3e-a331a63c40a4\"><p local-id=\"891f41a59bb0\"><code>/data/dev/repo/&lt;project&gt;/dev/apt.txt</code></p></li><li local-id=\"cec7a88c-a721-4134-9582-2a17fdc60968\"><p local-id=\"e371a6f3f550\"><code>/data/dev/repo/&lt;project&gt;/dev/build.sh</code></p></li><li local-id=\"68771e18-f8c6-4667-aa2b-91cd9406a9b4\"><p local-id=\"4533e20f3401\"><code>/data/dev/repo/&lt;project&gt;/dev/install.sh</code></p></li></ul><p local-id=\"776255b258a6\">You stamp completion in <code>/data/dev/state/</code> keyed by commit hash.</p><hr local-id=\"88d2dc95-ec64-484f-8beb-6838101c5a48\"/><h1 local-id=\"6b4ff3c2975a\" id=\"Spec:DevvsReleaseImages-AppendixB\u2014systemdLayout\">Appendix B \u2014 systemd Layout</h1><p local-id=\"a4a8fa8a2041\">Targets:</p><ul local-id=\"22f171da-1a7b-4a0b-957c-ff43c60ced9f\"><li local-id=\"a33bd3fe-4931-41af-912c-e4faed6a25f7\"><p local-id=\"22410240acc7\"><code>/etc/systemd/system/hmnd-release.target</code></p></li><li local-id=\"585a201d-af05-488c-8ae0-50d5064e0279\"><p local-id=\"6fbc5c203ea2\"><code>/etc/systemd/system/hmnd-dev.target</code></p></li></ul><p local-id=\"dd1c381885f3\">Release units live with the image.</p><p local-id=\"d7c18aefe8f7\">Dev units can be shipped with the image but point to stable repo paths (<code>/data/dev/repo/...</code>). They should be inert unless DIRTY and switched.</p><p local-id=\"e6ddb8497856\">Masking policy:</p><ul local-id=\"bb2d6e5b-6144-4c27-afa8-eb2c756da819\"><li local-id=\"e109c783-2578-4138-8b52-30a5aa8f2a32\"><p local-id=\"41262772bf5a\">In CLEAN: <code>hmnd-dev.target</code> and <code>hmnd-*-dev.service</code> masked.</p></li><li local-id=\"8f3d006c-40cb-4e7d-8bc8-e8e37a88b97c\"><p local-id=\"18c48197e92e\">In DIRTY: allowed, but not necessarily default.</p></li></ul><hr local-id=\"72a4a349-bd4d-4a97-890a-611c2e8b11bd\"/><h1 local-id=\"abe538355506\" id=\"Spec:DevvsReleaseImages-AppendixC\u2014CodexIntegrationFollow-upWork\">Appendix C \u2014 Codex Integration Follow-up Work</h1><p local-id=\"704e8c48cfb4\">Codex CLI is installed on the image, but integrated as <em>one tool</em> in the dev console, not a monoculture.</p><p local-id=\"e1f6bd559a3a\">Follow-ups:</p><ul local-id=\"7443a23b-1c20-4539-96cf-8bb72d656285\"><li local-id=\"6de39f52-dfe4-4bb9-8719-37df63daa44d\"><p local-id=\"b511adb806c3\">Define <code>codex-agent.service</code> (DIRTY-only) if you want a persistent background agent.</p></li><li local-id=\"afd4d748-f26d-4fda-9157-4666d08a22ab\"><p local-id=\"70235d9b0761\">Add a <code>hmnd-codex</code> tmux window that runs Codex CLI against <code>/data/dev/repo/&lt;project&gt;</code>.</p></li><li local-id=\"2ee2d203-3caf-4db8-b391-e899f6069b0a\"><p local-id=\"44afae5798e9\">Optionally wire Codex to <code>robotctl</code> commands (sync/build/switch/status) as a \u201ctoolbelt,\u201d not a replacement for normal ops.</p></li></ul><hr local-id=\"cdcde272-27a1-414c-bc5e-46335f37f554\"/><p local-id=\"dbc003f2f959\">This version nails the two big corrections:</p><ol start=\"1\" local-id=\"2bad2ce7-8f56-4edb-9c6a-2f350a57f052\"><li local-id=\"6fbe5e3d-c626-4851-a316-fd343d22143a\"><p local-id=\"88d2b62fa81e\">filesystem hygiene (<code>/etc/hmnd</code>, <code>/var/lib/hmnd</code>, <code>/var/log/hmnd</code>, <code>/run/hmnd</code>, <code>/data/dev</code>), and</p></li><li local-id=\"455bb05a-cda1-460b-b01c-5211aac11f56\"><p local-id=\"5471e17e5252\">tmux as the controlled cockpit, with Codex as one instrument panel among several.</p></li></ol><p local-id=\"0a49b5d0374e\">Next step is choosing whether dev units are shipped with the base image (preferred for stability) or generated from the repo (more flexible, more footguns).</p>"
        },
        {
          "id": "1712324676",
          "title": "Spec: Dev Tooling & Agent Substrate",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1712324676",
          "last_modified": "2026-03-06T10:50:21.541Z",
          "created_at": "2026-03-06T10:42:44.117Z",
          "body_html": "<p local-id=\"1df5dca211bd\"><strong>Owner</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a> <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:7db982f7-f9c1-437c-b348-8b6702d0fd4b\" href=\"https://sklvc.atlassian.net/wiki/people/712020:7db982f7-f9c1-437c-b348-8b6702d0fd4b?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"1645510674\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Oleg Sinavski</a> </p><p local-id=\"a9673b17a762\"><strong>Date</strong>: <time datetime=\"2026-03-06\" class=\"date-past\">06 Mar 2026</time></p><p local-id=\"2da3e93f1728\"><strong>Approvers</strong>:</p><p local-id=\"b63f589951b4\"><strong>Informed</strong>:</p><p local-id=\"3c5743058518\"><strong>Related</strong>:</p><h2 local-id=\"bca33384-f6a5-42e0-a6d2-d26403519659\" id=\"Spec:DevTooling&amp;AgentSubstrate-Problem\">Problem</h2><p local-id=\"4fad2641858c\">The opportunity cost of NOT running agents is growing fast.  Right now there is still quite a bit of toil involved - you have to clone a massive repo, you have to have the disk space, you have to have the CPU/RAM to do the builds, GPUs for simulation.  Can we do better?</p><h2 local-id=\"a3e852d1-d16a-4627-959d-6f61dfdc2d78\" id=\"Spec:DevTooling&amp;AgentSubstrate-Scope\">Scope</h2><h3 local-id=\"0e0bf34b-0996-412e-9be0-81cedcdd2e01\" id=\"Spec:DevTooling&amp;AgentSubstrate-InScope\">In Scope</h3><ul local-id=\"c29cc9970880\"><li local-id=\"ac52304170c2\"><p local-id=\"e8ca5b3e860e\">Cloud-based clones</p></li><li local-id=\"6e4bdf41ae11\"><p local-id=\"f1824babf46d\">Feedback/testing</p></li><li local-id=\"db09a0a8e4a9\"><p local-id=\"7c4d6026da15\">Simulation</p></li><li local-id=\"8374e9e6da48\"><p local-id=\"3082568570f8\">Evals/Benchmarks</p></li></ul><h3 local-id=\"1e8265d1-e784-4b5d-9412-8dc196df8e96\" id=\"Spec:DevTooling&amp;AgentSubstrate-OutofScope\">Out of Scope</h3><h2 local-id=\"b4c4e624-9140-4ccf-ae4e-5eb5894349ce\" id=\"Spec:DevTooling&amp;AgentSubstrate-DesignOverview\">Design Overview</h2><p local-id=\"5c6adf341579\">Very high-level - but imagine an AI-powered sync engine that uses Git as the source of truth, but can render confluence specs (not unlike this one) and Jira tickets/updates as work is done by 24/7 agents.</p><p local-id=\"473d4f10cac7\">The key idea is to push the bottleneck from development to merging.  Ideally when making a release, someone can simply identify the ~10 or so agent-developed branches that they want to include.</p><p local-id=\"e725902c3459\">Developers will need to document their feature along with the metrics and any necessary SOPs in a spec, which can then be broken down and implemented autonomously by coding agents.  Developers (and others) can provide feedback within the spec or PR with the agents incorporating feedback autonomously.  Agents keep the branches up to date with main, resolving conflicts until the spec is ready to be released.</p><p local-id=\"4cd4dd564909\">At no point do developers need to clone the repo or run builds locally.</p><p local-id=\"d7ebcb29c6f0\" />"
        },
        {
          "id": "1672478731",
          "title": "Observability Stack (Grafana/Loki/Tempo/Mimir)",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1672478731",
          "last_modified": "2026-02-25T10:32:37.287Z",
          "created_at": "2026-02-25T10:31:18.698Z",
          "body_html": "<p local-id=\"71a314a34741\"><strong>Summary</strong>: Current \u201cPhase 1\u201d Grafana-based observability </p><p local-id=\"c1cef3948952\"><strong>Owner</strong>: Cody Griffin</p><p local-id=\"c9fae59dd032\"><strong>Date</strong>: 02/25/2026</p><p local-id=\"cadf95178606\"><strong>Approvers</strong>: </p><p local-id=\"83d4a2c7fed3\"><strong>Informed</strong>: Core / Robot / Infra</p><p local-id=\"e1690314a6d1\"><strong>Related</strong>: Spec: HMND Core Control Plane</p><h2 local-id=\"4ae06c50bf0b\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-ProblemStatement\">Problem Statement</h2><p local-id=\"2fb7db442de4\">We need a small, operationally simple observability stack for the Core Control Plane that:</p><ul local-id=\"87698f44ad13\"><li local-id=\"cf6968011cdf\"><p local-id=\"1513434ba7ea\">Works \u201cday 1\u201d without a Kubernetes dependency.</p></li><li local-id=\"02bdb7e9bccd\"><p local-id=\"93427411a97e\">Provides a single pane of glass (Grafana) for metrics, logs, and traces.</p></li><li local-id=\"01b1b8f58c69\"><p local-id=\"07681f5261df\">Offers durable object storage for long-term retention.</p></li><li local-id=\"74e5f195835b\"><p local-id=\"86b31e328620\">Is reproducible and environment-scoped via Terraform.</p></li></ul><h2 local-id=\"7066f0ed8b34\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-Scope(Phase1)\">Scope (Phase 1)</h2><p local-id=\"1cae5b033ea8\"><strong>In-scope</strong></p><ul local-id=\"d81dc6bd0076\"><li local-id=\"4d4d2f6341a5\"><p local-id=\"382250e8e7fc\">Terraform module that provisions:</p><ul local-id=\"d5236cd03682\"><li local-id=\"230a8ab9d25c\"><p local-id=\"6bc78ef84e2c\">Public ALB with TLS termination.</p></li><li local-id=\"9378bff02f97\"><p local-id=\"406962758fd7\">Route53 records for service hostnames.</p></li><li local-id=\"8af87bf5091d\"><p local-id=\"3b10f8c2da8d\">Single private EC2 instance running Grafana/Loki/Tempo/Mimir via <code>systemd</code>.</p></li><li local-id=\"23fb41bfa6f7\"><p local-id=\"c50ab1a5fe27\">S3 bucket for long-term storage (blocks/chunks/traces + ruler/alert data).</p></li><li local-id=\"13e6a768153e\"><p local-id=\"7ae1e9e0c144\">A dedicated gp3 EBS volume mounted at <code>/var/lib/observability</code> for WAL/cache.</p></li></ul></li><li local-id=\"1bc9ae4981a3\"><p local-id=\"877efafb785b\">Basic auth at the edge (Nginx) for non-Grafana endpoints.</p></li><li local-id=\"a224b16c266c\"><p local-id=\"c593276ae61f\">Grafana datasource provisioning so the UI is usable immediately.</p></li></ul><p local-id=\"4604dfc574eb\"><strong>Out-of-scope</strong></p><ul local-id=\"f26f56405f91\"><li local-id=\"595ce1d30414\"><p local-id=\"4b288fe51e6b\">High availability (multi-instance quorum, multi-AZ replication, automatic failover).</p></li><li local-id=\"541c747d2591\"><p local-id=\"22f9302e1caf\">Fine-grained tenant separation / per-robot authZ.</p></li><li local-id=\"0fc3ba358950\"><p local-id=\"86b903ad8391\">\u201cProduction hardening\u201d (OIDC, mTLS, WAF, rate limiting, secret rotation workflows).</p></li><li local-id=\"0aea80006c36\"><p local-id=\"229caf332d32\">Managed scaling for high ingest rates.</p></li></ul><h2 local-id=\"eaa102bd4221\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-DesignOverview\">Design Overview</h2><h3 local-id=\"5ca6c60fdbd2\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-Topology\">Topology</h3><ul local-id=\"8cf4f9bed3df\"><li local-id=\"b9893c9492be\"><p local-id=\"61e7683b216a\"><strong>ALB (public)</strong></p><ul local-id=\"48619adc38d3\"><li local-id=\"1ce19a9b60dd\"><p local-id=\"b2e3ad315b27\">Listeners: <code>:80</code> redirects to <code>:443</code></p></li><li local-id=\"c02b1d88f4c8\"><p local-id=\"1a5126dcfbd0\"><code>:443</code> uses an ACM wildcard certificate for <code>*.&lt;domain_suffix&gt;</code> (example: <code>*.core.dev.hmnd.ai</code>)</p></li><li local-id=\"ea3e58ac8e4f\"><p local-id=\"bafe8951f22b\">Host-based listener rules forward to a single target group</p></li></ul></li><li local-id=\"4a1c2c921136\"><p local-id=\"a9c003fa3b79\"><strong>EC2 instance (private subnet, no public IP)</strong></p><ul local-id=\"73af34814f7c\"><li local-id=\"6b2c3470de7f\"><p local-id=\"413221d5c1f8\">Nginx reverse-proxy on <code>:80</code></p></li><li local-id=\"26191b061ca7\"><p local-id=\"0c1005a87a96\">Services on localhost:</p><ul local-id=\"c199586b573c\"><li local-id=\"3127bb19c84a\"><p local-id=\"af924efc6c2f\">Grafana <code>127.0.0.1:3000</code></p></li><li local-id=\"fc63c9ee57cc\"><p local-id=\"83c6c30dad08\">Mimir <code>127.0.0.1:8080</code></p></li><li local-id=\"27a4a85c1c47\"><p local-id=\"d718c8b1786b\">Loki <code>127.0.0.1:3100</code></p></li><li local-id=\"392e3bb1f848\"><p local-id=\"b2c6c1917ebd\">Tempo <code>127.0.0.1:3200</code> (+ OTLP HTTP on <code>127.0.0.1:4318</code>)</p></li></ul></li></ul></li><li local-id=\"a93b7053d8cd\"><p local-id=\"2ec392e3fdd7\"><strong>S3 bucket</strong></p><ul local-id=\"6dabd5a555e5\"><li local-id=\"9835bb2cde26\"><p local-id=\"ef4fb2543959\">Shared object storage backend for Loki/Mimir/Tempo persisted data</p></li></ul></li><li local-id=\"9532e6ec8b39\"><p local-id=\"6ec5dff68a96\"><strong>EBS gp3 cache volume</strong></p><ul local-id=\"27f8c8291f12\"><li local-id=\"3f1ad5562977\"><p local-id=\"34dfffdb6449\">Mounted at <code>/var/lib/observability</code> for WALs and caches</p></li></ul></li></ul><h3 local-id=\"c5d65b95f574\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-PublicEndpoints\">Public Endpoints</h3><p local-id=\"5b0aa303e60c\">Terraform creates Route53 <code>A</code> aliases pointing at the ALB (example domain suffix shown):</p><ul local-id=\"25d0db4f6d18\"><li local-id=\"090562e91002\"><p local-id=\"676ed3396334\"><code>grafana.&lt;domain_suffix&gt;</code> (e.g. <code>grafana.core.dev.hmnd.ai</code>) \u2192 Grafana UI</p></li><li local-id=\"6e5c66fd42b6\"><p local-id=\"b0f97f4d4d1b\"><code>metrics.&lt;domain_suffix&gt;</code> (e.g. <code>metrics.core.dev.hmnd.ai</code>) \u2192 Nginx \u2192 Mimir (basic auth)</p></li><li local-id=\"ed4f00f66c75\"><p local-id=\"70a153fe80c6\"><code>logs.&lt;domain_suffix&gt;</code> (e.g. <code>logs.core.dev.hmnd.ai</code>) \u2192 Nginx \u2192 Loki (basic auth)</p></li><li local-id=\"11167b443043\"><p local-id=\"0b13f62bba12\"><code>traces.&lt;domain_suffix&gt;</code> (e.g. <code>traces.core.dev.hmnd.ai</code>) \u2192 Nginx \u2192 Tempo (basic auth)</p><ul local-id=\"71fe34ad6621\"><li local-id=\"74d7607a13be\"><p local-id=\"add57ef8bb4c\">OTLP HTTP ingestion: <code>https://traces.&lt;domain_suffix&gt;/v1/traces</code></p></li></ul></li></ul><h3 local-id=\"f23690ecb4d6\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-DataFlow(Conceptual)\">Data Flow (Conceptual)</h3><ul local-id=\"8456945659e9\"><li local-id=\"c1c13a79bc23\"><p local-id=\"2ae97ec8b1b1\"><strong>Metrics</strong>: apps/agents remote_write \u2192 <code>metrics.&lt;domain&gt;</code> \u2192 Nginx (basic auth) \u2192 Mimir \u2192 S3 blocks</p></li><li local-id=\"c99b3b2612c7\"><p local-id=\"ff5a2ee62b55\"><strong>Logs</strong>: agents push \u2192 <code>logs.&lt;domain&gt;</code> \u2192 Nginx (basic auth) \u2192 Loki \u2192 S3 TSDB/chunks</p></li><li local-id=\"a9792910b654\"><p local-id=\"ea84aaee83de\"><strong>Traces</strong>: OTLP HTTP \u2192 <code>traces.&lt;domain&gt;/v1/traces</code> \u2192 Nginx (basic auth) \u2192 Tempo \u2192 S3 blocks</p></li><li local-id=\"ae1c7c41ec8e\"><p local-id=\"b29cd5dc6d4a\"><strong>Visualization</strong>: browser \u2192 <code>grafana.&lt;domain&gt;</code> \u2192 Grafana queries local Mimir/Loki/Tempo</p></li></ul><h3 local-id=\"47974467f2d8\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-StorageModel\">Storage Model</h3><ul local-id=\"e151a3995777\"><li local-id=\"e3f283f1f595\"><p local-id=\"9f02b62e5ea7\"><strong>S3</strong> (<code>observability_bucket_name</code>, default <code>hmnd-obs-dev</code>)</p><ul local-id=\"5e385e611c54\"><li local-id=\"f9ca7502a9a4\"><p local-id=\"9242917f6f74\">Versioning enabled</p></li><li local-id=\"b4be7fbe4857\"><p local-id=\"843244a31b1d\">Server-side encryption (SSE-S3 / AES256)</p></li><li local-id=\"cf625a6de9bc\"><p local-id=\"d184784438b7\">Public access blocked</p></li></ul></li><li local-id=\"6960b795dd1f\"><p local-id=\"a2a056cf2822\"><strong>Local disk</strong> (EBS)</p><ul local-id=\"fdae2230d66b\"><li local-id=\"eab51d174039\"><p local-id=\"93923cd76081\">WAL directories and caches under <code>/var/lib/observability/*</code></p></li></ul></li></ul><h2 local-id=\"6811b9e06e60\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-ConfigurationSurface\">Configuration Surface</h2><h3 local-id=\"527bdb69a3bb\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-RootModuleInputs(hmnd_infra/variables.tf)\">Root Module Inputs (<code>hmnd_infra/variables.tf</code>)</h3><p local-id=\"0e036384111c\">Common knobs:</p><ul local-id=\"a3160eeb7954\"><li local-id=\"fc46d4af961e\"><p local-id=\"7ca8e2ef5419\"><code>core_domain_suffix</code> (default <code>core.dev.hmnd.ai</code>)</p></li><li local-id=\"758cae7c9b3c\"><p local-id=\"fa1403a5e74e\"><code>core_route53_zone_name</code> (default <code>dev.hmnd.ai</code>)</p></li><li local-id=\"e5dfafd0f3ee\"><p local-id=\"cb3462ee2843\"><code>core_route53_zone_id</code> (optional)</p></li><li local-id=\"3a72eb1831e1\"><p local-id=\"9445c965209b\"><code>observability_bucket_name</code></p></li><li local-id=\"e9b96c186f80\"><p local-id=\"01ac01f61dc8\"><code>observability_instance_type</code></p></li><li local-id=\"62d618953c5f\"><p local-id=\"b9163febbd1c\"><code>observability_allowed_ssh_cidrs</code> / <code>observability_ssh_key_name</code></p></li><li local-id=\"bfcb7406d88b\"><p local-id=\"87d3003fc7e9\"><code>observability_loki_version</code> / <code>observability_tempo_version</code> / <code>observability_mimir_version</code></p></li><li local-id=\"5f0452b93a9b\"><p local-id=\"12ad2bec66be\"><code>observability_basic_auth_username</code> / <code>observability_basic_auth_password</code></p></li><li local-id=\"cb20f042aaf8\"><p local-id=\"52cccebf2c5a\"><code>observability_grafana_admin_password</code></p></li></ul><h2 local-id=\"cd2171728845\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-OperationalNotes\">Operational Notes</h2><ul local-id=\"f7b74bacd959\"><li local-id=\"91150b3c868b\"><p local-id=\"60a6bf7602df\">EC2 is managed with <code>AmazonSSMManagedInstanceCore</code> attached to the instance role.</p></li><li local-id=\"098f8b200e24\"><p local-id=\"ec3bce173212\">ALB target group health check hits <code>GET /healthz</code> served by Nginx.</p></li><li local-id=\"2ba18dd07228\"><p local-id=\"cfd239c0cd36\">Services are started via <code>systemd</code> (<code>grafana-server</code>, <code>mimir</code>, <code>loki</code>, <code>tempo</code>, <code>nginx</code>).</p></li><li local-id=\"b6a03a5a8332\"><p local-id=\"163ff3d6aba4\">Grafana datasources are provisioned at boot for:</p><ul local-id=\"6e546449ff0b\"><li local-id=\"2831704f7960\"><p local-id=\"f8aadc9da827\">Local Mimir (default datasource)</p></li><li local-id=\"1dc345c92819\"><p local-id=\"a06d3198477d\">Local Loki</p></li><li local-id=\"6622ddc43775\"><p local-id=\"f07c2b1d4a84\">Local Tempo</p></li><li local-id=\"3de22bd44f2a\"><p local-id=\"cd53eb1e456d\">Plus optional external Prometheus datasources used today for lab clusters.</p></li></ul></li></ul><h2 local-id=\"ee3b60c2ef3a\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-KnownLimitations/Risks\">Known Limitations / Risks</h2><ul local-id=\"c000afe0d4b9\"><li local-id=\"d1d7de167278\"><p local-id=\"816adb0875e0\"><strong>Single-instance / single-AZ</strong> deployment: an AZ or instance failure is a full outage.</p></li><li local-id=\"b27f1ced1f2d\"><p local-id=\"55969a01b935\"><strong>Bootstrap security</strong>: defaults are weak until overridden; treat as non-production.</p></li><li local-id=\"ec19012cfa8b\"><p local-id=\"93f6ef627b94\"><strong>Grafana nightly</strong> package channel: increased upgrade/compat risk.</p></li><li local-id=\"159384436db4\"><p local-id=\"d17a6a302773\"><strong>Multitenancy disabled</strong> in Mimir/Loki configs (fine for bootstrap; revisit for fleet scale).</p></li></ul><h2 local-id=\"a8b778e5456d\" id=\"ObservabilityStack(Grafana/Loki/Tempo/Mimir)-FutureWork\">Future Work</h2><ul local-id=\"0c3d0d4e9085\"><li local-id=\"7d1c32815e50\"><p local-id=\"9ee45954808b\">HA design (multi-AZ, redundancy, automated failover).</p></li><li local-id=\"edcdda154bea\"><p local-id=\"810796d53560\">Replace basic auth with OIDC and/or mTLS + per-device identity.</p></li><li local-id=\"ceef5a6f76f4\"><p local-id=\"310fc6d0a2b0\">Alerting strategy (ruler/alertmanager durability, paging integrations, SLOs).</p></li><li local-id=\"1e64fc64c0ce\"><p local-id=\"e6400337eb98\">Move from single-node services to managed offerings or Kubernetes operators once needed.</p></li></ul>"
        },
        {
          "id": "1636925456",
          "title": "Control Plane PKI and Secrets",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1636925456",
          "last_modified": "2026-02-24T14:20:53.015Z",
          "created_at": "2026-02-12T11:28:10.296Z",
          "body_html": "<p><strong>Summary</strong>: PKI and secrets model for the current Backbone control-plane deployment.</p><p><strong>Owner</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a></p><p><strong>Date</strong>: February 24, 2026</p><p><strong>Approvers</strong>:</p><p><strong>Informed</strong>:</p><p><strong>Related:</strong> <a href=\"/wiki/spaces/ROBOT/pages/1151303693/Spec+HMND+Core+Control+Plane\" data-linked-resource-id=\"1151303693\" data-linked-resource-version=\"8\" data-linked-resource-type=\"page\">Spec: HMND Core Control Plane</a></p><h2 id=\"ControlPlanePKIandSecrets-ProblemStatement\">Problem Statement</h2><p>We need a boring, auditable way to issue short-lived mTLS client certificates to robots, terminate mTLS at the edge for core services, and tie every request to a concrete device identity. For human-facing operations, we want SSO-backed identity with a minimal authorization model (group membership) and good operational ergonomics.</p><p>This implementation is intentionally AWS-managed (ACM PCA, ALB trust store, Cognito, Secrets Manager) rather than a self-hosted CA/auth stack. We avoid CRL/OCSP and instead rely on short certificate TTL plus immediate access removal by deleting or disabling the device record in the control plane.</p><p>The deployed implementation in <code>hmnd_infra/modules/backbone_stack</code> is the source of truth for edge behavior (ALBs, mTLS, Cognito wiring, WAF, secrets injection). The Backbone application defines the exact certificate profile and REST surface; the appendices below document the current intended contract and the parts of it that are enforced/protected by the infrastructure.</p><h2 id=\"ControlPlanePKIandSecrets-DesignOverview\">Design Overview</h2><p>Backbone runs on ECS/Fargate behind two ALBs. The non-mTLS ALB provides the public browser and bearer-token entrypoints, and terminates standard TLS with ACM-issued certificates. It is exposed at <code>backbone_public_domain_name</code> (default <code>public.core.dev.hmnd.ai</code>) and <code>backbone_api_domain_name</code> (default <code>api.core.dev.hmnd.ai</code>).</p><p>Robots connect to a separate ALB when <code>backbone_enable_mtls=true</code> (default). That ALB is exposed at <code>backbone_devices_domain_name</code> (default <code>devices.core.dev.hmnd.ai</code>) and enforces mutual TLS at the listener. Concretely, the listener is configured with <code>mutual_authentication.mode = verify</code>, uses an ALB trust store sourced from an S3-published CA bundle (<code>ca-bundle.pem</code>), and does not ignore client certificate expiry.</p><p>Human identity is Cognito-backed. The stack creates a user pool and two groups (admin/operator names default to <code>hmnd-core-&lt;environment&gt;-admins/operators</code>, but are overrideable). The <code>/v1/dashboard*</code> paths are protected by ALB <code>authenticate-cognito</code>, which provides a simple browser login flow without the Backbone service having to run its own hosted UI.</p><p>At runtime, the service is configured for its auth adapters via environment variables (for example, <code>BACKBONE_HUMAN_AUTH_MODE=alb_oidc_or_cognito_jwt</code> and <code>BACKBONE_DEVICE_AUTH_MODE=alb_mtls</code> when the robots ALB is enabled). Certificate issuance is performed by the Backbone service using ACM PCA (<code>BACKBONE_SIGNER=aws_pca</code> and a resolved PCA ARN), with issuance permissions granted to the ECS task role.</p><h2 id=\"ControlPlanePKIandSecrets-PKI/TrustStore\">PKI / Trust Store</h2><p>The stack can either create a ROOT ACM PCA (default <code>backbone_create_pca=true</code>) or consume an existing PCA (<code>backbone_create_pca=false</code> and <code>backbone_pca_arn</code> set). The ALB trust store bundle is published to S3 as <code>ca-bundle.pem</code>. You can override the bundle explicitly with <code>backbone_trust_store_ca_bundle_pem</code>; otherwise it resolves from the current PCA certificate.</p><p>Robots present a client certificate issued from the trusted CA bundle. The ALB verifies that certificate chain before forwarding traffic to the service; the application then derives identity from the presented certificate and enforces authorization and device lifecycle via its backing store.</p><h2 id=\"ControlPlanePKIandSecrets-Secrets\">Secrets</h2><p>Backbone uses Secrets Manager for runtime configuration and credentials, and the ECS execution/task roles are granted <code>secretsmanager:GetSecretValue</code> scoped to the injected secret ARNs.</p><p>The module creates:</p><ul><li><p><code>${name}/backbone/database_url</code> (Aurora connection URL)</p></li><li><p><code>${name}/backbone/config</code> (Backbone config JSON; currently includes <code>BACKBONE_DB_MIGRATE=1</code>)</p></li><li><p>optional <code>${name}/backbone/openai</code> when <code>backbone_openai_api_key</code> is provided</p></li></ul><p>It can also consume:</p><ul><li><p><code>backbone_google_oauth_secret_arn</code> (recommended when <code>backbone_enable_google_idp=true</code>)</p></li><li><p><code>backbone_extra_secret_arns</code> (additional app-readable secrets)</p></li></ul><p>Operational helper scripts in <code>hmnd_infra</code>:</p><ul><li><p><code>upsert-backbone-secrets.sh</code> bootstraps Google OAuth/OpenAI secrets</p></li><li><p><code>create-backbone-dev-user.sh</code> creates/updates Cognito users and group membership</p></li><li><p><code>backbone-membership</code> adds existing users to admin/operator groups (dev utility)</p></li></ul><h1 id=\"ControlPlanePKIandSecrets-AppendixA-InfraResourceMap\">Appendix A - Infra Resource Map</h1><p>The <code>modules/backbone_stack</code> Terraform module provisions the full Backbone edge and stateful dependencies: ECR + ECS/Fargate service, a public ALB (plus an optional dedicated robots mTLS ALB), ACM certificates and Route53 records for the entrypoints, an ALB trust store backed by an S3 CA bundle object, Aurora PostgreSQL Serverless v2 (with <code>pg_cron</code> enabled), Cognito user pool + groups + hosted domain (plus optional Google IdP), WAF protection on the public ALB (including enrollment endpoint rate limiting), and Secrets Manager entries for DB/config and other application secrets.</p><h1 id=\"ControlPlanePKIandSecrets-AppendixB-KeyRuntimeConfiguration\">Appendix B - Key Runtime Configuration</h1><p>The Backbone task definition wires configuration via environment variables and secret injection. The key parts are: (1) store selection (<code>BACKBONE_STORE=postgres</code>) backed by <code>BACKBONE_DATABASE_URL</code> from Secrets Manager, (2) certificate signer selection (<code>BACKBONE_SIGNER=aws_pca</code> with <code>BACKBONE_PCA_ARN</code>), and (3) auth adapter selection for humans vs robots (<code>BACKBONE_HUMAN_AUTH_MODE</code> and <code>BACKBONE_DEVICE_AUTH_MODE</code>).</p><p>Cognito integration is provided via <code>BACKBONE_COGNITO_REGION</code>, <code>BACKBONE_COGNITO_USER_POOL_ID</code>, and <code>BACKBONE_COGNITO_APP_CLIENT_ID</code>, along with group names (<code>BACKBONE_ADMIN_GROUP</code> and <code>BACKBONE_OPERATOR_GROUP</code>) that Backbone uses to implement a minimal authorization model (admin for write operations, operator for read-only).</p><h1 id=\"ControlPlanePKIandSecrets-AppendixC-RESTAPI(IntendedContract)\">Appendix C - REST API (Intended Contract)</h1><p>This appendix describes the current intended REST surface for the Backbone control plane. Exact request/response shapes are defined by the Backbone service implementation, but the endpoints below reflect what the infrastructure is explicitly configured to protect and what clients are expected to use.</p><h2 id=\"ControlPlanePKIandSecrets-Health\">Health</h2><p><code>GET /health</code></p><p>Used by ALB target group health checks.</p><h2 id=\"ControlPlanePKIandSecrets-Enrollments(Robot-Initiated,Human-Approved)\">Enrollments (Robot-Initiated, Human-Approved)</h2><p><code>POST /v1/enrollments</code> (unauthenticated; rate limited by WAF)</p><p>A robot begins enrollment by submitting metadata and a CSR. The control plane returns a short-lived enrollment record that the robot can poll.</p><p>Example request:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"8f42daad-0ca7-4d90-8de9-41f4cd1bdfc2\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">{\n  &quot;robot_id&quot;: &quot;RBT-042&quot;,\n  &quot;robot_type&quot;: &quot;alpha_wheelbase&quot;,\n  &quot;device_type&quot;: &quot;rtpc&quot;,\n  &quot;csr_pem&quot;: &quot;...&quot;,\n  &quot;nonce_hash&quot;: &quot;...&quot;\n}</pre>\n</div></div><p>Example response:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"85b50436-1591-4443-8c6d-84ec641bfc8e\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">{ &quot;enrollment_id&quot;: &quot;...&quot;, &quot;expires_at&quot;: &quot;...&quot; }</pre>\n</div></div><p><code>GET /v1/enrollments/{id}</code></p><p>While pending:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"f837f4c3-fc51-4b8f-87ee-ec1c6fbe8092\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">{ &quot;status&quot;: &quot;PENDING&quot;, &quot;expires_at&quot;: &quot;...&quot; }</pre>\n</div></div><p>On completion, the response includes the issued certificate material:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"0cf71815-815c-4876-83c3-02772276704d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">{\n  &quot;status&quot;: &quot;COMPLETE&quot;,\n  &quot;device_id&quot;: &quot;...&quot;,\n  &quot;cert_pem&quot;: &quot;...&quot;,\n  &quot;chain_pem&quot;: &quot;...&quot;,\n  &quot;cert_expires_at&quot;: &quot;...&quot;\n}</pre>\n</div></div><h2 id=\"ControlPlanePKIandSecrets-Devices(Human-Authenticated)\">Devices (Human-Authenticated)</h2><p><code>POST /v1/devices</code> (human-authenticated)</p><p>A human approves an enrollment by presenting the enrollment ID and the matching nonce. In the current model, write actions are expected to require admin group membership.</p><p>Example request:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"9498cb5f-8a95-4f26-9c4c-04fc24fa393c\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">{ &quot;enrollment_id&quot;: &quot;...&quot;, &quot;nonce&quot;: &quot;...&quot; }</pre>\n</div></div><p>Typical server behavior:</p><ul><li><p>validate enrollment and nonce</p></li><li><p>issue certificate via ACM PCA</p></li><li><p>create or update the durable device record</p></li><li><p>delete the enrollment record</p></li></ul><p><code>GET /v1/devices</code> and <code>GET /v1/devices/{device_id}</code> (human-authenticated)</p><p>Read actions are expected to be permitted for operator group membership.</p><p><code>DELETE /v1/devices/{device_id}</code> (human-authenticated)</p><p>Immediate blocking is implemented by removing/invalidating the device record so subsequent requests fail authorization.</p><h2 id=\"ControlPlanePKIandSecrets-Sessions/Presence(Robot-Authenticated)\">Sessions / Presence (Robot-Authenticated)</h2><p><code>POST /v1/sessions</code> (robot-authenticated)</p><p>Robots periodically upsert last-seen presence and optional metadata. When mTLS is enabled, authentication is based on the client certificate verified at the ALB.</p><h1 id=\"ControlPlanePKIandSecrets-AppendixD-DataModel(Intended)\">Appendix D - Data Model (Intended)</h1><p>All state is stored in Aurora PostgreSQL. The infra enables <code>pg_cron</code> as a shared preload library and the intended design uses TTL-based cleanup for ephemeral tables. The exact schema is owned by the Backbone service migrations; the DDL below captures the intended structure.</p><p>devices (durable)</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"3165ddb9-22a2-4185-b5e9-88cb1998b8af\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">CREATE TABLE devices (\n  device_id UUID PRIMARY KEY,\n  robot_id TEXT NOT NULL,\n  robot_type TEXT NOT NULL,\n  device_type TEXT NOT NULL CHECK (device_type IN ('RTPC','ORIN','OTHER')),\n  cert_fingerprint_sha256 TEXT NOT NULL UNIQUE,\n  cert_expires_at TIMESTAMPTZ NOT NULL,\n  created_by_iss TEXT NOT NULL,\n  created_by_sub TEXT NOT NULL,\n  created_at TIMESTAMPTZ NOT NULL DEFAULT now(),\n  updated_at TIMESTAMPTZ NOT NULL DEFAULT now()\n);\n\nCREATE UNIQUE INDEX ON devices (robot_id, device_type);\nCREATE INDEX ON devices (robot_id);\nCREATE INDEX ON devices (cert_expires_at);</pre>\n</div></div><p>enrollments (TTL)</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"6f0b64c6-975a-4d04-b100-0a5c056ab3eb\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">CREATE TABLE enrollments (\n  enrollment_id UUID PRIMARY KEY,\n  robot_id TEXT NOT NULL,\n  robot_type TEXT NOT NULL,\n  device_type TEXT NOT NULL CHECK (device_type IN ('RTPC','ORIN','OTHER')),\n  csr_pem TEXT NOT NULL,\n  nonce_hash TEXT NOT NULL,\n  expires_at TIMESTAMPTZ NOT NULL,\n  created_at TIMESTAMPTZ NOT NULL DEFAULT now()\n);\n\nCREATE INDEX ON enrollments (expires_at);</pre>\n</div></div><p>sessions (presence TTL)</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"15f7870b-cf7a-4b03-9722-5dcfad39ea33\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">CREATE TABLE sessions (\n  device_id UUID PRIMARY KEY REFERENCES devices(device_id),\n  last_seen_at TIMESTAMPTZ NOT NULL,\n  data JSONB\n);\n\nCREATE INDEX ON sessions (last_seen_at);</pre>\n</div></div><p>TTL cleanup via <code>pg_cron</code> (example schedule: every 5 minutes)</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"2e0ee693-ff7f-4894-aa9c-7c2d8aa5bded\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">DELETE FROM enrollments\nWHERE expires_at &lt; now();\n\nDELETE FROM sessions\nWHERE last_seen_at &lt; now() - interval '7 days';</pre>\n</div></div><h1 id=\"ControlPlanePKIandSecrets-AppendixE-Enrollment,Renewal,andRecovery(Intended)\">Appendix E - Enrollment, Renewal, and Recovery (Intended)</h1><p>A robot enrollment starts locally: the device generates a keypair and a CSR, generates a high-entropy nonce, and submits the CSR and a hash of the nonce to <code>POST /v1/enrollments</code>. The robot then shows the enrollment ID and the nonce out-of-band to a human operator.</p><p>The human completes approval by authenticating via Cognito (optionally federated to Google) and submitting <code>POST /v1/devices</code> with the enrollment ID and nonce. Backbone issues the certificate via ACM PCA, binds it to the device record, and the robot begins authenticating to the robots ALB using mTLS.</p><p>Renewal is expected to be a normal online operation prior to expiry, driven by a new CSR and resulting in an updated fingerprint/expiry on the same device identity. If a robot is offline past expiry and cannot authenticate to renew, recovery is treated as re-enrollment; the stable logical device identity is preserved in the registry while rotating keys and certificate.</p><h1 id=\"ControlPlanePKIandSecrets-AppendixF-MinimalAbuseControls\">Appendix F - Minimal Abuse Controls</h1><p>The public ALB is protected by WAF with an IP-based rate limit on <code>POST /v1/enrollments</code>. The intended application-level controls include: CSR size limits, short enrollment TTL, and nonce hashing (nonce never stored in plaintext).</p>"
        },
        {
          "id": "1417478145",
          "title": "Spec: Booting Alpha With kexec",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1417478145",
          "last_modified": "2025-12-12T10:15:55.261Z",
          "created_at": "2025-12-12T10:11:21.016Z",
          "body_html": "<p local-id=\"a212635c-3bd7-4001-9c5a-19cf949d5c93\">Spec: kexec-Based Ephemeral RootFS Boot for Robot Bringup<br/>Owner: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a> <br/>Date: <time datetime=\"2025-12-12\" class=\"date-past\">12 Dec 2025</time> <br/>Approvers: \u2014</p><h2 local-id=\"97824fbf-5687-4d78-87eb-9863a33d288c\" id=\"Spec:BootingAlphaWithkexec-ProblemStatement\">Problem Statement</h2><p local-id=\"0cc68e77-2a93-433a-a887-700cb9bc4127\">Flashing Jetson partitions and maintaining bootloader state is slow, brittle, and hostile to iteration. On x86, touching EFI/GRUB for every experiment is equally dumb.</p><p local-id=\"7ab2e8fb-fb5e-46c1-8c14-a503ed6f2303\">We need a fast, reproducible way to boot a fully-built robot software stack (kernel + initramfs + rootfs) <strong>from inside a known-good host OS</strong> without repartitioning, bootloader changes, or permanent installation.</p><p local-id=\"949fc57f-99cc-4100-92a8-eccef4e3d477\">The system must support:</p><ul local-id=\"d5ba4d5e-221e-41c7-bfee-2d8e69e8ca7e\"><li local-id=\"ec750a7f-3ba1-4b05-ac87-b2e9e5f9a474\"><p local-id=\"889f8917-7158-4fba-b1c7-f18fdec2dbbc\">Jetson Orin AGX running JetPack (L4T), where we <strong>reuse host DTB/firmware</strong>.</p></li><li local-id=\"21748c44-0c03-4016-ad7b-ec06fbe376b0\"><p local-id=\"5be1ca77-1706-4238-bbf0-4547e03ee8d5\">Congatech x86 running an RT-patched kernel doing EtherCAT, where <strong>post-kexec EtherCAT behavior is the biggest risk</strong>.</p></li></ul><h2 local-id=\"5791a00c-c4b2-4c08-b550-229223f094c1\" id=\"Spec:BootingAlphaWithkexec-Goals\">Goals</h2><ul local-id=\"acecd1d3-823e-47e5-8646-2c7975d3455c\"><li local-id=\"31abf5f9-8b09-4b3b-84d4-70906c3f48bc\"><p local-id=\"48500a8e-42aa-42cc-9000-3ffb1da2d008\">Boot a versioned \u201cguest OS\u201d built by CI/Bazel as an immutable SquashFS image.</p></li><li local-id=\"4bab90cd-efeb-4f1c-86e0-02bbc1e165d0\"><p local-id=\"c49e9e24-63ed-4be5-8c67-582355ceecac\">Transition from host \u2192 guest via kexec in seconds.</p></li><li local-id=\"1161a852-ac03-4339-9ba0-5b7f1ba6bac9\"><p local-id=\"ceed2282-8749-4172-b784-bbd0f9259e52\">Keep a small set of state/config persistent across guest boots (e.g., <code>/etc/hmnd</code>, <code>/var/lib/hmnd</code>).</p></li><li local-id=\"3e4c4c52-e297-4f45-b0d4-a8746ce2a6c2\"><p local-id=\"a76a88ce-5193-415d-88c0-07d3a4a41fbf\">Make failure modes diagnosable from serial/console without needing network.</p></li><li local-id=\"3ea763ec-737e-4c1e-93e7-91aec8e0d262\"><p local-id=\"bf60c5f0-a6e5-493a-9e4b-a80ec333c62c\">Preserve a clean escape hatch back to the host baseline.</p></li></ul><h2 local-id=\"766be5ae-6d86-4938-8c87-7da9e79a6e04\" id=\"Spec:BootingAlphaWithkexec-Non-Goals\">Non-Goals</h2><ul local-id=\"7aeefbcc-ad08-4973-abb7-796f293e0054\"><li local-id=\"0f3e1877-fcdb-4cea-9b1d-413943ad1132\"><p local-id=\"e9d98cd9-4d1d-4ed1-9667-39a01848c718\">Replacing the platform bootchain (UEFI/MB1/MB2/GRUB) or changing partition layouts.</p></li><li local-id=\"9689b5c2-513e-4a63-9675-f3c90d8bae98\"><p local-id=\"2438e8f4-5811-41a1-bc7c-e4cbc236daf7\">Full hardware reinitialization guarantees equivalent to power-cycle.</p></li><li local-id=\"d71a06b8-831c-4fca-b08a-f9dcd877b9d9\"><p local-id=\"56491fa3-6b7e-41d1-b508-c3e9c18f0b0d\">Secure boot / measured boot / attestation (future work).</p></li><li local-id=\"1a293026-ba45-46f8-8c60-55d887d09d5d\"><p local-id=\"c0ad4ff6-76dd-4d79-a9d4-633ed1cc496c\">Long-term \u201cproduction boot\u201d path (this is a development and field-debugging boot path first).</p></li></ul><h2 local-id=\"058eda47-9aa0-47b6-a0a8-2ddc50297702\" id=\"Spec:BootingAlphaWithkexec-Scope\">Scope</h2><h3 local-id=\"d41dbead-c7b4-458a-af2e-1e0ea846bcb3\" id=\"Spec:BootingAlphaWithkexec-Inscope\">In scope</h3><ul local-id=\"852ee99a-1fb3-4fc0-ae97-66d9470b2291\"><li local-id=\"6f492b22-a1f1-43b0-8d66-c8e6aa99ef19\"><p local-id=\"809d9201-eaf5-434b-9c82-97cf30a2fce5\">Host-side launcher that loads guest kernel/initramfs (from SquashFS) and executes kexec.</p></li><li local-id=\"efc9b1ae-bbdf-4a63-a450-035835f870a1\"><p local-id=\"b938c4f0-0867-49c2-ad75-41eead41193b\">Guest initramfs that assembles the final root from:</p><ul local-id=\"7f004c30-223e-4eb6-92d4-31f28669360c\"><li local-id=\"a578aae6-255c-4e56-97c7-cfff0997d5f9\"><p local-id=\"1cb475b1-a6fb-4fb9-b76c-f41bf556dbca\">lowerdir: immutable SquashFS rootfs</p></li><li local-id=\"1cf0bd67-7b8d-4c34-9e92-9bb07a1ca1e4\"><p local-id=\"4011a884-6ec7-415e-9613-3acb981c8854\">persistence: bind mounts from host root partition</p></li><li local-id=\"fd827a8c-b38c-488c-895b-4ae807ffc587\"><p local-id=\"97016803-80c5-4c21-bc9c-6a24a2912302\">optional overlay upperdir: tmpfs (ephemeral) or persistent dir on host partition</p></li></ul></li><li local-id=\"aa4de0c9-c742-4cb7-8d40-0106ccfa3bcf\"><p local-id=\"e64105c6-fa20-4eec-9611-d1065f53addf\">Platform support:</p><ul local-id=\"ed99e426-b3e2-437e-9471-c8d368fe6007\"><li local-id=\"72d3f6cb-e96b-480f-a7ef-01798c7f4e04\"><p local-id=\"46c7f1d6-ddd9-4b3b-a988-bd7e04ef32c5\">Jetson Orin AGX (JetPack host; reuse host DTB; firmware via host bind or guest packaging)</p></li><li local-id=\"6b91431e-7e04-4a3d-91fc-390e03245e96\"><p local-id=\"b1493958-1ed4-407b-bc71-19f694843691\">Congatech x86 (RT kernel host; EtherCAT driver behavior under kexec explicitly tested)</p></li></ul></li><li local-id=\"8af350ff-51ce-498a-9a7d-a1a7307ee3ae\"><p local-id=\"715c2d47-75bc-452f-a820-493ddc5c043a\">Packaging into the robot image (systemd service + CLI + initramfs + docs).</p></li></ul><h3 local-id=\"0e1f454c-6f61-499e-ad69-35912e5953d8\" id=\"Spec:BootingAlphaWithkexec-Outofscope\">Out of scope</h3><ul local-id=\"446216ca-2967-45e8-aaf0-4682b46eac0e\"><li local-id=\"8a35aefb-65d3-4d77-9526-78b8d7c06fd1\"><p local-id=\"f50e297b-c11f-42aa-9d67-710e29b00b43\">Remote boot selection.</p></li><li local-id=\"b6d1afc6-54f3-4157-a162-4ba39eb1a8d4\"><p local-id=\"f315c25a-1bb9-4417-9620-0435f1a5078c\">Automatic fallback boot integration with firmware boot menus.</p></li><li local-id=\"6e743f26-ede2-4bec-bcc6-2cbaa674f7ef\"><p local-id=\"f283b1c4-eb99-4a4f-9b57-d91ddf461234\">Hot-swapping DTBs on Jetson with bootloader-equivalent fixups (we explicitly avoid this).</p></li></ul><h2 local-id=\"296a9588-c935-432f-ad74-9396e0727aab\" id=\"Spec:BootingAlphaWithkexec-DesignOverview\">Design Overview</h2><h3 local-id=\"5416f4f0-a729-4f1a-b008-91a3919d93df\" id=\"Spec:BootingAlphaWithkexec-Architecture\">Architecture</h3><p local-id=\"50a464a2-6a2c-43f4-ac9a-330ed90208a5\"><strong>Host OS (baseline, \u201clauncher\u201d)</strong></p><ul local-id=\"47fc5bff-f0a5-4c77-81fe-1bccc0d9a424\"><li local-id=\"dd6a8b5e-8a25-432a-8313-0eb6b48eaba5\"><p local-id=\"39f9c700-1b9f-4b60-b26c-6e9694cb93a1\">Known-good OS installed normally (JetPack on Orin; RT Linux on x86).</p></li><li local-id=\"1ebd30ad-cb32-4594-b522-335e1dcf5b16\"><p local-id=\"6682620d-47bf-4c25-96af-479b43841c9a\">Provides storage, firmware blobs (optional), and persistence directories.</p></li><li local-id=\"5b81dc48-8e12-49d2-adce-9139280fdfde\"><p local-id=\"32a8aa35-95c2-4792-b2ff-fbc90c4207a5\">Runs <code>hmnd-kexec</code> launcher to transition to guest.</p></li></ul><p local-id=\"8e78bc3e-097b-4e81-863a-d5b4b7aba44d\"><strong>Guest OS (ephemeral, \u201cimage\u201d)</strong></p><ul local-id=\"9038ec43-b2f0-4356-8e47-7268ac3152a8\"><li local-id=\"95cfb2d3-35cb-48e3-9037-15a49c03cb8c\"><p local-id=\"cf8e3cf4-2eb5-42a8-b624-f276d8cf1891\">Built artifacts:</p><ul local-id=\"9b25ca71-ec2b-46ee-b57b-28d3a4383f8c\"><li local-id=\"b5802687-2c9e-4ff1-9b12-fd8a0939b65d\"><p local-id=\"bbd0f27e-d61a-4a1a-bc76-3056fffe5c01\"><code>vmlinuz</code> (guest kernel)</p></li><li local-id=\"44ad0636-b127-4125-adc5-db4bdf8a5a7e\"><p local-id=\"95676e87-d598-43be-a0ff-31bdccfbd6e7\"><code>initramfs.img</code> (guest initramfs)</p></li><li local-id=\"5beb9cf8-21da-4d63-8a2d-30ad1f5db4a3\"><p local-id=\"87bc7014-3687-4845-8812-97cd43e18fbb\"><code>root.squashfs</code> (immutable rootfs)</p></li><li local-id=\"76c96442-9ec4-4ab2-8767-c7de8e53923c\"><p local-id=\"5a64f5ff-c43d-42d9-b7d5-7979ce9a6e87\"><code>manifest.json</code> (version metadata, kernel ABI, modules hash, etc.)</p></li></ul></li><li local-id=\"e4231509-a641-481e-b9e3-0330949da353\"><p local-id=\"fa233698-79ef-4c2f-9755-0ed36df989bf\">Boots via kexec into guest initramfs.</p></li><li local-id=\"be887690-f879-4988-9406-bc6224ac72d0\"><p local-id=\"eff18540-2df2-49bd-a751-27eaf083a77b\">Guest initramfs mounts/assembles final <code>/</code> and <code>switch_root</code>s into it.</p></li></ul><h3 local-id=\"877b499c-3d14-44fa-b6cb-7f3a2736b2b4\" id=\"Spec:BootingAlphaWithkexec-BootFlow\">Boot Flow</h3><ol start=\"1\" local-id=\"f1510095-dd21-449b-8a7e-489dfe6c7491\"><li local-id=\"25600bfa-3ac2-41e4-9c34-4a3303650123\"><p local-id=\"7854e5cb-3b90-454f-a8f2-de9f239a0ae2\">Host mounts <code>root.squashfs</code> read-only (loop mount).</p></li><li local-id=\"c41669df-c108-47d6-a003-143f4536b83b\"><p local-id=\"ec882894-9031-45ee-824c-11ee16a5e83e\">Host copies <code>vmlinuz</code> + <code>initramfs.img</code> to tmpfs (avoid loop device dependency during handoff).</p></li><li local-id=\"b42de50d-2c72-4c8f-a0e8-e9aed955a4c2\"><p local-id=\"5aca93d7-78f8-4613-a2f0-7707923f43f8\">Host runs:</p><ul local-id=\"4bdf3052-c647-4e8c-855a-449d667d69fb\"><li local-id=\"6a33f7bf-26ac-47ac-aed4-7683418edccc\"><p local-id=\"6b4329f5-aef6-4ba6-a42c-89d1c908bfaa\"><code>kexec -l &lt;vmlinuz&gt; --initrd &lt;initramfs&gt; --command-line &quot;&lt;cmdline&gt;&quot;</code></p></li><li local-id=\"5956cd9e-390c-43aa-913a-3859b6965d6f\"><p local-id=\"3d9f95c0-008b-461e-97ec-850e3550c823\"><code>kexec -e</code></p></li></ul></li><li local-id=\"13348791-1010-4a9b-9fbe-e34ed9e40ac0\"><p local-id=\"3c30c2cd-7e8e-4db6-8f44-f3fa3988468c\">Guest kernel starts, executes initramfs <code>/init</code>.</p></li><li local-id=\"c55d22ea-7741-4e8a-ad66-ac413b091dbc\"><p local-id=\"04a8c2b9-8203-496e-b379-3894d9aebbfc\">Guest initramfs:</p><ul local-id=\"35fdc2ed-63d3-425c-aee3-6bce50ca785f\"><li local-id=\"32e50551-661b-4a87-adbc-6ff3ca85984b\"><p local-id=\"ac31b81d-4d0d-424a-b714-f7fb0a7eeb17\">mounts <code>proc/sys/dev</code></p></li><li local-id=\"c2bb8269-8cd3-44ed-b22d-e61bd9247c8b\"><p local-id=\"bbb0a22d-98df-4d63-92ed-6f2bf8c2a40c\">mounts the host root partition read-only at <code>/host</code> (from <code>root=</code> / UUID)</p></li><li local-id=\"8bf09ab9-7585-4b2a-a66b-d380c46156af\"><p local-id=\"8523e3df-31ed-4745-804e-5f0f6e3cc965\">loop-mounts SquashFS image at <code>/squash</code> (from <code>hmnd.squash=</code>)</p></li><li local-id=\"749cfb7f-82de-4260-8d8b-b0f4c362a935\"><p local-id=\"e2a57cb5-3919-4558-8dbe-ec6cf3988925\">creates <code>/newroot</code> using one of:</p><ul local-id=\"b3f1cb7d-70ce-4089-8cec-164549cc39af\"><li local-id=\"901edea1-bd47-40d6-8b99-02a4c3aa52cc\"><p local-id=\"ddbfa805-cc8f-4678-9616-709814160f0b\"><strong>RO mode</strong>: bind mount <code>/squash</code> as <code>/newroot</code></p></li><li local-id=\"38583523-df5f-4713-8137-f0be2717d926\"><p local-id=\"ff9540e9-c1eb-4b54-b954-0e797e542a18\"><strong>Overlay mode (recommended)</strong>: overlayfs with lowerdir=<code>/squash</code>, upperdir=<code>tmpfs</code> (or persistent)</p></li></ul></li><li local-id=\"93d5a791-ddb3-4e33-9ff4-90b2edc67521\"><p local-id=\"c427875f-4a59-4bf6-9778-8e9caf5e80a3\">bind-mounts persistence paths from <code>/host</code> \u2192 <code>/newroot</code></p></li><li local-id=\"8e095a91-7dce-48a1-96ac-3752b5e88221\"><p local-id=\"c439cbf9-4274-4457-b29d-8c027924f514\"><code>switch_root /newroot /sbin/init</code></p></li></ul></li></ol><h3 local-id=\"710ba628-95e2-48e1-b00b-5819fb9d19d2\" id=\"Spec:BootingAlphaWithkexec-CommandLineContract\">Command Line Contract</h3><p local-id=\"3ad3911a-205c-490a-8710-fcf9dbb487dd\">Guest kernel cmdline includes:</p><ul local-id=\"faea5abc-7dbb-4f19-b1d3-2cafd8b997b4\"><li local-id=\"b44ddb1f-0178-4191-841d-d85f439f13cf\"><p local-id=\"fdba78e9-5a8b-4109-a139-b2dc5cf963dc\"><code>root=</code> host partition identifier (UUID/LABEL) used only as a source mount in initramfs</p></li><li local-id=\"73eb1d2d-bfa4-4821-be69-1cd33c775921\"><p local-id=\"30b5e1bf-d2bc-4717-b449-2d981041c827\"><code>hmnd.squash=</code> absolute path to SquashFS on host FS (e.g., <code>/ssd_2tb/images/hmnd-root.squashfs</code>)</p></li><li local-id=\"2707c5cd-909b-452a-8ff4-148a0d870ad1\"><p local-id=\"8e674d5a-6fa9-4de8-8163-fc00c2f333d0\"><code>hmnd.persist=</code> comma-separated list of host paths to bind into guest (rw)</p></li><li local-id=\"148f80b9-f5eb-43f2-b449-8ac346f3393f\"><p local-id=\"61807ebc-ca9b-4aa4-822b-732097c88b61\"><code>hmnd.host_ro=</code> comma-separated list of host paths to bind into guest (ro) for vendor firmware/libs</p></li><li local-id=\"7ab7dbae-0f55-4f9f-8cf9-eebbbf2e1cc0\"><p local-id=\"4821ef57-957f-4dfb-9452-224f8069cc90\"><code>hmnd.overlay=</code> <code>tmpfs|persistent|off</code></p></li><li local-id=\"455454e7-1104-4e3f-a8b4-aac53ad8aac3\"><p local-id=\"c2715563-23c6-42f8-b308-296d099a681a\"><code>hmnd.overlay_dir=</code> (if persistent) where upper/work live on host partition</p></li><li local-id=\"244d13d1-0068-46f4-9d15-2afd9505c1a6\"><p local-id=\"03435601-8cb0-4535-959e-291c1989c99e\"><code>hmnd.debug=</code> enables initramfs shell on failure</p></li></ul><p local-id=\"7673a730-d173-44c3-b647-560bf415cd22\">Example:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"536aefa8-5072-4462-90ee-321501836153\" data-local-id=\"38e898dd-399f-4bef-af9a-5da307f0721b\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">console=tty0 root=UUID=&lt;host-root-uuid&gt; ro rootwait \\\nhmnd.squash=/ssd_2tb/images/hmnd-root.squashfs \\\nhmnd.persist=/etc/hmnd,/var/lib/hmnd \\\nhmnd.host_ro=/lib/firmware \\\nhmnd.overlay=tmpfs hmnd.debug=1\n</pre>\n</div></div><h2 local-id=\"2402489f-26b5-435b-af9b-0181c9721c58\" id=\"Spec:BootingAlphaWithkexec-Platform-SpecificDesign\">Platform-Specific Design</h2><h3 local-id=\"4d36420a-953f-4440-ba2c-cde42804d419\" id=\"Spec:BootingAlphaWithkexec-A)JetsonOrinAGX(JetPackhost)\">A) Jetson Orin AGX (JetPack host)</h3><p local-id=\"9dac220e-a326-4bf2-978d-5a9ccd1a9766\"><strong>DTB policy</strong></p><ul local-id=\"3452fda1-6c24-4ab8-b433-92576a0b9bc3\"><li local-id=\"169887fb-d300-4e2b-a96f-c01a038868f5\"><p local-id=\"7ab6a5f0-fbc6-4c57-952a-23e61030e2e4\">Default: <strong>reuse running DTB</strong> (no <code>--dtb</code> passed to kexec).</p></li><li local-id=\"02c861ff-c307-4b52-b58a-a5109f3865f9\"><p local-id=\"4034cda2-5fed-4675-996a-bdcdf57e6590\">Rationale: Jetson boot firmware applies fixups/carveouts; reusing avoids mismatch and \u201cGPU explodes later\u201d scenarios.</p></li></ul><p local-id=\"7b29a617-6b80-448e-90ac-40a0672f7a57\"><strong>Firmware policy</strong></p><ul local-id=\"32a91ec1-46de-4358-bd0a-2962b96f2f0f\"><li local-id=\"520bc7d0-d01c-459c-891c-0bc2f775c4c0\"><p local-id=\"dc352e89-92ef-49f4-8f76-8689e60d8a30\">Default: bind-mount <code>/lib/firmware</code> from host into guest (ro).</p></li><li local-id=\"3201c815-25a2-4b20-ae12-02b3faa63212\"><p local-id=\"7e3e4e68-f5ac-48b0-84ab-a24fe678dc1f\">Optional: ship firmware in SquashFS if we pin a known-good bundle.</p></li></ul><p local-id=\"29ce97aa-7185-485a-9a26-d9fd95696d74\"><strong>Kernel policy</strong></p><ul local-id=\"a63b233b-3394-4059-a0b8-1a718cb8a175\"><li local-id=\"3c4fcbd7-210b-4f5a-9def-3183fabf5d75\"><p local-id=\"33494b97-0f6b-451b-bbe8-507eb3367aae\">Phase 1: use host-matched kernel ABI (or same kernel build) to reduce driver surprises.</p></li><li local-id=\"675cac75-8725-45c3-bef2-752da19527bf\"><p local-id=\"2d4e3872-445a-4fe3-9fef-9211678e8500\">Phase 2: allow guest kernel divergence once stable; require explicit compatibility validation.</p></li></ul><p local-id=\"f4010e6b-62ac-47f6-97bd-f43e8f62d955\"><strong>Known risks</strong></p><ul local-id=\"5ca84dd3-b523-4bd5-a17d-13331b80d93e\"><li local-id=\"c2bce945-0395-48dd-8a1d-c5f2e0bd6e1a\"><p local-id=\"b7da5d66-68fa-49f7-bf9a-3f38188ef7cf\">Hardware not reset; devices may be in non-default states.</p></li><li local-id=\"3b3bb37d-b677-454c-83ac-0f2f4cd21ebe\"><p local-id=\"c96adbd4-0eeb-4466-9e79-8525d8303b83\">Any NVIDIA stack mismatch between kernel/userspace/firmware becomes \u201cfun\u201d quickly.</p></li></ul><h3 local-id=\"aff69a74-68b2-4d10-a04d-4c647a7b421d\" id=\"Spec:BootingAlphaWithkexec-B)Congatechx86(RTLinuxhost,EtherCAT)\">B) Congatech x86 (RT Linux host, EtherCAT)</h3><p local-id=\"01cb97a3-21b9-4717-b2bb-b403f271ebbd\"><strong>Kernel policy</strong></p><ul local-id=\"a9badbba-31df-4536-b194-662adb6f3d37\"><li local-id=\"b70e1eb9-55a5-490d-acc0-f6bc913bdfdc\"><p local-id=\"bee14a13-ef47-4ca4-ba5d-ae06f40d8ee5\">Guest kernel must be RT-patched and configured consistent with EtherCAT requirements.</p></li><li local-id=\"36524e66-0e6a-4553-8e94-58b49b7a86ce\"><p local-id=\"36fc08a6-4515-4f02-a89e-ccc5c7e48ded\">Keep NIC driver, PTP, and any real-time settings in the guest image, not inherited magically.</p></li></ul><p local-id=\"a199c953-1dee-448c-ac5b-4c7f46e7a59c\"><strong>EtherCAT risk focus</strong></p><ul local-id=\"a54dea8e-bc38-4b1a-ac1f-4343be26ed99\"><li local-id=\"446cba81-d044-4de4-9cf1-07c5bcf973e4\"><p local-id=\"eebc6eed-5bf2-43dc-8acb-f647d2aa0e21\">EtherCAT masters/drivers often assume clean device init and deterministic timing.</p></li><li local-id=\"0d8412f5-e089-44fc-ab1a-a16bf592357e\"><p local-id=\"f45fda1a-46fd-4294-99a8-e8b9948cab6b\">kexec may leave NIC/PCIe/interrupt state \u201cwarm\u201d, causing:</p><ul local-id=\"d1423699-0a1c-44fc-8ab3-c4b53939b88f\"><li local-id=\"e0817868-0296-4965-b770-6dbc1681cfeb\"><p local-id=\"f7f2cdcd-a801-4baf-91cb-38d334aa469e\">missed link negotiation edge cases</p></li><li local-id=\"6c0bf5de-305b-4ec8-85f8-a18b5b97edff\"><p local-id=\"ba7c4d20-c180-4136-9c3f-5421ff3f0d96\">IRQ affinity drift</p></li><li local-id=\"a2f2299f-ca7f-4406-b1ba-91407d6bc1cf\"><p local-id=\"03518081-79e7-4ef9-a051-b92ca0263a8b\">DMA ring state confusion</p></li><li local-id=\"fe9f89c6-d7d3-46c0-af9b-7174e3d94c97\"><p local-id=\"79e2cd90-8bcd-4218-bc27-3fd864021c1d\">cycle jitter or DC sync instability</p></li></ul></li></ul><p local-id=\"8f473c73-d56e-49e7-b05d-013c1242fde1\"><strong>Mitigations</strong></p><ul local-id=\"3ed3c4e5-40b5-44c9-82bd-1b83e50b7df3\"><li local-id=\"aee85287-3eb3-4d87-afa7-b9a6dce46512\"><p local-id=\"505571fd-f8d8-4652-9ea2-00163657a7f4\">Before kexec (host):</p><ul local-id=\"fbf9b959-8f49-40a2-851c-c8686c5a6f4c\"><li local-id=\"03784c4a-9c5d-4b38-97dd-8e0694fd7265\"><p local-id=\"bf39f2e6-9d29-4225-97d2-c2dd166c174a\">stop EtherCAT master cleanly</p></li><li local-id=\"b1738e76-8a75-470c-9fcd-a45a3c67eadf\"><p local-id=\"44ccd931-7f81-497e-99ce-1b857d4f7c4f\">unload EtherCAT modules (if applicable)</p></li><li local-id=\"8654f447-d410-427e-9011-c4cb9386d1c8\"><p local-id=\"433dd55d-e858-43d1-ac90-8eac73110d46\">bring down relevant NIC(s)</p></li><li local-id=\"8b051e9f-659e-4d2a-b242-6da84f7e0e5b\"><p local-id=\"aa99b906-d818-4321-be74-8f168873cba0\">optional: reset NIC via <code>ethtool -r</code> / driver reload</p></li></ul></li><li local-id=\"1fcbe391-e7cf-4739-9095-2ed1ee4dc16a\"><p local-id=\"ff2c79c3-9214-4a3b-b62e-d5e310a20884\">In guest initramfs / early boot:</p><ul local-id=\"35dbd558-0fae-4369-86fa-1277e502f253\"><li local-id=\"1450dedc-1396-4add-b4c7-1987e3c2f7f6\"><p local-id=\"1fabbf22-46e0-455f-ac70-3fbe65d73cf7\">set IRQ affinities and CPU isolation deterministically</p></li><li local-id=\"ffdb47f6-910b-4ef7-b6c6-9de59adb95ec\"><p local-id=\"4caef276-742a-43b6-8e56-909af371b6a0\">re-init NIC link state before starting EtherCAT</p></li><li local-id=\"7c73c0da-99e7-484e-8cb5-da730d645e8e\"><p local-id=\"b47186a7-9fe9-48a5-b08f-9c3c0630f286\">enforce RT sysctls / <code>chrt</code> policies</p></li></ul></li><li local-id=\"49492f8a-54f9-4e1f-8315-9998903907dd\"><p local-id=\"915c818e-cfbd-42da-b9d0-814e12b02948\">Verification gates are stricter for x86 target (see below).</p></li></ul><h2 local-id=\"46faa2ca-9679-4a0b-837d-9f4b31a65db5\" id=\"Spec:BootingAlphaWithkexec-Deployment&amp;Integration\">Deployment &amp; Integration</h2><h3 local-id=\"9ca75816-0e09-4aa8-95fc-581ba2ed537e\" id=\"Spec:BootingAlphaWithkexec-HostComponents\">Host Components</h3><ul local-id=\"24ec58be-15e2-41bf-a6a0-e607a82336ed\"><li local-id=\"8e8202f4-4067-4031-9de6-344172edb1d6\"><p local-id=\"d61f39f7-fef3-4601-a78a-87408198555e\"><code>/usr/local/sbin/hmnd-kexec</code> (launcher CLI)</p></li><li local-id=\"7a8699a0-62bc-4f4c-9c1a-4fc2838f7442\"><p local-id=\"a45bc393-e526-4993-a443-6552b75f19ce\"><code>systemd</code> unit(s):</p><ul local-id=\"487e3bb3-211b-4bec-a25b-d0fdbed8f8d4\"><li local-id=\"d050faa2-f80e-4def-be19-b31d48678c48\"><p local-id=\"cc855b55-6770-43a6-903e-f4b4ad19095f\"><code>hmnd-kexec.target</code> (optional)</p></li><li local-id=\"5aaff08c-ac96-4018-838c-607bfdc4464b\"><p local-id=\"787dca8c-f212-4d04-a082-c3daffedfaba\"><code>hmnd-kexec.service</code> (runs kexec when requested)</p></li></ul></li><li local-id=\"5d361a9f-5b83-4f15-b88b-211ebf869041\"><p local-id=\"718abb84-7085-438b-9f43-687c269b837a\">Optional \u201creturn-to-host\u201d helper:</p><ul local-id=\"4cd9b7d9-ea4c-42a8-a864-3c1cc81646bc\"><li local-id=\"7b0201fb-7127-4a27-ac1a-67cb97357e3b\"><p local-id=\"796a4b7e-a62d-4137-9aed-abb7914aa387\">a guest-side <code>reboot --bootloader-entry=</code> is not assumed</p></li><li local-id=\"d31b7022-51b6-4e62-a26f-b987c251100a\"><p local-id=\"cca03d9a-2b21-4eb8-9e2b-1ef51613dcaf\">simplest: guest triggers plain reboot and firmware returns to host by default</p></li></ul></li></ul><h3 local-id=\"6c2c4920-aa93-4c3b-aa60-3d6b9278769f\" id=\"Spec:BootingAlphaWithkexec-GuestComponents\">Guest Components</h3><ul local-id=\"657bab41-2eb0-4918-9a9a-d107f3b936cb\"><li local-id=\"ab0b934e-b7df-440a-ae47-18baf0897083\"><p local-id=\"aa8c3d2b-3dd3-414a-9600-d4b0830138c1\">initramfs <code>/init</code> implementing the mount/overlay/bind/switch_root logic</p></li><li local-id=\"8e74d13e-658d-4f55-b47c-168a33ac7334\"><p local-id=\"5c1e3368-fc4d-48bd-9d75-ccef12a78369\">minimal debug tools in initramfs (busybox shell, mount, blkid, losetup, dmesg)</p></li><li local-id=\"c78f3751-9837-4db1-9b0f-a83eecb0e4fa\"><p local-id=\"ff27db20-7bea-4498-b381-247501e5d96b\"><code>/etc/hmnd/</code> and <code>/var/lib/hmnd/</code> treated as persistent bind mounts</p></li></ul><h3 local-id=\"c4a4341d-3982-476b-8962-b50717ac4646\" id=\"Spec:BootingAlphaWithkexec-ImageBuild(Bazel/CI)\">Image Build (Bazel/CI)</h3><ul local-id=\"535570f8-e5de-4b70-aba5-9c0bd94134f1\"><li local-id=\"3b1fd784-0d42-4f09-a474-5bfeda8c350c\"><p local-id=\"75fcc876-444d-4100-8a69-402468f3eb0c\">Build produces a versioned bundle:</p><ul local-id=\"2fab9298-7860-458e-b49d-ce67a68af16a\"><li local-id=\"62a34ba3-8686-44df-87be-e0dbe30af683\"><p local-id=\"a7f704e3-a381-4460-803a-f9e4a1688ec2\"><code>hmnd-guest-&lt;platform&gt;-&lt;version&gt;.squashfs</code></p></li><li local-id=\"35c91b9f-bcff-4fda-9080-531be5a8d436\"><p local-id=\"7dcf0f9b-9983-4836-a1d4-968c433c6521\"><code>vmlinuz</code>, <code>initramfs.img</code>, <code>manifest.json</code></p></li></ul></li><li local-id=\"59d2f337-2a8b-4ff6-9955-93d2a18609ac\"><p local-id=\"ef71824e-b2a2-4c33-ac08-177e879b07e4\">CI publishes artifacts to the robot host storage location.</p></li><li local-id=\"96b35d83-9fa5-4ee4-8496-53d4ea503fd4\"><p local-id=\"4b4a6394-afe6-4af5-a935-54671aced447\">Launcher selects bundle by version tag, \u201clatest\u201d, or explicit path.</p></li></ul><h2 local-id=\"eae6207e-dd54-4b37-bd8d-d8551f7cc75d\" id=\"Spec:BootingAlphaWithkexec-Observability&amp;Verification\">Observability &amp; Verification</h2><h3 local-id=\"2fb7d9dc-57a1-4dff-a3bd-cb6657853c2f\" id=\"Spec:BootingAlphaWithkexec-FunctionalTests(common)\">Functional Tests (common)</h3><ul local-id=\"0ee18398-340f-4e11-9698-44bfb9e47f1d\"><li local-id=\"e8cd5fab-ae7e-4323-8d83-9a5276b152da\"><p local-id=\"a150b2ba-fa16-430a-8764-e6562121d458\">Boot time: host \u2192 guest <code>switch_root</code> within target budget (e.g., &lt; 20s).</p></li><li local-id=\"842a8e54-9cd2-408f-a0fc-fdea621993db\"><p local-id=\"8189764b-b7fa-4e90-85a1-b17e3ab55fa2\">Persistence: values written to <code>/etc/hmnd</code> and <code>/var/lib/hmnd</code> survive across guest boots.</p></li><li local-id=\"98486d2c-8296-4b30-891e-903abfda1891\"><p local-id=\"b53ce0bf-ad3e-4aa5-884c-721c30faaa91\">Host cleanliness: after rebooting back to host, no filesystem corruption; services resume.</p></li></ul><h3 local-id=\"7395b2ab-6c29-441d-96d0-4ee9c7b658bf\" id=\"Spec:BootingAlphaWithkexec-Jetson-specificverification\">Jetson-specific verification</h3><ul local-id=\"421e9b4e-5d74-4789-8ca9-b619c9f42556\"><li local-id=\"acd6905e-c013-43e4-876a-ceb6a548c28e\"><p local-id=\"2d0c004f-b661-425d-9bbb-ec16fe4c87cd\">GPU sanity: run a minimal CUDA/NVDEC smoke test (or equivalent) post-boot.</p></li><li local-id=\"1503838c-2ab2-4877-ae6e-79a0805b911d\"><p local-id=\"f6052a9d-3569-4099-b522-5c075f8df6b9\">Firmware availability: confirm expected firmware files resolved from bound <code>/lib/firmware</code>.</p></li><li local-id=\"3d987180-b130-408a-a1e9-8b41b72e3d52\"><p local-id=\"384f9657-7da3-4bc2-ac4e-f3413bb3c5d2\">Device stability across repeated cycles: N cycles of kexec without requiring power-cycle.</p></li></ul><h3 local-id=\"4dfc3b67-3196-4965-96e6-04c601142339\" id=\"Spec:BootingAlphaWithkexec-x86EtherCATverification(majorgate)\">x86 EtherCAT verification (major gate)</h3><ul local-id=\"d504cb9d-0165-4646-9b8b-6bc3d8dec487\"><li local-id=\"8562925d-9685-474c-9bdf-21c394c87045\"><p local-id=\"f58da540-6f6f-45b1-98a9-d56b55e034d1\">Determinism: measure cycle jitter under load (CPU stress + network bulk).</p></li><li local-id=\"01ba58e0-a25b-45c4-8705-04f6bd21b04f\"><p local-id=\"d113905d-ea6c-4362-be7f-64e422da6fd4\">DC sync stability: no drift beyond threshold over duration.</p></li><li local-id=\"270d68f6-4330-4242-99d9-584203241776\"><p local-id=\"fb8f0301-66c2-4d26-9a45-f66261c6b108\">Link reinit reliability: repeated kexec cycles do not degrade link bring-up success rate.</p></li><li local-id=\"e46955f5-331a-4b1b-9a3b-59e78988bf39\"><p local-id=\"602f8502-87fa-498f-bc0e-f42c757acfdf\">IRQ and CPU pinning: validated post-boot (expected affinities, isolated CPUs, RT scheduling).</p></li></ul><h3 local-id=\"2a88aa50-ff57-4f34-aef4-575c5a17bd19\" id=\"Spec:BootingAlphaWithkexec-Diagnostics\">Diagnostics</h3><ul local-id=\"3f628d74-1bc2-4cf8-9164-2541f29ec55c\"><li local-id=\"0af0862d-ddd2-4cda-80e8-111569d0a5da\"><p local-id=\"a6fde2f8-20e9-4168-9cb1-a2b5ff57218a\">Initramfs logs to console with explicit step markers.</p></li><li local-id=\"78e4cfe5-b048-4d7e-baa1-7837915cdb37\"><p local-id=\"73c22a99-3120-4b5e-ad35-773e1fd4c38f\">On failure: drop to initramfs shell if <code>hmnd.debug=1</code>.</p></li><li local-id=\"afcfba68-d613-450c-ae85-2eec6d5c64e0\"><p local-id=\"0547a7d5-aed2-48d7-a5ba-6e41b53616e1\">Capture:</p><ul local-id=\"fec89186-2bfb-47e6-904b-f6ea47b7754e\"><li local-id=\"9f1f6a97-92e3-4417-b9a2-cf0f9b3041a6\"><p local-id=\"72ade391-7305-447b-a068-626392488eb5\"><code>dmesg</code> around kexec transition</p></li><li local-id=\"9941466c-8e9d-4033-9267-9125aaa0295d\"><p local-id=\"16a39617-163e-4a27-b1e2-d47d432d8292\"><code>journalctl -b</code> in guest</p></li><li local-id=\"baeadab7-308c-4f82-8f93-a0d25de31073\"><p local-id=\"7a891993-9b5b-46cf-a87a-739ab3b5e634\">on x86: <code>cyclictest</code>, EtherCAT master logs, NIC driver stats</p></li></ul></li></ul><h2 local-id=\"5415a649-52f1-442b-9cea-145374d198bc\" id=\"Spec:BootingAlphaWithkexec-Milestones\">Milestones</h2><p local-id=\"fdfc5eb0-39e2-4bd4-899d-2fb013afb4f8\">M1 \u2013 Prototype (both platforms)<br/>Deliverable: manual kexec into guest; initramfs mounts SquashFS and boots to systemd<br/>Verification: repeated boot works; persistence bind mounts functional</p><p local-id=\"9bf64fad-00c5-4cd3-a8a2-e00dbfd7a036\">M2 \u2013 Automation<br/>Deliverable: host launcher + systemd integration; versioned image selection<br/>Verification: kexec invoked reliably; logs available; no manual mount steps</p><p local-id=\"c10bee7a-bfff-460c-8e19-5628adecc1c1\">M3 \u2013 Jetson Stabilization<br/>Deliverable: DTB reuse path locked; firmware policy decided (bind vs ship)<br/>Verification: GPU/codec smoke test passes; N-cycle kexec stability</p><p local-id=\"73814bdd-9d0b-4b32-8097-43b79d66b1e1\">M4 \u2013 x86 EtherCAT Hardening<br/>Deliverable: pre-kexec teardown + guest early-boot NIC/RT setup; test harness<br/>Verification: EtherCAT jitter/DC metrics within thresholds across N cycles</p><p local-id=\"634cdd98-0a26-4dd3-b854-4e77291dda11\">M5 \u2013 Packaging &amp; Rollout<br/>Deliverable: packaged into robot host images; docs; \u201cknown bad\u201d safeguards<br/>Verification: field units can boot guest and report health; rollback path documented</p><h2 local-id=\"d1af50fa-3acd-43fd-af26-7155847af181\" id=\"Spec:BootingAlphaWithkexec-Risks&amp;OpenIssues\">Risks &amp; Open Issues</h2><ul local-id=\"72e105df-dc54-4298-99c4-09225e4e7bb5\"><li local-id=\"a28846c9-f2c6-4daa-bcf5-c2c0239095b9\"><p local-id=\"036856c9-24d5-4642-bee3-65d71b6e7b9f\">kexec does not reset hardware; some peripherals will occasionally wedge without a power cycle.</p></li><li local-id=\"42496817-e32a-43ba-8e2e-ba7f8c31459e\"><p local-id=\"bce8e161-722f-407f-a4d3-f507c1eff372\">Jetson DTB/carveouts: passing a custom DTB risks silent incompatibility; default is DTB reuse.</p></li><li local-id=\"37a63433-6a5d-40ff-8716-cf303f538926\"><p local-id=\"276a286c-0002-459f-907d-77fd6243a7a4\">NVIDIA userspace/kernel mismatch: binding host libs/firmware into guest can become ABI roulette if not pinned.</p></li><li local-id=\"b2aeb6e5-fd48-4031-92e8-da775ac469f5\"><p local-id=\"ace387be-651c-4ea2-ae89-2e50972e61d0\">x86 EtherCAT determinism: kexec warm state may break assumptions; requires aggressive verification and teardown/reinit.</p></li></ul><h2 local-id=\"104c2da7-11b4-4844-8485-d4c88e9e3962\" id=\"Spec:BootingAlphaWithkexec-Outcome\">Outcome</h2><p local-id=\"0db6ca8a-a6c4-4f88-93b7-bc3abcfcadc9\">Developers can boot a full robot stack as an immutable image in seconds without touching bootloaders or partitions. Jetson uses the host\u2019s DTB/firmware to minimize platform weirdness. x86 prioritizes determinism and EtherCAT correctness, with explicit teardown/reinit and hard gates on jitter and sync stability.</p>"
        },
        {
          "id": "1177911301",
          "title": "Spec: Wifi QoS",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1177911301",
          "last_modified": "2025-12-11T09:18:49.237Z",
          "created_at": "2025-10-22T21:45:34.884Z",
          "body_html": "<p local-id=\"ebe91305-ce69-4332-a372-ab9c6142fa76\"><strong>Spec: Robot Network QoS and Metrics Integration</strong><br/><strong>Owner:</strong> <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a> <br/><strong>Date:</strong> <time datetime=\"2025-12-08\" class=\"date-past\">08 Dec 2025</time> <br/><strong>Approvers:</strong> \u2014</p><hr local-id=\"bbd7d571-56d1-4c28-8cbf-e3ce371325ad\"/><h3 local-id=\"8632ee48-416a-42e8-9e48-18cd867d5fa9\" id=\"Spec:WifiQoS-ProblemStatement\"><strong>Problem Statement</strong></h3><p local-id=\"1ac4947d-9c45-4b76-ae9e-8bbd72042f3f\">Robot control and telemetry share the same uplink.<br/>Interactive sessions (SSH, UI) and realtime traffic (ROS 2 / teleop) compete with bulk data (logs, updates, downloads).<br/>This causes unpredictable latency spikes\u2014visible as control lag and WebRTC hiccups\u2014especially when bulk transfers saturate the link.</p><p local-id=\"7630b8ac-92ca-40bc-8814-0d52bb71e975\">We need deterministic local egress scheduling so critical flows retain low latency regardless of other activity.<br/>Additionally, these queues must be <strong>observable</strong> through our existing telemetry pipeline (Vector \u2192 Mimir/Grafana).</p><hr local-id=\"26726ee7-6b19-4ec6-85c5-1b6714ef86be\"/><h3 local-id=\"95ec187d-47d8-4fb7-b6aa-949b1d7e3449\" id=\"Spec:WifiQoS-Scope\"><strong>Scope</strong></h3><p local-id=\"7c3e2f86-ea85-4059-9c69-e3f07c2d55c7\"><strong>In scope</strong></p><ul local-id=\"97eab259-ec75-4c30-9c31-60e2c67c110c\"><li local-id=\"2707b61d-0a45-4503-b627-6015f1e23e15\"><p local-id=\"512ab6a1-8930-4846-9d5e-0912688408de\"><span class=\"inline-comment-marker\" data-ref=\"18397af3-1fbe-4d12-84f0-c130f06c698e\">Egress shaping on the robot\u2019s </span><strong><span class=\"inline-comment-marker\" data-ref=\"18397af3-1fbe-4d12-84f0-c130f06c698e\">external interface</span></strong><span class=\"inline-comment-marker\" data-ref=\"18397af3-1fbe-4d12-84f0-c130f06c698e\"> (</span><code><span class=\"inline-comment-marker\" data-ref=\"18397af3-1fbe-4d12-84f0-c130f06c698e\">eth0</span></code><span class=\"inline-comment-marker\" data-ref=\"18397af3-1fbe-4d12-84f0-c130f06c698e\"> / </span><code><span class=\"inline-comment-marker\" data-ref=\"18397af3-1fbe-4d12-84f0-c130f06c698e\">wlan0</span></code><span class=\"inline-comment-marker\" data-ref=\"18397af3-1fbe-4d12-84f0-c130f06c698e\">)</span></p></li><li local-id=\"9fdce328-d6d0-4c2b-a218-23c82bfcc27e\"><p local-id=\"c69b3339-3101-479e-b638-06b5c85c5948\">Local traffic classification into three service classes:</p><ul local-id=\"ccff002c-a6f8-4326-80a8-ecdc191120ba\"><li local-id=\"78f290e5-eb44-4810-adb5-97b7eaba1242\"><p local-id=\"1ef01d7d-ed23-4b23-a481-ac1b847d3eb7\"><em>Realtime</em> \u2013 ROS 2 UDP, WebRTC/teleop</p></li><li local-id=\"15b810c8-eee9-4aea-9bc0-7c8afea85c52\"><p local-id=\"e47ac40e-8587-4df7-a016-bfd4c90a6c51\"><em>Interactive</em> \u2013 SSH, Web UIs, WebSockets</p></li><li local-id=\"304502fc-acc3-47d0-a878-7332fc2b1932\"><p local-id=\"894242c5-6d83-44be-8a50-74ff60e60833\"><em>Bulk</em> \u2013 everything else</p></li></ul></li><li local-id=\"e68a18d5-7d58-41bc-9149-fe1c0dec0920\"><p local-id=\"fc509155-5afe-418c-959b-0baa40ad2189\">Deployment on Ubuntu systems managed by <strong>NetworkManager</strong></p></li><li local-id=\"a6c17938-7e97-4b16-94e1-0bcc06c7f19d\"><p local-id=\"bd5ab580-7f67-4653-b100-0eb154a3ee0d\">Export of queue utilization/drops to <strong>Vector</strong> for observability</p></li></ul><p local-id=\"5a679db9-693d-46c2-9453-adafe8ac57e5\"><strong>Out of scope</strong></p><ul local-id=\"151b3955-6b09-407f-a799-955425b4fed2\"><li local-id=\"616e79d3-8bbe-4586-8673-8b9a05ec0baf\"><p local-id=\"b8fd0639-880f-4c04-80b4-be6fe960c9dd\">Ingress shaping (handled later via IFB if required)</p></li><li local-id=\"ee1bca22-2c43-47fe-9924-9033f91e6d9f\"><p local-id=\"9876c339-08e4-41ae-9fbf-dea00dbb5f8c\">Preservation of DSCP markings beyond the host</p></li><li local-id=\"4aa4681b-22c3-4cbc-842d-3f47e05a8ddd\"><p local-id=\"b2946fee-34ce-49f7-8c8b-c687670fc044\">Per-container/pod shaping (handled by upstream orchestration)</p></li><li local-id=\"62536f01-f6d3-4e86-8fe9-09b926e5bb5f\"><p local-id=\"83c2c3af-c8ad-4b1f-b8b7-db72503e278e\">Remote or cloud QoS enforcement</p></li></ul><hr local-id=\"a530b017-dd31-4994-a89b-f23a13e9b110\"/><h3 local-id=\"c5453a9f-6015-4753-bb92-ded3cb4e8aa3\" id=\"Spec:WifiQoS-DesignOverview\"><strong>Design Overview</strong></h3><p local-id=\"ce5bf531-cd96-4f78-9cd3-827c03fd65e6\"><strong>Architecture</strong></p><ol start=\"1\" local-id=\"a55fb4a4-2cc3-43c5-a697-398d517afa1f\"><li local-id=\"6a61d73b-e651-488a-87c1-69e6dfc526f0\"><p local-id=\"65a20a39-5ce4-4c95-87e6-eaa7f5fbc887\"><strong>Classification (nftables)</strong></p><ul local-id=\"746037ca-0f04-40e2-a494-1bb9e82c2d7c\"><li local-id=\"c1ca731a-7167-4190-bf74-13e32be9b647\"><p local-id=\"7b21d427-3cdc-4dd2-b978-38071bfcbcb4\"><span class=\"inline-comment-marker\" data-ref=\"6022b02f-3425-4c88-ae6f-f8720eb43b90\">Chain </span><code>inet qos mark_out</code> in <code>OUTPUT</code> hook.</p></li><li local-id=\"70612f01-6e6d-4d9e-8cdf-42c19432ee6c\"><p local-id=\"4fc71ae7-a5b5-4f58-b30b-467d19ea8a52\">Marks packets:</p><ul local-id=\"5ee8c518-56cf-4749-abe9-e5588d0764e5\"><li local-id=\"2178b0e8-1817-4555-b50c-88e9d077a4e2\"><p local-id=\"d6d1d1ae-622b-4293-8fc5-d6dca02bb4e4\">UDP 7400\u20137550 + multicast \u2192 fwmark 10 (realtime)</p></li><li local-id=\"a8782de8-5691-468a-8d47-7393584c7369\"><p local-id=\"f952b9af-be29-4188-8565-98f9e295c9e9\">TCP 22 \u2192 fwmark 20 (interactive)</p></li><li local-id=\"58235c71-3a6d-4126-9433-b1c71af756dd\"><p local-id=\"e02bfc18-82be-4821-8788-a128447deee6\">All others \u2192 fwmark 30 (bulk)</p></li></ul></li></ul></li><li local-id=\"9bc0d5f7-9af1-4ac9-976e-c05f281da9a9\"><p local-id=\"269323b2-8ad7-475e-b740-ad69da54fcdd\"><strong>Scheduling (tc/HTB)</strong></p><ul local-id=\"f190067f-dba2-4516-af9f-ea11657afeb0\"><li local-id=\"548e28c8-0c78-424f-82ca-5f0d69debe54\"><p local-id=\"e769f1f2-305e-4e26-8086-2aadedccb91c\"><code>tc-qos.sh</code> creates three HTB classes on the external interface:</p><ul local-id=\"04a08f58-5a4e-4dbf-9d8b-d0bfdaff6a15\"><li local-id=\"1b6f9d7e-ca20-437d-bf2d-e7c5ace70a0c\"><p local-id=\"db03fc84-af9f-4671-98c8-aae160f3784c\"><code>1:10</code> Realtime (<span class=\"inline-comment-marker\" data-ref=\"a0f50414-a090-462d-9dc0-5dd062149e1a\">10 Mbit </span>min / full ceil)</p></li><li local-id=\"df8bdb29-df6b-4f41-87d5-2f7bf05896db\"><p local-id=\"9f369348-9695-4832-8222-6b8b7ae0265c\"><code>1:20</code> Interactive (10 Mbit min / full ceil)</p></li><li local-id=\"f85ac8e9-1a69-4a5a-9887-2a915c77d10c\"><p local-id=\"5f78dd57-d89c-4a54-9d08-7a088ef1cc43\"><code>1:30</code> Bulk (5 Mbit min / full ceil, lowest prio)</p></li></ul></li><li local-id=\"342cf7b0-0b6f-4fe2-9c87-0587179601f9\"><p local-id=\"7f9ab792-6181-4ecb-8512-4c1500493555\">Each class uses <code>fq_codel</code> for sub-queue fairness.</p></li><li local-id=\"ae09fd69-fbf6-4ea4-bdc7-a4d7e1ba48ce\"><p local-id=\"25a76bc9-4e4d-4333-851c-263448adcf21\"><span class=\"inline-comment-marker\" data-ref=\"94e23e22-615b-468c-8dd7-2012a18b8af8\">Filters match </span><code><span class=\"inline-comment-marker\" data-ref=\"94e23e22-615b-468c-8dd7-2012a18b8af8\">fwmark</span></code> values to direct packets to proper class.</p></li></ul></li><li local-id=\"6d993934-9668-4bce-80c9-e9b05257ff0a\"><p local-id=\"3bcfc50c-2f71-48ca-9036-0dd660ec5bb2\"><strong>Activation</strong></p><ul local-id=\"77ec74ab-7123-4224-a97c-adf973634c7c\"><li local-id=\"4169fb43-dbde-43ec-a1ab-d508dea057a7\"><p local-id=\"e5ef9159-6271-46bd-bab5-9432c2237746\"><code>/etc/NetworkManager/dispatcher.d/70-qos</code> executes <code>tc-qos.sh</code> on <code>up</code> event for the external NIC.</p></li><li local-id=\"075fb177-ed66-4ed3-b699-9b6801a7d192\"><p local-id=\"a3e741d2-e419-43cd-8650-a8289e304311\"><code><span class=\"inline-comment-marker\" data-ref=\"4c686c2b-93ae-4015-af6c-69abd435028d\">nftables.service</span></code><span class=\"inline-comment-marker\" data-ref=\"4c686c2b-93ae-4015-af6c-69abd435028d\"> ensures </span><code><span class=\"inline-comment-marker\" data-ref=\"4c686c2b-93ae-4015-af6c-69abd435028d\">mark_out</span></code><span class=\"inline-comment-marker\" data-ref=\"4c686c2b-93ae-4015-af6c-69abd435028d\"> chain is loaded at boot.</span></p></li></ul></li><li local-id=\"a17dd835-709b-4a78-a275-a8f82f524463\"><p local-id=\"fb3f3416-33c3-4943-8b9c-e53686c438a8\"><strong>Observability (Vector exec source)</strong></p><ul local-id=\"dcab8a75-93fe-49a5-889f-5eeedfc62599\"><li local-id=\"4f0a8fcd-8233-487f-91ef-54498497ac7a\"><p local-id=\"deaf9879-1ff6-4c14-9009-26af6582b1da\">Vector runs <code><span class=\"inline-comment-marker\" data-ref=\"c878cf2a-b438-44d2-96b2-6f2ed72a035e\">tc -s qdisc show dev eth0</span></code> every 30 s.</p></li><li local-id=\"bb7e35ef-9984-4660-9fbf-c33ab16f8894\"><p local-id=\"ee57657e-3a75-474d-9b72-a99aed7999fc\">A transform parses counters (<code>Sent</code>, <code>dropped</code>) into Prometheus-style metrics:</p><ul local-id=\"6b8f045e-6ad5-46da-8a98-6f9579c9e88b\"><li local-id=\"34dcd24a-4172-4ab2-9900-81a961fdb13c\"><p local-id=\"00c05ec2-aca3-470d-be4b-944975832f3f\"><code>tc_packets_total{class=&quot;10&quot;}</code></p></li><li local-id=\"d6089d9d-a94e-40cf-b0ca-3e78b200a09f\"><p local-id=\"81504bd8-3111-4dde-a5c0-1af8e47d441b\"><code>tc_drops_total{class=&quot;10&quot;}</code> etc.</p></li></ul></li><li local-id=\"60d4bddc-33c8-4037-8eff-8ad7be930ebe\"><p local-id=\"d51f3c53-0a77-451d-bb77-f87d385af361\">Mimir/Grafana dashboards visualize queue load and drop rates per class.</p></li></ul></li></ol><hr local-id=\"72ea7ebc-c5e1-4fc5-9302-eba035b1b744\"/><h3 local-id=\"adf1d2fc-b57f-4856-8cbc-2b66776f3f92\" id=\"Spec:WifiQoS-Milestones\"><strong>Milestones</strong></h3><div class=\"table-wrap\"><table data-table-width=\"1800\" data-layout=\"default\" data-local-id=\"70d10ad6-7771-4469-968e-4a6cdccf15d6\" class=\"confluenceTable\"><tbody><tr data-local-id=\"4fbe0570-f3b5-45ce-8060-1aa6738b980b\"><th data-local-id=\"b62db41c-7f46-4ab9-81ae-cc3afbfaf9c0\" class=\"confluenceTh\"><p local-id=\"237a3a78-1d5a-4441-a4f5-063f6e32cff5\">Phase</p></th><th data-local-id=\"0739a72d-619a-41a4-b5aa-d2410f4a0053\" class=\"confluenceTh\"><p local-id=\"ba7841ee-4366-4988-9232-b331749b3063\">Deliverable</p></th><th data-local-id=\"6eeb16cf-7ce4-48d4-a312-fd9cfddefee6\" class=\"confluenceTh\"><p local-id=\"780e5331-e8d4-4235-a20d-38a27e4f11c9\">Verification</p></th></tr><tr data-local-id=\"0990fbe2-761f-484f-8c3e-44a0c10ae676\"><td data-local-id=\"a1351c33-9247-4a24-ac77-f2e5503d1f73\" class=\"confluenceTd\"><p local-id=\"d0395558-28a7-4207-9c9e-f2e845462784\"><strong>M1 \u2013 Prototype</strong></p></td><td data-local-id=\"d9a7bff9-9d73-4aaf-895a-d7d32abada25\" class=\"confluenceTd\"><p local-id=\"694f863e-6034-4487-a509-0345a4f622fd\">Working manual setup of nftables + tc on dev robot</p></td><td data-local-id=\"2a9de60e-e144-475a-bff7-b2d40c54ef1e\" class=\"confluenceTd\"><p local-id=\"222cd2ab-5eb9-4e18-8f56-d90eecc38731\">Ping RTT under 50 ms with bulk flood active</p></td></tr><tr data-local-id=\"7e37ca43-adc7-415b-a5ca-e093dd62ba61\"><td data-local-id=\"0a6113de-c561-4bd2-b358-b18d0e0cc71e\" class=\"confluenceTd\"><p local-id=\"b4d25c33-fbac-48b4-919c-5aac94558d11\"><strong>M2 \u2013 Automation</strong></p></td><td data-local-id=\"9bbcb4b3-e956-4bb3-a495-b54351057c65\" class=\"confluenceTd\"><p local-id=\"40bbf168-7875-481d-9493-1a818c8afd46\">Dispatcher script auto-applies rules on interface up</p></td><td data-local-id=\"487809b5-2a84-41a8-a803-6ac242663124\" class=\"confluenceTd\"><p local-id=\"d3fca189-2e5c-4aa0-8dff-36100626fa4f\"><code>tc qdisc show dev eth0</code> persistent after reboot</p></td></tr><tr data-local-id=\"5f53d3d8-9f42-4141-85e7-0bd59b641992\"><td data-local-id=\"3cf202ba-9541-4999-b698-99a7cdbdb1b8\" class=\"confluenceTd\"><p local-id=\"850f9e28-948d-44f7-94f3-70d577379b9a\"><strong>M3 \u2013 Observability</strong></p></td><td data-local-id=\"24c72592-2b3e-49fb-8670-39e53655bbe3\" class=\"confluenceTd\"><p local-id=\"c74dd13e-772f-44da-b109-1ee6dee5555f\">Vector collects and forwards metrics</p></td><td data-local-id=\"37344af2-08ce-4095-ba6b-1c6086e6e189\" class=\"confluenceTd\"><p local-id=\"2665cc2a-2731-4cff-a02e-3bbfa266f89e\">Metrics visible in Grafana dashboard</p></td></tr><tr data-local-id=\"b43dd910-c1ce-4ff8-b888-dfc30f726833\"><td data-local-id=\"ba867987-182e-4243-90cd-46c461d6b3ab\" class=\"confluenceTd\"><p local-id=\"73dd2bed-6f87-4c39-a68f-f1e083a3aa24\"><strong>M4 \u2013 Rollout</strong></p></td><td data-local-id=\"af58b613-d7d9-4fbd-a5ca-f06a3fe93ea0\" class=\"confluenceTd\"><p local-id=\"f9473011-a6c0-4071-ad9e-2727566ba12f\">Systemd/NM integration packaged in robot image</p></td><td data-local-id=\"b377ad0c-30e0-40d8-abcd-f73935191d4c\" class=\"confluenceTd\"><p local-id=\"fb77594b-c88d-415f-86fb-632c8e1b9c80\">All field units report queue metrics</p></td></tr><tr data-local-id=\"1c25289e-3489-4b6e-a780-160c0c9d65f4\"><td data-local-id=\"075f24e4-c876-420a-83ba-311011318b9e\" class=\"confluenceTd\"><p local-id=\"f1addbd5-610f-462a-a24e-82bdbe1b4c1f\"><strong>M5 \u2013 Optimization</strong></p></td><td data-local-id=\"85fc2781-9830-44ef-b875-51fa33001e77\" class=\"confluenceTd\"><p local-id=\"ced532b6-efce-4820-be00-7daf2385663c\">Tune rates per bandwidth profile</p></td><td data-local-id=\"2533494e-cbd6-4c9e-9dda-6af8afeb313b\" class=\"confluenceTd\"><p local-id=\"5d81bfec-5a66-44ff-9062-51e8b1086fb0\">Realtime jitter &lt; 20 ms under 80% link load</p></td></tr></tbody></table></div><hr local-id=\"c70cec7c-580c-44b4-af1b-d72abc23f1ca\"/><h3 local-id=\"3cc70250-e77c-46c9-bf1b-eb344200b083\" id=\"Spec:WifiQoS-Observability&amp;Verification\"><strong>Observability &amp; Verification</strong></h3><ul local-id=\"9324df00-a154-4fd7-ba45-f40adb2c7011\"><li local-id=\"820a2f75-bdb7-4ebb-b725-c59ff2ceac68\"><p local-id=\"14871804-270d-4bdf-bb5f-2a79207e6e90\"><strong>Functional Tests</strong></p><ul local-id=\"2690dbb6-cf92-4989-9d33-2fe5857447b9\"><li local-id=\"a70f3193-905b-4c32-a3d4-ce2b41f525b4\"><p local-id=\"9e5341fc-0046-44f7-8433-d513dd22cc0e\">Bulk transfer (e.g., <code>iperf3</code>) should not elevate RTT of ROS 2 UDP pings.</p></li><li local-id=\"1f2b0d61-4a11-4a11-9003-2cbf924477f0\"><p local-id=\"1775552e-edfc-4bbb-bf31-b1c61b8ed44b\">SSH remains responsive under heavy download/upload.</p></li></ul></li><li local-id=\"08ea41ea-bd02-4da0-9927-7c5f28c2e1a4\"><p local-id=\"d24f7721-f245-42d6-88a7-6b4aacb9368c\"><strong>Metrics</strong></p><ul local-id=\"a2d550f2-91f6-4c9b-a19e-f214ec869a02\"><li local-id=\"126176d9-b86b-4af7-824d-0de060c7121b\"><p local-id=\"2d8ffd18-0c71-4fbf-8ee7-f0f42861fc41\"><code>tc_packets_total</code> and <code>tc_drops_total</code> increase monotonically.</p></li><li local-id=\"3f6d6ae9-e71b-4abd-b8a3-6d378ac22434\"><p local-id=\"c2822942-fdf3-4930-a96c-97c81df830e0\">Drop rate of realtime class \u2248 0; bulk may drop under saturation.</p></li></ul></li><li local-id=\"6f138733-4b63-4db1-ac8c-17727786cf8e\"><p local-id=\"2f6f0197-6c5e-4b9a-88bc-79d875b5a30a\"><strong>Dashboards</strong></p><ul local-id=\"322c88cf-af0b-4a80-b049-27cda9cd625f\"><li local-id=\"ec2285e0-dc84-4843-9081-1fdf9c817b8e\"><p local-id=\"73a1bdfa-cbc1-4253-a91a-258846b472c0\">Grafana panels: per-class throughput, latency histograms, drop counters.</p></li><li local-id=\"433b7578-334f-4e0a-aecf-0a628ee837d5\"><p local-id=\"efa63046-26f3-461a-9b31-62d15d3157f6\">Alert when realtime queue drops &gt; 0 or delay &gt; 50 ms.</p></li></ul></li><li local-id=\"3fa0dd88-25da-49fa-9aa0-ff74174d785f\"><p local-id=\"de87ec74-38bc-479f-9559-aba6788a7e61\"><strong>Logs</strong></p><ul local-id=\"eb855c58-24bf-445a-b361-1b72ee637eb2\"><li local-id=\"835b46fa-4fb7-4ee9-9543-308e391c8fdb\"><p local-id=\"55e61938-3d38-4e97-95f1-1630c115b5e9\">Vector logs confirm successful <code>exec</code> scrape every 30 s.</p></li><li local-id=\"2ba8e92e-5e60-4a7e-a765-d05be90033d4\"><p local-id=\"4f34b3e1-4c15-4a2f-a4a1-fbe0f1f07650\"><code>nft list ruleset</code> and <code>tc -s qdisc</code> exported for troubleshooting.</p></li></ul></li></ul><hr local-id=\"e34f6ac6-3660-415a-bf15-bf59ad192e7e\"/><h3 local-id=\"f2e16f4f-831c-4e49-8c0b-deeb4713eafb\" id=\"Spec:WifiQoS-Appendices\"><strong>Appendices</strong></h3><h4 local-id=\"f7d185b1-8696-4ac1-9fb7-542a6ac9d15f\" id=\"Spec:WifiQoS-A.nftablesruleset\"><strong>A. nftables ruleset</strong></h4><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"6e719712-9ed4-414d-bde3-0b55851bdda6\" data-local-id=\"4865bbe6-893d-436f-9a1f-7016776227a2\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">table inet qos {\n  chain mark_out {\n    type route hook output priority mangle; policy accept;\n\n    # ROS 2 / DDS UDP ports\n    udp dport 7400-7550 meta mark set 10\n    udp sport 7400-7550 meta mark set 10\n    ip  daddr 224.0.0.0/4 udp meta mark set 10\n    ip6 daddr ff00::/8 udp meta mark set 10\n\n    # SSH\n    tcp dport 22 meta mark set 20\n    tcp sport 22 meta mark set 20\n\n    # Default\n    meta mark 0 meta mark set 30\n  }\n}\n</pre>\n</div></div><h4 local-id=\"2b6eda66-ad3f-4f3a-a0db-7ce5a455844a\" id=\"Spec:WifiQoS-B.tcsetupscript\"><strong>B. tc setup script</strong></h4><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"8e9f4ad2-b572-45a6-a655-37a32e4eaf8e\" data-local-id=\"c2e411e1-6943-445f-adcb-dfe630fd6cee\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">#!/usr/bin/env bash\nset -euxo pipefail\nIF=$1\nUP=100mbit\n\ntc qdisc del dev &quot;$IF&quot; root || true\ntc qdisc add dev &quot;$IF&quot; root handle 1: htb default 30\ntc class add dev &quot;$IF&quot; parent 1: classid 1:1 htb rate $UP\n\nfor class prio rate in &quot;10 0 10mbit&quot; &quot;20 1 10mbit&quot; &quot;30 2 5mbit&quot;; do\n  read c p r &lt;&lt;&lt;&quot;$class prio rate&quot;\n  tc class add dev &quot;$IF&quot; parent 1:1 classid 1:$c htb rate $r ceil $UP prio $p\n  tc qdisc add dev &quot;$IF&quot; parent 1:$c handle ${c}: fq_codel\ndone\n\nfor proto in ip ipv6; do\n  for h in 10 20 30; do\n    tc filter add dev &quot;$IF&quot; parent 1: protocol $proto handle $h fw flowid 1:$h\n  done\ndone\n</pre>\n</div></div><h4 local-id=\"29de260d-3445-4b74-90e2-c80591ee5af3\" id=\"Spec:WifiQoS-C.NetworkManagerhook\"><strong>C. NetworkManager hook</strong></h4><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"c4fbe672-73c6-47d0-8636-23b765bea63e\" data-local-id=\"3fbc5235-6921-4a3a-ac8d-e2ec6a34a82d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">#!/usr/bin/env bash\nIF=&quot;$1&quot;; ACTION=&quot;$2&quot;\nif [[ &quot;$IF&quot; == &quot;eth0&quot; &amp;&amp; &quot;$ACTION&quot; == &quot;up&quot; ]]; then\n  /usr/local/sbin/tc-qos.sh &quot;$IF&quot;\nfi\n</pre>\n</div></div><h4 local-id=\"f73a7758-b5e0-4365-9541-ad3e83c7990b\" id=\"Spec:WifiQoS-D.Vectorsource\"><strong>D. Vector source</strong></h4><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"639dd85b-baa4-47e4-a452-b2a83ddf60d9\" data-local-id=\"c5be216d-018f-4a04-8106-3f502839bf33\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[sources.tc]\ntype = &quot;exec&quot;\ncommand = [&quot;/usr/sbin/tc&quot;, &quot;-s&quot;, &quot;qdisc&quot;, &quot;show&quot;, &quot;dev&quot;, &quot;eth0&quot;]\ninterval_secs = 30\n</pre>\n</div></div><h4 local-id=\"407ddf50-2d1f-4626-a33f-8fb47b532f56\" id=\"Spec:WifiQoS-E.Verificationcommand\"><strong>E. Verification command</strong></h4><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"174e9651-2d42-46e2-b3e4-178558950e55\" data-local-id=\"18fe5e12-6947-4142-97a1-a318d526381a\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">watch -n 1 'tc -s qdisc show dev eth0'\n</pre>\n</div></div><hr local-id=\"f20ade45-ffec-4735-a56b-dd63baa6d152\"/><p local-id=\"905dd576-ed0f-470a-8a8f-79e4c7b23eef\"><strong>Outcome:</strong><br/>The robot now enforces deterministic outbound traffic priority. ROS 2 and teleop stay crisp even during bulk uploads. Queue stats flow into Vector, making QoS both visible and tunable without SSHing into the robot.</p>"
        },
        {
          "id": "1372160012",
          "title": "Robot Mapping and Deployment",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1372160012",
          "last_modified": "2025-12-03T15:28:05.670Z",
          "created_at": "2025-12-03T11:45:47.927Z",
          "body_html": "<p>We\u2019ve had a number of discussions around how to deploy robots.  This is my attempt to put together a strawman end-to-end deployment scenario.  This will be heavily influenced by my prior experience with deploying AMRs into commercial spaces, but looking forward torwards a solution that is more agentic and AI-driven.</p><p><strong>Deployment</strong></p><p>What is deployment?  There is the physical aspect: shipping the robot, uncrating it, charging it for the first time.  There is the security aspect: adding certificates, keys, identities.  We\u2019ll ignore these (very real, still difficult) problems for now and focus on the actual \u201csetup\u201d portion.  This involves a few key things:</p><ol start=\"1\"><li><p>How does the robot learn its environment?</p></li><li><p>How does the robot know what to do?</p></li><li><p>How does the robot know where to do it?</p></li></ol><p><strong>Deployment Anti-Pattern</strong></p><p>I don\u2019t know why, but the usual pattern for deployment is to create some sort of sprawling interface.  Something generates a map, and then operators are expected to draw paths and waypoints on some GUI, draw no-go zones, etc on the interface to adjust the robot\u2019s workflow.</p><p>This is kinda miserable in practice.  For one, operators are manipulating an abstract model of the robot\u2019s environment/workflow and it takes a lot of specialized skill to be able to do this correctly.  Consider a scenario where a robot takes a corner \u201cimproperly\u201d.  Maybe it\u2019s going too wide or too sharp - the details are unimportant for this example.  We want to adjust the path.</p><p>The \u201cclassic\u201d way this is done is to draw a new waypoint.  But this is easier said than done.  You see the robot do a thing physically, but now you need to move to an abstract representation.  You need to know where to click to add the waypoint.  You may need to adjust/re-orient the waypoint if you need directional constraints.  If the workflow is complicated, you need to be mindful about topology - adding a new waypoint into the middle of an existing path can be difficult when there are many overlapping/looping paths in the area.  Finally, once the workflow is adjusted you need to go BACK to the robot to re-execute and hopefully it works.  <em>Miserable</em>.</p><p><strong>Humanoid Deployment</strong></p><p>From prior experience, I\u2019ve learned its best to close the gap between deployment and operation of the robot as much as possible.  Having operators shifting between real-world context and abstract \u201cUI\u201d context of waypoints and no-go zones is extremely challenging in practice.  So let\u2019s make some assumptions:</p><ul><li><p>we have teleoperation - we can move and manipulate via teleoperation</p></li><li><p>we have SLAM - we can map a space (and get an initial mapping trajectory - important for later)</p></li><li><p>we have policy execution</p></li></ul><p>We have 2 of these 3 accessible from \u201cSockpuppet\u201d - so let\u2019s pretend for a moment that our mapping is available there too.  Now we have a \u201cdeployment tool\u201d.  Note that This assumes we have some sort of teleoperation setup available - but another approach would be a local display and a torque-assisted robot that allowed you to physically move it through the space manually.  We\u2019ll consider this an implementation detail.  What\u2019s important is that we have a way to control robots manually in the actual environment.</p><p><strong>Mapping and Setup</strong></p><p>When we first show up in a new environment, we should position the robot at some initial pose and beginning the mapping process.  The robot should then traverse the environment (hopefully uncovering the space) and then we should return back to that initial pose to save the map.  This is a very important detail, as it gives us a free loop closure constraint.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"600\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1372160012/Untitled%20Diagram-1764767332555.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1372160012/Untitled%20Diagram-1764767332555.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p>Now we have a map, and we have an initial spline loop where both the beginning and end pose are our known initial pose.</p><p><strong>Editing</strong></p><p>So our robot starts at our initial pose, and let\u2019s assume for this example we need to take totes from the ingress table (on the right) and place them on the egress table (on the left).  We can start the robot at its initial position, and then enter \u201cdeployment mode\u201d and teleop the robot to the table on the left and add a new waypoint.  Now we have a looping spline between these two waypoints.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"600\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1372160012/1764767747998-Untitled%20Diagram-1764767332555.drawio.png?api=v2&amp;version=3\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1372160012/1764767747998-Untitled%20Diagram-1764767332555.drawio.png?api=v2&amp;version=3\" loading=\"lazy\"></span><p>Now we can start the robot at its initial pose, and we can expect the robot to navigate to the ingress table, and then return back to our initial pose.  We have two waypoints now - w0 (our initial pose) and w1 (the ingress table).  We can choose to label or name a waypoint to turn it into a \u201ckeypoint\u201d (point of interest) which we can use within our workflow.  Keypoints are \u201clocked\u201d which we will see is important for the next step.</p><p>When we teleoperate the robot to the keypoint and save it, we can also tell the robot to run a policy - \u201cpick up the tote\u201d.  This saves a workflow transition in addition to our mapping data, so that the robot knows that when its at the ingress keypoint its supposed to run the policy.</p><p>Then we can teleoperate the robot to the egress table, save a keypoint, and tell the robot to \u201cput down the tote\u201d.   but here, something else happens.  You could see how if we add many keypoints and waypoints, our path will become complex and unpredictable.  Editing will get more and more difficult.  We want to keep a light touch.  Our initial pose is still \u201cjust\u201d a waypoint.  An implicit one at that.  When we drop a new waypoint at the egress table, we can look at any waypoints close by in the path and remove them, simplifying the path and keeping things manageable over time.  If we don\u2019t want a waypoint to be dropped, we simply lock it by giving it a name (turning it into a keypoint).</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"600\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1372160012/1764767747998-Untitled%20Diagram-1764767332555.drawio.png?api=v2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1372160012/1764767747998-Untitled%20Diagram-1764767332555.drawio.png?api=v2\" loading=\"lazy\"></span><p>The radius/distance that we clear waypoints can be configurable of course.  But at this point, without ever opening up a map editor or clicking, we\u2019ve managed to tell the robot about two key points and that it should run policies at each point.  Under the hood this involves inferring our map waypoints/keypoints, and inferring some states in the workflow (before policy/after policy) and transitions (our pick/place policies and navigation).</p><p><strong>Rewind and Constraints</strong></p><p>Let\u2019s assume that we add some new static obstacle to the environment.  Its positioned in a way that SOMETIMES the planner tries to navigate above it, which risks blocking access and causing robots to get stuck.  The robot could be stopped during this (go into teleoperation/manual mode) and then we could \u201crewind\u201d the robot by moving backward through the trajectory until the robot is back at the table.  Then we could teleoperate the robot to the proper side of the obstacle, add a waypoint, and then resume.  Now the robot will reliably and consistently pass on the proper side of the obstacle.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"600\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1372160012/1764770954698-1764767747998-Untitled%20Diagram-1764767332555.drawio.png?api=v2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1372160012/1764770954698-1764767747998-Untitled%20Diagram-1764767332555.drawio.png?api=v2\" loading=\"lazy\"></span><p>In my opinion, this \u201crewind\u201d is a killer deployment feature.  Without it, you have to somehow remember what the robot did incorrectly, then navigate to your map editing tool, somehow make the fix, then re-run the workflow.  With it, you can scrub back and forth along the workflow.  This scrubbing can be used as a quick check of new waypoints immediately (add the waypoint, move backward to see how it constrains the approach, and through it to see how it constraints the follow-through)</p><p><strong>Snap and Edit and Versioning</strong></p><p>As the robot progresses through its workflow, we can show the current waypoint/workflow state/transition.  If the robot starts doing something wrong (perhaps its following an older, stale waypoint or its generated some unconstrained path), the operator can enter deployment mode and scrub forward or backward to see which waypoints are influencing the current action.  Those waypoints can then be modified (their properties, not their pose) or deleted right there with full context.</p><p>There are two orders of waypoints that are important to keep in mind.  The version (basically ordered by timestamp) and the index (basically ordered by arclength through the spline).  If we keep a full log of all edits, operators can easily version control the workflow and undo changes.  By relying on the robot\u2019s position to act as a cursor through the index (its currently position along the workflow), its easier to make sure that waypoints are \u201cinserted\u201d into the existing path while preserving the topology.</p><p>Over time our map may need to be regenerated.  As long as we can maintain some number of fixed loop closures (most of our workflows will be cyclic in some way), we should be able to regenerate maps.  This is a whole area of research, and will depend on the underlying mapping/localization stack, but I just want to highlight the possibility that this is handled automatically.</p><p><strong>Branching and Looping</strong></p><p>More sophisticated workflows may involve the robot needing to \u201cbranch\u201d from a waypoint.  For example, some inspection-related policy may result in good or bad results, with good being placed to the left, and bad being taken to some bin on the right.  When entering deployment mode at a waypoint, the robot can simply be operated in another direction and the new waypoint saved, with the branch being inferred.</p><p>This is probably the area where this  \u201cimplicit\u201d approach becomes most difficult - we need to capture the branching/looping nature in the workflow but its not clear how this could be done purely with a local interface like this.  What\u2019s most important to capture with the robot is the physical pose of the waypoints to ensure that the various constraints are created, and to allow the incremental editing of the existing paths.  Its possible that more complex looping or branching-type workflows will require another pass within the fleet mgmt editor itself.  Who knows?</p><p><strong>Policy and Agentic Deployment</strong></p><p>As mentioned in some other places, there is a tension that exists between more policy-driven approaches and more \u201cclassical\u201d constrained approaches.  Classical approaches are more predictable, and can fit into existing rigid workflows more easily, but don\u2019t adapt to exceptional special cases very well.  Policy-driven approaches are extremely adaptable and flexible but may not always do what customers need or may be difficult to integrate with other more rigid processes.  Hopefully here we can split the difference.</p><p>We should be able to allow deployment operators to stitch together complex end-to-end workflows from well-supported policies and behaviors.  In turn, the end-to-end execution of these workflows can be used to train longer-horizon policies which incorporate the necessary constraints.  The hope (and it is just a hope) would be that very dense, complex workflows and deployment schemes could be made less granular over time as policies become more capable.  Instead of \u201cgo to ingress\u201d, \u201cpick up tote\u201d, \u201cgo to egress\u201d, \u201cplace tote\u201d we should be able to run \u201cpick up totes from the ingress table and take them to the egress table\u201d.  Easier said than done.  Similarly we could do RL on a reasoning model based on these workflow traces to get more predictable workflows.</p><p>Another possible use of AI during deployment would be scan documents describing SOPs and building the initial scaffold of the workflow.  The keypoints could be extracted from the SOP so that the interface has a list of them ready to go, along the deployment tool to guide the operator through the setup with a bit less friction.  </p><p><strong>Summary</strong></p><p>I think what\u2019s outlined here is a viable deployment scenario that allows operators with full situational awareness (via manual or teleoperation) to incrementally evolve the workflow without being burdened by the challenges of rapidly flipping between real operations and an abstract map view of the workflow.  Operators can scrub forward and backward through time to insert new waypoints to constrain navigation so that we can run policies and navigate predictably through customer sites.</p><p>\u201cBut Cody - we won\u2019t be using lidar maps or stone-age SLAM methods forever\u201d.  Yep.  But I think we must provide an easy way for deployment teams to constrain navigation in order to reliably work in real-world environments.  A deployment tool that\u2019s very \u201cmap centric\u201d will effectively REQUIRE some sort of map view to be edited, which I think is more constraining to our navigation and perception efforts.  An implicit deployment scenario outlined here doesn\u2019t really care about specifics - only that the robot knows where it is (some map pose), and which waypoints need to be satisfied in which order (index order not necessarily the order the waypoints were created).  Obviously we\u2019d need to think about this in the context of VIO and more policy-driven approaches to navigation but that\u2019s why I\u2019m writing this down.<br/><br/><strong>Questions </strong><br/>- How would you propose we mark speed zones or would this be automatic? - <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:41bbdf45-4569-47b4-a70e-75a413336dfc\" href=\"https://sklvc.atlassian.net/wiki/people/712020:41bbdf45-4569-47b4-a70e-75a413336dfc?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"758972465\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Jack Smith</a> <br/>-How would we mark no go zones? - <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:41bbdf45-4569-47b4-a70e-75a413336dfc\" href=\"https://sklvc.atlassian.net/wiki/people/712020:41bbdf45-4569-47b4-a70e-75a413336dfc?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"758972465\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Jack Smith</a> <br/></p>"
        },
        {
          "id": "1170341889",
          "title": "Spec: HMND Fleet Control Plane",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1170341889",
          "last_modified": "2025-12-02T14:52:42.444Z",
          "created_at": "2025-10-21T08:37:31.823Z",
          "body_html": "<p><strong>Summary</strong>: Local Fleet-centric Control Plane for Robot Coordination</p><p><strong>Owner</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a> </p><p><strong>Date</strong>: <time datetime=\"2025-10-21\" class=\"date-past\">21 Oct 2025</time> </p><p><strong>Approvers</strong>: </p><p><strong>Informed</strong>: </p><p><strong>Related</strong>: </p><p><a href=\"/wiki/spaces/ROBOT/pages/1151303693/Spec+HMND+Core+Control+Plane\" data-linked-resource-id=\"1151303693\" data-linked-resource-version=\"8\" data-linked-resource-type=\"page\">Spec: HMND Core Control Plane</a> </p><h2 id=\"Spec:HMNDFleetControlPlane-ProblemStatement\">Problem Statement</h2><p>When many robots are operating within a single operational zone, perhaps collaborating on the same workflow, the existing behavior-tree model of our applications begin to fall short:</p><ul><li><p>Maps only exist local to the robot - we have no way to share them.</p></li><li><p>We have no way to coordinate behavior tree progress between robots.</p></li><li><p>Behavior trees cannot really be analyzed to exploit concurrency or identify bottlenecks.</p></li><li><p>Defining behavior trees requires modifying application code and lengthy build-test-release cycles.</p></li></ul><p>Even just a few robots operating in a small area can cause things to get clogged up.  There may only be space at a table for one robot to pick up one tote.  Or there may only be space in one aisle for one robot to pass at a time.  We need shared maps and workflows within which robots can coordinate.</p><p>We also need our robots to possibly integrate w/ customer-managed systems like WMS, point-of-sale/orders or anything else that may require additional context for how robots ought to coordinate their work.  We need to be able to accept work items from some external system, and report progress events to these same external systems.</p><p>Another major challenge (maybe specific to short-term realities within Humanoid) is running demos across a small pool of Alpha hardware.  For a demo which needs to run across multiple robots, it will become unbearably difficult to manually recover/setup each robot before demos.  This will become even more painful if these robots need to be used for other demos or PoCs, resulting in significant development and configuration churn.</p><p><strong>Why not a completely agentic fleet manager?</strong></p><p>In a perfect world, business operations would be scripted by simple rules and nothing would ever go wrong.  Just move the items from A to B.  Forever.  These rules are easy to describe (and thus specify in some business process).  But everything fails all the time.</p><p>Instead, we can write the happy path as some rigid workflow, and then call out to an agent or any other 3rd party API to keep things moving when exceptional scenarios arrive.  Exceptional doesn\u2019t mean rare, so very powerful agents could significantly improve process throughput.</p><p>Finally, agents often require fine-tuning to reach viable performance beyond simple demonstrations.  The trace logs could be used for RL (score = work item throughput for example).  The rate of work items (robot charging, order fulfillment, machine feeding, tote handling) is maximized.  We can use the workflow to string together more complicated prompts and longer-horizon actions for our VLA.</p><h2 id=\"Spec:HMNDFleetControlPlane-Scope\">Scope</h2><p><strong>In Scope:</strong></p><ul><li><p>Fleet Enrollment and Site Assignment (non-PKI - simple identifiers)</p></li><li><p>Simple one-way map sharing (static)</p></li><li><p>Workflow setup (static)</p><ul><li><p>including points of interest on our static map</p></li></ul></li><li><p>Shared workflow execution (static)</p></li><li><p>Dynamic workflow assignment (<span class=\"inline-comment-marker\" data-ref=\"600a8e43-c6a8-4db4-a4c2-cc7e4afa4238\">add robots / remove robots</span> from a static workflow)</p></li><li><p>Simple \u201cworkflow-following\u201d application running on robot</p></li></ul><p><strong>Out of Scope</strong></p><ul><li><p>Fleet-local PKI (see <a href=\"/wiki/spaces/ROBOT/pages/1151303693/Spec+HMND+Core+Control+Plane\" data-linked-resource-id=\"1151303693\" data-linked-resource-version=\"8\" data-linked-resource-type=\"page\">Spec: HMND Core Control Plane</a>)</p></li><li><p>Dynamic mapping or mapping updates</p></li><li><p>Dynamic workflows or workflow updates</p></li><li><p>Multi-map workflows.</p></li><li><p>Training data or data compliance (still relying on existing humanoid console + ML buckets)</p><ul><li><p>no jurisdictions yet</p></li></ul></li><li><p>Data plane - teleop still done \u201crobot-local\u201d (sockpuppet hosted by robot) rather than fleet-local</p></li></ul><h2 id=\"Spec:HMNDFleetControlPlane-DesignOverview\">Design Overview</h2><p>At the top-most level we have our global control plane, which includes every unit we\u2019ve ever manufactured.  For clarity we won\u2019t refer to this as a \u201cfleet\u201d and we\u2019ll reserve that terminology for robots that exist within some customer-specific context (meaning they have sites, maps and workflows).  We\u2019ll call this top-level grouping the \u201c<strong>field</strong>\u201d, as this goes along with \u201cfield replacements\u201d and \u201cfield population\u201d terminology which isn\u2019t uncommon.  This name can be changed if something better is proposed.</p><p>Within the field, we may have one more or more <strong>fleets</strong>, which are robots which have been assigned to some customer context.  In the future this will include RaaS-specific things like billing along with concerns like jurisdictions or data sovereignty - but for now its mostly a way to group robots independently of our global control plane.  Fleets are largely a logical grouping of robots, meaning there is <span class=\"inline-comment-marker\" data-ref=\"97566775-8cfe-41ee-be52-cd3d987ef72a\">no expectation that robots within a fleet will share maps or workflows</span>.</p><p /><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"879\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1170341889/Untitled%20Diagram-1761039594597.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1170341889/Untitled%20Diagram-1761039594597.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p>The more physical grouping of robots will occur at the <strong>site</strong>-level.  A site is a physical location where robots may be assigned and where these robots are expected to work.  Maps and workflows will be scoped to a site for example.</p><p>For the moment we will assume that robot fleet enrollments are static - meaning we will manually onboard a robot to a specific fleet.  This allows us to build the data model now without paying for the complexity of dynamic assignments.  In the future, especially under a RaaS model, we should expect robots to be transferred/re-enrolled between different fleets.</p><p>To see how this all fits together - let\u2019s imagine Humanoid as a fleet.  We\u2019d have 3 sites - one in Vancouver, one in Boston and one in London - each with its own maps and demo areas/workflows.  Robots are assigned to these specific sites.  A robot may be assigned to London as its built there, but if its later shipped to another site we\u2019d simply re-assign the current site (leaving the fleet enrollment alone).</p><h3 id=\"Spec:HMNDFleetControlPlane-Operations,WorkflowsandTasks\"><strong>Operations, Workflows and Tasks</strong></h3><p>In the scope of a Fleet, we may have some number of <strong>Operations</strong>, the top-level container for organizing work.  An example of this may be something like \u201cOrder Fulfillment Operations\u201d for a large distribution company.  At the moment it isn\u2019t clear how much functionality will actually exist at this level, so we could treat this as simply a tag or a label to help organize things.  In the short-term this layer is almost certainly unnecessary, but if we start versioning or inferring workflows from demonstration it could become much more important.</p><p>The real meat here would be the <strong>workflow</strong> which is a description of a set of <strong>tasks </strong>which can be performed in sequence to accomplish some operational goal, within the context of a specific site and <strong>map</strong>.  A workflow can encode the various states and transitions robots may take to complete the work (waiting for a package, filling a tote, carrying a payload through a series of waypoints).  By representing the workflow as a \u201c<a href=\"https://en.wikipedia.org/wiki/Petri_net\" class=\"external-link\" rel=\"nofollow\">Petri-Net</a>\u201d, we can scale the number of robots within a workflow to increase parallelism in addition to identifying bottlenecks.  In the future, we can even discover or adapt these petri-net workflows from event logs meaning that robots can learn workflows from demonstration.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"991\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1170341889/Untitled%20Diagram-1761049273775.drawio.png?api=v2&amp;version=4\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1170341889/Untitled%20Diagram-1761049273775.drawio.png?api=v2&amp;version=4\" loading=\"lazy\"></span><p>Tasks represent behaviors that can be performed by the robot autonomously.  For example, navigating to some point of interest on the map or executing some specific policy.  In addition to actually executing the task, the robot should verify pre/post-conditions as part of task execution.  Meaning that the robot should verify that there is a tote in front of it before executing the \u201cpick up tote\u201d policy, or that there is a global path available before executing a navigation policy.  After picking up a tote, the robot should validate that its successfully grasped the tote or after navigating that it has reached the PoI within some margin.  This core loop represents the new application that robots will run in order to execute these fleet-owned workflows.  Roughly:</p><ul><li><p>Get new task lease - returns any transitions that the robot is permitted to make (expiring after some time)</p></li><li><p>Validate task preconditions</p></li><li><p>Execute task - potentially \u201crenewing\u201d leases if its taking a long time to avoid spurious timeouts/churn</p></li><li><p>Validate task post-conditions</p></li></ul><p>The exceptional cases above (failing validate or execute) can be handled via local tele-operation initially, but we may be able to incorporate more agentic capabilities into the fleet manager itself to better handle these issues at the \u201csystem 3\u201d level (avoiding the need for teleoperation ideally).</p><p>In addition to the actual dependencies/ordering of tasks, the workflow also contains information about <span class=\"inline-comment-marker\" data-ref=\"bcabc0f7-456e-45d3-9ff1-13747dbc603c\">the capacity of individual \u201cplaces\u201d</span> in the petri-net.  This ensures that only one robot at a time is occupying spaces like the end of a conveyor belt or a table for staging totes.</p><p><strong>Oracles &amp; Middleware</strong></p><p>The workflow is a relatively simple description of how robots and goods are expected to progress through various tasks.  Each edge is guarded by a number of conditions.  For example, the robot may need to be close enough to SKU #XYZ before it can be expected to pick the item to progress the workflow.  How does the workflow know?</p><p>None of this information can really be kept inside the workflow itself, as it would cause an explosion in the state-space and render the entire thing computationally intractable.  Instead, the workflow can consult a number of different \u201coracles\u201d about the state of the world.  Because Oracle is a well-known ERP, we probably shouldn\u2019t call these oracles - and they basically function like integration middleware or plugins so we\u2019ll stick with middleware for now.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"919\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1170341889/Untitled%20Diagram-1764534673454.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1170341889/Untitled%20Diagram-1764534673454.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p>For example, we could have a simple \u201cspatial middleware\u201d running which knows the map and the locations of some static keypoints.  A \u201crobot middleware\u201d could tell us where robots are in that map (current pose) along with charge levels and other relevant facts.  The customer\u2019s PoS, WMS or other ERP systems could be integrated as middleware, so that the workflow can know how to resolve order_ids, or locate individual SKUs.</p><p>A more extreme example of an middleware would be an agentic VLM capable of taking arbitrary information/context about the fleet and making decisions.  Keeping these systems outside of the workflow itself means we can keep things verifiable and understandable, while opening up endless possibilities for expansion and integration.  Robots never talk to middleware directly, so the workflow can scale to many integration points without adding complexity to the robot software itself.  Integrated systems never communicate with anything other than middleware, which helps to limit interactions and keep things simple.</p><p><strong>Concurrency Control</strong></p><p>One of the main challenges of a multi-robot workflow is managing congestion/conflict.  How do we make sure that only one robot at a time passes through a choke point or approaches a tote?  Especially in a noisy environment with poor network connectivity?</p><p>In cases where the robot needs to perform some task (navigating, running a policy, etc) the robot should acquire a <strong>lease </strong>from the workflow coordinator.  Leases are exclusive permissions to perform some task, and the coordinator can guarantee that only one robot will have a valid lease at any given time.  Leases should expire after a short-period of time (though robots could renew if necessary).  The workflow itself cannot know whether or not it is safe to grant a lease, but it can make sure that only one robot at a time has the lease.  The rough separation of responsibilities is thus:</p><ol start=\"1\"><li><p>Robot \u2192 responsible for knowing that it should obtain a lease before performing a transition.  If the robot performs a transition without a lease, that\u2019s an implementation bug.</p></li><li><p>Coordinator \u2192 responsible for granting up to K leases (depending on the capacity)</p></li><li><p>Middleware \u2192 responsible for determining wether or not the lease can actually be granted</p></li></ol><h2 id=\"Spec:HMNDFleetControlPlane-Milestones\">Milestones</h2><ol start=\"1\"><li><p>Python simulation of PoC Workflow (TBD) using off the shelf petri-net library/DES tooling \n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1736\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1170341889_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"35313c07-d82b-4d02-9e90-3794db906615\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1736\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1736</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p><ul><li><p>demonstrate multiple robots making progress concurrently within the workflow</p></li><li><p>demonstrate adaptability as robots are removed/added to the workflow (1, 2 or 3)</p></li></ul></li><li><p>Wrap PoC workflow in simple coordinator API \n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1737\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1170341889_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"8b1f26a8-c9c2-438a-a2b4-76471ba1a97d\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1737\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1737</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p><ul><li><p>Drive petri net (from milestone 1) with API calls, returning task assignments/leases as appropriate</p></li><li><p>Just do everything in RAM (small) and checkpoint to S3 periodically if necessary (mostly for debug)</p></li></ul></li><li><p>Create simple map and robot status oracles</p><ul><li><p>robot status tells us which robots are around and what their current pose is (updated periodically by robots directly) \n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1739\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1170341889_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"f6ddde72-b41e-413a-9b7e-fc2d4192e655\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1739\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1739</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p></li><li><p>map oracle stores our map + key points \n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1738\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1170341889_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"f43c4931-e5ba-404d-9005-d62daaf71a50\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1738\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1738</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p></li></ul></li><li><p>Create robot behavior tree (app) for executing workflows \n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1740\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1170341889_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"8ba87a27-45cb-446b-91d7-28570de1a949\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1740\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1740</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p><ul><li><p>App should make API calls to coordinator to get task assignments</p></li><li><p>App should execute task assignments (no fallback yet)</p></li></ul></li><li><p>Workflow Visualization (stretch) \n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1741\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1170341889_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"c7ac7723-b5b3-47be-b9ee-42d27fcba4a2\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1741\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1741</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p><ul><li><p>Since we have the static map saved under the site, we should be able to render along with robot telemetry</p></li><li><p>TBD - lots of different ways to achieve this</p></li></ul></li></ol><h2 id=\"Spec:HMNDFleetControlPlane-SOPs\">SOPs</h2><p><strong>Fleet Enrollment </strong>- for this initial MVP, fleet enrollment will be setting an HMND_FLEET_TOKEN somewhere in the environment.  In the future we will use PKI and mint fleet certificates (similar to how we mint provisioning certificates in the global control plane)<strong> </strong></p><p><strong>Site Mapping </strong>- a static map (plus some information about origin pose) is saved during mapping.  An operator uploads this map to an endpoint.</p><p><strong>Site Assignment </strong>- an API call to the fleet manager will allow setting a robot\u2019s current site.   A robot will download the static map for the configured site.</p><p><strong>Workflow Definition </strong>- a declarative representation of the workflow (petri-net, PNML, YAML - lots of options) is uploaded to an endpoint.  </p><p><strong>Workflow Assignment </strong>- a robot is added to the workflow via an endpoint.</p><h1 id=\"Spec:HMNDFleetControlPlane-AppendixA:PetriNets\">Appendix A: Petri Nets</h1><p>Petri-Nets are a formalization of processes comprising \u201cplaces\u201d and \u201ctransitions\u201d.  For this reason they are sometimes also called PT-nets.   Each place can contain some number of \u201ctokens\u201d, which can move through transitions to go from place to place.  A bit unintuitive, but places don't correspond to<span class=\"inline-comment-marker\" data-ref=\"3df3e4ef-b6dd-4672-919d-0432842b8130\"> physical places (like locations in the map), but are are more conditions or constraints which the tokens satisfy</span>.  Because we are dealing with discrete sets, we typically don't encode poses directly in the workflow.  We simply \u2018ask' the map questions about the spatial relationships in our transitions\u2019 guards.  This also saves us from needing to re-configure poses we embedded into the workflow of our map updates.</p><p>Petri nets allow for non-deterministic execution, meaning they are well-suited for concurrent distributed systems like a multi-robot fleet workflow.  In these applications, robots are one of the types of tokens that will transition through the places in the net, but we can also represent payloads like orders or totes or assemblies - anything that must move through the workflow.</p><p>There are all sorts of fancy formalized variations of petri nets that are relevant for us.  For example, maybe a place can only have so many tokens.  Maybe only 1 robot at a time can stand in front of the conveyor belt.  These places are<em> k-bounded</em>, and these are bounded petri nets.  When tokens aren\u2019t fungible, then \u201ccolored\u201d petri nets may be appropriate.  If we want to model the timing of transitions we may want to look at timed or stochastic petri nets.  There are tons of sources on these things and a rich ecosystem of algorithms.</p><p><strong>Inferring or Updating Workflows</strong></p><p>A really interesting area of research is known as \u201cprocess mining\u201d, which is the goal of inferring something like a petri net from the traces generated by some process.  Using a technique like alpha mining or inductive mining, you can take the logs from some arbitrary process, and then reverse engineer the petri net that would produce them.  Although not in scope for this initial demo, this has very interesting ramifications for learning workflows from demonstration and for adapting workflows to changes via intervention.</p><h1 id=\"Spec:HMNDFleetControlPlane-AppendixB:APIs\">Appendix B:  APIs</h1><h2 id=\"Spec:HMNDFleetControlPlane-KeyConcepts\">Key Concepts</h2><p><strong>Workflows</strong> - A directed graph of states connected by tasks</p><p><strong>States</strong> - Named buckets of work items or units satisfying some constraints.</p><p><strong>Tasks</strong> - State changes with guards (CEL expressions) and optional timing. Two kinds:</p><p style=\"margin-left: 30.0px;\">internal: coordinator-only bookkeeping; no robot action.</p><p style=\"margin-left: 30.0px;\">robot: requires exclusive lease granted to a robot; the robot executes a local policy/behavior and makes claims about the status.</p><p><strong>Work Item/Unit</strong> - Units of work. Each has a token_id, a place_id, and a color (typed payload map). Work Items flow from state to state via tasks, possibly being transformed in the process.  </p><p><strong>Middleware</strong> - A service which provides external context - issuing tickets or providing facts relevant to the workflow</p><p><strong>Coordinator</strong> - The service responsible for executing a workflow.  Its goal is to \u2018push\u2019 work items along the workflow.</p><p><strong>Facts</strong> - Site-scoped, versioned, TTL\u2019d objects the coordinator caches from oracles (e.g., maps.poi/BIN-A17, order.line/OL-42, robot.status/R14). Guards read facts; no network in the hot path.</p><p><strong>Leases</strong> - A temporary binding of inputs (satisfying guards) and tokens which agents may use to perform specific tasks.</p><p><strong>Claims </strong>- The result of any task executed.</p><h2 id=\"Spec:HMNDFleetControlPlane-KeyMetrics\">Key Metrics</h2><p><strong>States</strong></p><ul><li><p>min/max/average of how long work items were in state</p></li><li><p>token throughput</p></li></ul><p><strong>Tasks</strong></p><ul><li><p>success rate</p></li><li><p>duration</p></li><li><p>token throughput</p></li></ul><p><strong>Leases</strong></p><ul><li><p>average hold time</p></li><li><p>conflicts/rejections?</p></li></ul><p>Goal is to make looking at things like \u201cUPH\u201d or \u201csuccess rates\u201d intrinsic to the workflow - measuring this stuff should pretty much be \u201cfree\u201d.</p><h2 id=\"Spec:HMNDFleetControlPlane-CoordinatorAPI\">Coordinator API</h2><p>Many collaborating agents (robots, chargers, 3rd party ERP systems) may work together via the coordinator API to advance work items through the workflow as quickly and reliably as possible.</p><p>Agents will make requests to the Coordinator for leases to perform tasks which will advance work items through the workflow.  Agents will then return any claims (that these tasks succeeded or were retried or failed or whatever) in the request for a new lease.</p><p>The coordinator will, based on the claims, move the work items between states in the workflow.  The rate (how many work items are transitioned to the \u201cdone\u201d state per unit time or UPH) and reliability (how many work items  that were accepted were transitioned to the \u201cdone\u201d state) can be produced directly as KPIs.  Or agent availability (time not spent in some \u201cdown\u201d state).</p><h2 id=\"Spec:HMNDFleetControlPlane-MiddlewareAPI(integrations/oracle)\">Middleware API (integrations/oracle)</h2><p>Our coordinator needs to get a lot of external context to evaluate task guards or verify claims.  Agents communicate with middleware services which may have side effects (communicating with external services or running some manipulation or navigation policy) while they communicate with the coordinator to determine what to do next.</p><p>A robot agent could periodically update a robot middleware with the current pose.  The coordinator may lookup this robot\u2019s pose to see if a guard has been satisfied (\u201cdistance(r1.pose, poi1) &lt; 0.1\u201d), which will poll for this pose and cache it for a bit.</p><p>An \u201cSAP\u201d agent could feed new work items (totes arriving at some ingress stack) and subscribe to events about the workflow which can be used to update records in SAP or to add additional work items.</p><h3 id=\"Spec:HMNDFleetControlPlane-RobotLoop\">Robot Loop</h3><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"6bf64330-2af9-4971-927d-4b4f35856792\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">claims = []\nwhile True:\n  claims, leases = coordinator.get_leases(claims)\n  task = choose(leases)\n  claims.append(run_policy(task))\n  # run_policy may have side-effects and may call middleware with updates?</pre>\n</div></div><p> </p>"
        },
        {
          "id": "1039335426",
          "title": "How To Slack",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1039335426",
          "last_modified": "2025-11-13T17:45:13.897Z",
          "created_at": "2025-08-13T18:56:35.187Z",
          "body_html": "<p>Slack is an amazing tool for coordinating and communicating, but it's not always obvious how to get the best use out of it.  What follows is a rought attempt to provide some guidance on how to work effectively in Slack.</p><h2 id=\"HowToSlack-ChannelNaming&amp;Activity\">Channel Naming &amp; Activity</h2><p><span class=\"inline-comment-marker\" data-ref=\"bd27b488-babb-4d4e-9275-72d5e0a54ed0\">Short, generic names (#software, #build, #ai, #random) should be the busiest places.  Broad channels build network effects - more eyes, more serendipity.</span></p><p>People learn that their queries will be answered in these channels because they are active.  Niche channels are fine, but the default should be to post in the broadest relevant one.  Make it as easy as possible for people to decide where to post.</p><h2 id=\"HowToSlack-PostingLocation\">Posting Location</h2><p>Post where it will have the highest chance of being seen by the right people, even if it feels slightly off-topic.</p><p>Avoid scattering related discussions across multiple tiny channels - centralize instead.</p><h2 id=\"HowToSlack-ChannelAccess\">Channel Access</h2><p>Keep channels open by default.</p><p>Transparency builds shared context and avoids \u201cprivate knowledge silos.\u201d</p><p>If it must be private,  at least announce or summarizes what\u2019s happening somewhere.  For example, the weekly TLT digest serves this purpose.</p><h2 id=\"HowToSlack-Mentions&amp;Pings\">Mentions &amp; Pings</h2><p>Don\u2019t @channel or @here unless it\u2019s genuinely urgent for everyone.</p><p>Direct @-mentions are fine, but only for people who truly need to respond.</p><p>Think before pinging: \u201cDo they need this now, or can they find it when they check in?\u201d</p><h2 id=\"HowToSlack-ThreadDiscipline\">Thread Discipline</h2><p>Always reply in threads unless you are starting a new conversation.</p><p>Threads keep channels scannable and make context easier to follow.</p><p>If a thread becomes high-value, summarize it back to the channel.</p><h2 id=\"HowToSlack-AsynchronousMindset\">Asynchronous Mindset</h2><p>Don\u2019t expect immediate replies - Slack is not an on-call pager.</p><p>Multiple conversations can run in parallel across different timescales.</p><p>You can leave a thread for hours or days and still pick it back up.</p><h2 id=\"HowToSlack-CultureofContext\"><span class=\"inline-comment-marker\" data-ref=\"daa1fcb6-8ecd-47f4-aec2-ff96f6c2eba7\">Culture of Context</span></h2><p>Provide enough detail in your initial message so others can respond without hunting for backstory.</p><p>Link to docs, code, or prior threads rather than re-explaining from scratch.</p><p>Summarize outcomes so lurkers still learn from the conversation.</p><p><span class=\"inline-comment-marker\" data-ref=\"03b4db7c-5334-41b1-8d7e-71a09a2499a8\">Due to limited retention, record major decisions somewhere more deliberate (confluence or git)</span></p><h1 id=\"HowToSlack-HumanoidChannels\"><span class=\"inline-comment-marker\" data-ref=\"cc30e554-5981-4b24-8039-43e7682384fb\">Humanoid Channels</span></h1><p>Let's take a look specifically at the engineering channels for Humanoid as a whole.  We have approximately 20 team_eng-* channels (<span class=\"inline-comment-marker\" data-ref=\"e8adb310-442b-40a2-aeba-8aa850e08059\">though not all are in active use</span>), and roughly 10 robot_ipt-* and a few other integration channels.</p><p><span class=\"inline-comment-marker\" data-ref=\"77dae306-d748-45e6-b6a7-21544ffb2062\">The intent (I believe) was to provide places for functional area/team discussion in additional to cross-functional/cross-team integration.</span></p><h2 id=\"HowToSlack-Fragmentation\">Fragmentation</h2><p>When a developer wants to make a post, they need to almost digest and process our entire org chart in order to understand where to post.  Is this an integration request?  Which team?  Which subsystem?</p><p>The root issue here is that this is a tough decision and we don't have any 'tie-breaker' logic.  So communication gets spread around and we lose network effects and ultimately the utility of the tool.  We just end up with dozens of nearly dead channels.</p><h2 id=\"HowToSlack-Salvation\">Salvation</h2><p>Let's imagine we allow developers to endlessly create new channels - what prevents us from just smearing out communications?  Don't we need to lock everything down?  Believe it or not - you don't!</p><p>We have already started the process of consolidating some channels (thanks to all who have helped make this happen) which has I believe resulted in more effective use of Slack.  But we can do better.</p><p><span class=\"inline-comment-marker\" data-ref=\"e809b7d1-d982-4b81-afa1-ca217c46fbc6\">I suggest we drop our naming scheme entirely to help reduce the noise of channel names and to make defaults more obvious.</span></p><p>Instead of:</p><p>```</p><p>#team_eng-software</p><p>#team_eng-hmnd-robot</p><p>#chapter-software</p><p>```</p><p>Just `#software`.</p><h2 id=\"HowToSlack-SplittingChannels\">Splitting Channels</h2><p>At some point, channels will become too busy.  If the main page scrolls so fast that no one can follow or if ~50% of the messages are pure noise to any one participant, then chances are the channel is too broad and too busy and it's worth splitting something out.</p><p>For an example, let's consider #software.  Assume we have one giant software channel.  At some point, it will be flooded with questions from developers about random build errors, CI issues, submodules mismatches etc etc.  Eventually it may make sense to move build support conversations to a separate #build thread.</p><p>The general goal should be to start with few channels, building critical mass and then splitting off new channels when it makes sense.  This more organic growth with ensure good utilization of the tool while keeping things organized.</p>"
        },
        {
          "id": "1186627652",
          "title": "Spec: Secure Thor + OTA",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1186627652",
          "last_modified": "2025-10-27T14:21:42.153Z",
          "created_at": "2025-10-25T01:28:56.112Z",
          "body_html": "<p><strong>Spec: Secure OTA, Encrypted Rootfs, and Verified Boot on Thor</strong></p><p><strong>Owner:</strong> \u2014<br/><strong>Date:</strong> \u2014<br/><strong>Approvers:</strong> \u2014</p><h2 id=\"Spec:SecureThor+OTA-ProblemStatement\">Problem Statement</h2><p>We\u2019re running robots on Nvidia Thor-class compute.  We want to ship new OS images over the air (OTA), atomically upgrade them, roll back safely if things go sideways, and prevent anyone (including with physical access) from tampering with or spying on the filesystem.</p><p>Right now we have none of that.</p><p>Pain today:</p><ul><li><p>Flashing new software means invasive manual re-image and chasing revisions</p></li><li><p>Root filesystem is readable if you pull the NVMe.</p></li><li><p>Kernel / boot chain are not actually locked.</p></li><li><p>There\u2019s no A/B slotting, so upgrades are high-risk (in-place).</p></li></ul><p>We need:</p><ul><li><p>A deterministic way to build a full stack image (bootloader \u2192 kernel \u2192 userland).</p></li><li><p>A way to boot our new stack temporarily on a live robot without bricking it.</p></li><li><p>A way to lay down an encrypted disk image with A/B rootfs slots.</p></li><li><p>A way to verify what boots, with hardware-backed trust.</p></li></ul><h3 id=\"Spec:SecureThor+OTA-Scope\">Scope</h3><p><strong>In scope</strong></p><ul><li><p>Bazel-built Linux for Tegra (L4T) kernel, modules, and firmware blobs as a versioned artifact.</p></li><li><p>Bazel-built rootfs (Ubuntu 24 base + our services) as a versioned artifact.</p></li><li><p>Capture of Nvidia proprietary bits (CUDA, graphics, Holoscan, TensorRT, etc.) into two <code>.deb</code> packages we control:</p><ul><li><p><code>nvidia-kernel.deb</code></p></li><li><p><code>nvidia-userland.deb</code></p></li></ul></li><li><p>Live boot via <code>kexec</code> into that Bazel-built rootfs, without flashing yet. (intermediate step)</p></li><li><p>Full disk encryption via LUKS on NVMe.</p></li><li><p>A/B rootfs layout on NVMe for OTA + rollback.</p></li><li><p>Boot chain hardening: fuse burn, measured / trusted boot.</p></li></ul><p><strong>Out of scope</strong></p><ul><li><p>Secure comms channel for OTA delivery (we assume we can already pull artifacts from a trusted endpoint over TLS/mTLS).</p></li><li><p>User data partitioning / log persistence design - assume we have a shared data partition to mount overlay</p></li><li><p>Recovery via physical UART/U-Boot interposer</p></li></ul><h2 id=\"Spec:SecureThor+OTA-DesignOverview\">Design Overview</h2><p>We\u2019re going to walk from volatile to permanent:</p><ol start=\"1\"><li><p>We build images.</p></li><li><p>We boot them temporarily.</p></li><li><p>We lay down encrypted disk with A/B slots.</p></li><li><p>We flip the boot target.</p></li><li><p>We lock the silicon.</p></li></ol><h4 id=\"Spec:SecureThor+OTA-1.ImageConstruction(Bazelassourceoftruth)\">1. Image Construction (Bazel as source of truth)</h4><p>We produce three outputs from CI, all immutable and content-addressed.</p><ol start=\"1\"><li><p><strong>Kernel bundle (</strong><code>thor-kernel.tar.zst</code><strong>)</strong></p><ul><li><p>Cross-compiled L4T kernel for Thor, plus kernel modules, device tree blobs (DTBs), and firmware blobs.</p></li><li><p>Built under Bazel, not JetPack. We vendor the Nvidia kernel sources / defconfigs / out-of-tree modules into the repo, and we make Bazel rules that:</p><ul><li><p>apply our patches (PREEMPT_RT knobs, IRQ affinity, missing drivers for our PCIe devices, etc.),</p></li><li><p>spit out:</p><ul><li><p><code>/boot/Image</code> (or <code>Image.gz</code>/<code>zImage</code> depending on chain),</p></li><li><p><code>/boot/*.dtb</code>,</p></li><li><p><code>/lib/modules/&lt;kernel-ver&gt;/**</code>,</p></li><li><p>proprietary firmware blobs for GPU, ISP, etc.</p></li></ul></li></ul></li></ul><p>This bundle is later repackaged as <code>nvidia-kernel.deb</code>.</p></li><li><p><strong>Userland bundle (</strong><code>thor-userland.tar.zst</code><strong>)</strong></p><ul><li><p>Ubuntu 24 rootfs we own.</p></li><li><p>Our daemons, our QoS stack, ROS2, teleop stack, inference services, etc.</p></li><li><p>No Nvidia proprietary runtime yet.</p></li><li><p>Built root-first (Bazel <code>pkg_tar</code> / <code>deb_image</code> style), so we get a reproducible <code>/</code> tree.</p></li><li><p>This becomes the canonical \u201crobot OS userspace.\u201d</p></li></ul></li><li><p><strong>Nvidia proprietary split</strong> We don\u2019t want to be hostage to JetPack, but we still need CUDA, Vulkan/Wayland accel, display stack, TensorRT, Holoscan, codecs.</p><p>So we snapshot those from a reference L4T/JetPack-style install on a sacrificial dev box and repack them into two internal Debian packages:</p><ul><li><p><code>nvidia-kernel.deb</code></p><ul><li><p>Kernel-adjacent binaries:</p><ul><li><p>GPU kernel modules (if they\u2019re out-of-tree)</p></li><li><p>Firmware blobs not already baked</p></li><li><p>Any initramfs hooks that must run early (power rail bring-up, GPU clocks, etc.)</p></li><li><p>UAPI headers/so files that tightly couple to kernel version</p></li></ul></li></ul><p>Installed into <code>/lib/firmware</code>, <code>/lib/modules/&lt;ver&gt;/extra</code>, <code>/usr/lib/modprobe.d</code>, possibly <code>/etc/initramfs-tools/hooks/nvidia-*</code>.</p></li><li><p><code>nvidia-userland.deb</code></p><ul><li><p>User-mode acceleration stack:</p><ul><li><p>CUDA libs</p></li><li><p>TensorRT</p></li><li><p>V4L2 / ISP userspace bits</p></li><li><p>Wayland/EGL/OpenGL/Vulkan user libraries for display</p></li><li><p>Holoscan runtime/SDK pieces that assume Nvidia SoC layout</p></li><li><p>GStreamer accel plugins</p></li><li><p>Any compositor bits we need for kiosk mode / HUD</p></li></ul></li></ul><p>Installs into <code>/usr/lib/*</code>, <code>/opt/nvidia/*</code>, <code>/usr/share/holoscan/*</code>, etc.</p></li></ul><p>These two packages are versioned against:</p><ul><li><p>specific Thor silicon rev</p></li><li><p>specific kernel ABI</p></li><li><p>specific CUDA/TensorRT ABI</p></li></ul><p>CI enforces that <code>thor-userland.tar.zst + nvidia-userland.deb + nvidia-kernel.deb + thor-kernel.tar.zst</code> all agree on ABI versions. If not, build fails.</p><p>Result: we can apt install/upgrade Nvidia stuff like normal packages, instead of re-running JetPack voodoo.</p><p>Deliverable: <code>thor-os.sqfs</code> (squashfs rootfs image) assembled from:</p><ul><li><p>base Ubuntu 24</p></li><li><p>our services</p></li><li><p><code>nvidia-userland.deb</code></p></li><li><p><code>nvidia-kernel.deb</code></p></li><li><p>kernel bundle staged under /boot and /lib/modules</p></li></ul><p>This <code>thor-os.sqfs</code> is the payload we\u2019ll roll out OTA.</p><p>Philosophically: Bazel is the forge, <code>.deb</code> is the distribution format, squashfs is the shipping crate.</p></li></ol><h4 id=\"Spec:SecureThor+OTA-2.LiveStagingviakexec(Pre-flashVerification)\">2. Live Staging via kexec (Pre-flash Verification)</h4><p>We do not immediately overwrite what\u2019s running in the field. That\u2019s suicide.</p><p>Instead, we:</p><ul><li><p>Push new artifacts (<code>thor-os.sqfs</code>, kernel Image+dtb, initramfs) to the robot into a staging dir on the <em>current</em> rootfs.</p></li><li><p>Use <code>kexec</code> to jump directly into the new kernel + initramfs without touching bootloader or disk layout.</p></li></ul><p>Mechanics:</p><ol start=\"1\"><li><p>Generate an initramfs for the candidate image that:</p><ul><li><p>mounts <code>thor-os.sqfs</code> read-only as root,</p></li><li><p>brings up minimal GPU stack (Wayland kiosk splash) so we know graphics init works,</p></li><li><p>runs a health probe:</p><ul><li><p>enumerates PCIe / I2C devices we depend on,</p></li><li><p>validates /dev nodes for actuators/sensors,</p></li><li><p>runs a tiny inference through TensorRT to prove CUDA path,</p></li><li><p>runs a Holoscan pipeline (camera \u2192 passthrough \u2192 sink) to prove sensor graph alive.</p></li></ul></li></ul></li><li><p><code>kexec -l &lt;Image&gt; --initrd &lt;initramfs&gt; --command-line &quot;&lt;our cmdline&gt;&quot;</code><br/>Then <code>kexec -e</code> to enter it.</p></li></ol><p>This gives us an ephemeral boot of \u201cthe new world\u201d in RAM. We haven\u2019t touched NVMe yet. If it blows up, we reboot and we\u2019re back to the old world.</p><p>This is Milestone M1 health check, see milestones below.</p><p>Why this matters: we prove our Bazel-built kernel and userland can actually run on that physical Thor SKU, with its weird daughterboards and timing quirks, before we commit the update to disk encryption hell.</p><h4 id=\"Spec:SecureThor+OTA-3.DiskLayout(EncryptedNVMewithA/BSlots)\">3. Disk Layout (Encrypted NVMe with A/B Slots)</h4><p>Once a candidate image passes kexec validation, we lay down the permanent on-disk layout.</p><p>Disk is NVMe (<code>/dev/nvme0n1</code>). Layout target (final form):</p><ul><li><p>Partition 1: EFI / bootloader / boot control (unencrypted, signed content only)</p></li><li><p>Partition 2: LUKS container A</p></li><li><p>Partition 3: LUKS container B</p></li><li><p>Partition 4: /data (may be separate LUKS container later; not mandatory in v1)</p></li></ul><p>Inside each LUKS slot (A or B):</p><ul><li><p>One ext4 (or btrfs, calm down) rootfs.</p></li><li><p>That rootfs contains our system, basically <code>thor-os.sqfs</code> exploded or mounted as lower layer + overlay for mutable bits like /etc, /var.</p></li></ul><p>We alternate:</p><ul><li><p>Active rootfs = A</p></li><li><p>Next OTA gets staged into B</p></li><li><p>Flip</p></li><li><p>Repeat</p></li></ul><p>Rollback is \u201cboot the other slot.\u201d</p><p>Encryption:</p><ul><li><p>Each LUKS container uses dm-crypt with strong cipher + integrity mode.</p></li><li><p>Keys are not sitting loose. Keys are sealed to the device using a TPM-like hardware root (Thor has fuse-backed secrets; if we don\u2019t get that, we use an encrypted keyfile in boot partition, itself wrapped with a device-unique secret burned into fuses / keyslots). The idea: if someone steals the NVMe and plugs it into a laptop, they get ciphertext.</p></li></ul><p>Write process for OTA:</p><ol start=\"1\"><li><p>Pick inactive slot (say slot B).</p></li><li><p>Format/refresh its LUKS container.</p></li><li><p>Unlock and mount it as <code>/mnt/newroot</code>.</p></li><li><p>Lay down the new rootfs version into <code>/mnt/newroot</code>:</p><ul><li><p>install <code>thor-os.sqfs</code> or fully untarred tree,</p></li><li><p>install versioned <code>/boot</code> with the new kernel + dtb + initramfs for that slot,</p></li><li><p>stamp metadata: version string, build hash, signature.</p></li></ul></li><li><p>Update boot control vars (see below) to \u201cboot slot B next boot.\u201d</p></li><li><p>Reboot normally via bootloader.</p></li></ol><p>If new slot boots and stays alive long enough to pass health checks, mark it \u201cgood\u201d and keep it as active. If it fails early boot health, bootloader or early userspace reverts to previous slot.</p><p>This is classic A/B update flow like Android system partitions, but for Thor.</p><p>Important: both A and B live inside full-disk crypto. You don\u2019t get a free look at either slot just by pulling the drive.</p><h4 id=\"Spec:SecureThor+OTA-4.BootControl,FusePolicy,Anti-tamper\">4. Boot Control, Fuse Policy, Anti-tamper</h4><p>We close the loop with trust. The steps go like this:</p><p>Boot chain of trust:</p><ul><li><p>We rely on Thor\u2019s secure boot hardware (fuse-backed keys) to enforce that only signed bootloader and kernel images can execute.</p></li><li><p>We burn fuses to lock the signing chain. After this point, you can't boot unsigned junk without hardware glitching.</p></li></ul><p>Bootloader responsibilities:</p><ul><li><p>Validate signature on kernel + initramfs + DTB before loading.</p></li><li><p>Decide whether to boot slot A or slot B based on:</p><ul><li><p>last known good,</p></li><li><p>pending update flag,</p></li><li><p>fallback counter.</p></li></ul></li></ul><p>Kernel/initramfs responsibilities:</p><ul><li><p>Unlock correct LUKS slot using a key sealed to device identity.</p><ul><li><p>This is the moment where disk confidentiality relies on that hardware secret.</p></li></ul></li><li><p>Mount rootfs.</p></li><li><p>Hand off to userspace.</p></li></ul><p>Tamper resistance story:</p><ul><li><p>You unscrew the robot, yank NVMe, plug into your box? You see dm-crypt noise.</p></li><li><p>You try to alter the rootfs on-disk? Signature mismatch or dm-verity-style integrity check kills boot / drops to recovery.</p></li><li><p>You try to boot your own kernel to bypass all this? Secure boot refuses because fuses say \u201conly keys we signed.\u201d</p></li></ul><p>This prevents:</p><ul><li><p>Offline IP theft of ML models / perception code.</p></li><li><p>Silent insertion of backdoored daemons.</p></li><li><p>Random \u201cfield tech\u201d debugging with vim in /usr/bin on a production unit.</p></li></ul><p>We are now a real robot company, not a loose pile of tarballs in a trench coat.</p><p>\u2013\u2013\u2013</p><h2 id=\"Spec:SecureThor+OTA-Milestones\">Milestones</h2><p><strong>M1 \u2013 Ephemeral boot (kexec smoke test)</strong><br/>Deliverable: We can kexec from the factory Thor image into our Bazel-built kernel + initramfs + <code>thor-os.sqfs</code>, run health probes (GPU init, Holoscan pass-through, one-shot inference).<br/>Verification: robot survives, teleop overlay draws, CUDA tensor multiply returns sane result.</p><p><strong>M2 \u2013 Packaging (nvidia-*.deb split complete)</strong><br/>Deliverable: <code>nvidia-kernel.deb</code> + <code>nvidia-userland.deb</code> built and installed into <code>thor-os.sqfs</code> purely via <code>dpkg -i</code>, no JetPack installer.<br/>Verification: clean Bazel rootfs + those two .debs still pass M1 health probe.</p><p><strong>M3 \u2013 Disk provisioning + A/B layout</strong><br/>Deliverable: Script that:</p><ul><li><p>Partitions NVMe,</p></li><li><p>Creates LUKS A/B,</p></li><li><p>Populates slot A from <code>thor-os.sqfs</code>,</p></li><li><p>Boots natively from encrypted slot A (not kexec).<br/>Verification: Cold boot from NVMe, rootfs mounted from dm-crypt, robot comes up and runs control stack.</p></li></ul><p><strong>M4 \u2013 OTA update &amp; rollback</strong><br/>Deliverable: Update service that:</p><ul><li><p>Downloads a new signed <code>thor-os.sqfs</code>,</p></li><li><p>Writes it into inactive slot,</p></li><li><p>Flips boot target,</p></li><li><p>Reboots,</p></li><li><p>Marks success/failure,</p></li><li><p>Auto-reverts on failure.<br/>Verification: We intentionally ship a \u201cbad\u201d image; box reverts to previous slot automatically.</p></li></ul><p><strong>M5 \u2013 Secure boot + fuse lockdown</strong><br/>Deliverable: Secure boot enforced. Bootloader, kernel, initramfs signed. Fuses burned for prod units so unsigned images will not boot. LUKS keys sealed to that hardware identity, not just a plaintext file.<br/>Verification: Altering rootfs on the NVMe from an external machine leads to a non-booting system. Attempting to boot unsigned kernel fails before handoff.</p><h2 id=\"Spec:SecureThor+OTA-Observability&amp;Verification\">Observability &amp; Verification</h2><p>We have to prove this machinery works, with metrics, not vibes.</p><p>Functional checks:</p><ul><li><p>From running system, report:</p><ul><li><p>active slot (<code>A</code> or <code>B</code>),</p></li><li><p>OS version hash,</p></li><li><p>secure boot status (enforced / not enforced),</p></li><li><p>disk encryption status (LUKS active yes/no),</p></li><li><p>rollback pending yes/no.</p></li></ul></li><li><p>From updater service logs:</p><ul><li><p>write time of new slot,</p></li><li><p>verification steps it ran,</p></li><li><p>signature validation result.</p></li></ul></li></ul><p>We\u2019ll export these as Prometheus-style gauges/counters the same way we\u2019re doing tc/qdisc stats in the QoS spec.</p><p>Concretely:</p><ul><li><p><code>thor_slot_active{slot=&quot;A&quot;}</code> = 1</p></li><li><p><code>thor_secure_boot_enforced</code> = 1</p></li><li><p><code>thor_root_encrypted</code> = 1</p></li><li><p><code>thor_update_success_total</code> counter</p></li><li><p><code>thor_update_rollback_total</code> counter</p></li><li><p><code>thor_update_healthcheck_seconds</code> histogram of how long validation took</p></li></ul><p>Vector will scrape a small local CLI (call it <code>thor-status --metrics</code>), which prints these, Prometheus text format.<br/>Vector forwards to Mimir. Grafana panels show fleet compliance: who\u2019s on newest hash, who\u2019s drifted, who rolled back.</p><p>Debug surfaces:</p><ul><li><p><code>journalctl -b -1 | grep thor-update</code> shipped via Vector to Loki, so we can read previous-boot failure context without SSH.</p></li><li><p>A \u201cwhy did I revert\u201d code path that logs the bootloader decision (slot B failed healthcheck N times, fell back to slot A).</p></li></ul><p>This makes deployment auditable and lets us spot units that are stuck on old software because they keep failing health.</p><h2 id=\"Spec:SecureThor+OTA-AppendixA.kexec-basedvalidationflow\">Appendix A. kexec-based validation flow</h2><ol start=\"1\"><li><p>Robot is running \u201cslot A normal world.\u201d</p></li><li><p>OTA agent downloads:</p><ul><li><p><code>Image</code> (kernel),</p></li><li><p><code>initramfs-new</code>,</p></li><li><p><code>thor-os.sqfs</code>,</p></li><li><p>signatures/metadata.</p></li></ul></li><li><p>Agent runs:</p><ul><li><p>signature check (our signing key),</p></li><li><p>ABI check (kernel \u2194 CUDA \u2194 TensorRT).</p></li></ul></li><li><p>Agent loads: <code>kexec -l ./Image --initrd=./initramfs-new --command-line=&quot;root=/dev/ram0 init=/sbin/thor-probe quiet splash&quot;</code></p></li><li><p>Agent executes <code>kexec -e</code>.</p></li><li><p>Probe environment boots from RAM:</p><ul><li><p>mounts <code>thor-os.sqfs</code>,</p></li><li><p>runs GPU bring-up,</p></li><li><p>runs Holoscan graph test,</p></li><li><p>runs inference smoke (e.g. 1-layer conv),</p></li><li><p>validates basic IO to real robot peripherals.</p></li></ul></li><li><p>Probe writes result to a known handoff location (e.g. tmpfs shared via kexec handoff or persisted to the old root via a tmp mount).</p></li><li><p>If probe passes, we\u2019re allowed to install to inactive slot and schedule reboot.</p></li></ol><p>We do not touch NVMe, boot slots, LUKS headers, or fuses until the probe passes.</p><p>This is our airbag.</p><h2 id=\"Spec:SecureThor+OTA-AppendixB.NVMepartitioningandLUKSprovisioning(conceptsketch)\">Appendix B. NVMe partitioning and LUKS provisioning (concept sketch)</h2><p>Pseudocode-ish provisioning script (first-time install or full-disk refresh):</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"ad023deb-f07c-426d-b5f2-0d12811bde42\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">#!/usr/bin/env bash\nset -euxo pipefail\n\nDISK=/dev/nvme0n1\n\n# 1. Partition table:\n#    p1: EFI/boot (256M)\n#    p2: slotA (rest/2)\n#    p3: slotB (rest/2)\n# (p4 later for data)\nparted --script &quot;$DISK&quot; \\\n  mklabel gpt \\\n  mkpart boot fat32 1MiB 257MiB \\\n  set 1 esp on \\\n  mkpart slotA 257MiB 50% \\\n  mkpart slotB 50% 100%\n\n# 2. LUKS format slotA / slotB\ncryptsetup luksFormat ${DISK}p2 --key-file /root/thor.key\ncryptsetup luksFormat ${DISK}p3 --key-file /root/thor.key\n\ncryptsetup open ${DISK}p2 thorA --key-file /root/thor.key\nmkfs.ext4 /dev/mapper/thorA\nmount /dev/mapper/thorA /mnt/newroot\n\n# 3. Populate rootfs\ntar -C /mnt/newroot -xpf thor-os.tar   # thor-os.sqfs exploded or equivalent\n# install boot artifacts for slotA, write version metadata, etc.\n\numount /mnt/newroot\ncryptsetup close thorA\n</pre>\n</div></div><p>In production, <code>/root/thor.key</code> is not a plaintext file. The unlock key is derived/loaded from hardware-sealed storage. That detail lands in Milestone M5.</p><h2 id=\"Spec:SecureThor+OTA-AppendixC.Bootslotmetadata\">Appendix C. Boot slot metadata</h2><p>We maintain a tiny boot-control struct, ideally in the unencrypted boot partition (so bootloader can read it early), something like:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"bb5833bb-1ae3-4b1c-8d3f-5fed3f191eac\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">ACTIVE=A\nPENDING=B\nA_GOOD=1\nB_GOOD=0\nRETRIES_LEFT=3\nVERSION_A=2025.10.24.abc123\nVERSION_B=2025.10.25.def456\nSIG_B_OK=1\n</pre>\n</div></div><p>Bootloader logic:</p><ul><li><p>If <code>PENDING</code> is set and <code>RETRIES_LEFT&gt;0</code>, try booting that slot.</p></li><li><p>On first userspace start, systemd service <code>thor-boot-good.service</code> marks that slot GOOD and clears PENDING.</p></li><li><p>If the new slot fails to come up and report GOOD, <code>RETRIES_LEFT</code> decrements. Eventually we fall back.</p></li></ul><p>This is how rollback becomes automatic and boring.</p><h2 id=\"Spec:SecureThor+OTA-AppendixD.Secureboot&amp;fuseburning\">Appendix D. Secure boot &amp; fuse burning</h2><p>Final manufacturing / field-hardening step:</p><ol start=\"1\"><li><p>Generate signing keys for boot images and kernel. Guard them like crown jewels.</p></li><li><p>Program Thor\u2019s fuse bank / key slots so only images signed with that key will execute.</p></li><li><p>Write bootloader configured to:</p><ul><li><p>verify kernel+initramfs signature,</p></li><li><p>verify DTB signature (prevents DTB attacks that remap I/O or disable watchdogs),</p></li><li><p>refuse unsigned.</p></li></ul></li><li><p>Seal the LUKS decryption secret using that same root of trust (hardware-unique secret \u2192 unwrap disk key).</p></li><li><p>Permanently burn fuses so unsigned boot is no longer allowed.</p></li></ol><p>Now:</p><ul><li><p>Attacker with physical NVMe learns nothing (LUKS).</p></li><li><p>Attacker trying to inject malware kernel is blocked (secure boot).</p></li><li><p>Attacker trying to downgrade to an older vulnerable image is blocked if we enforce anti-rollback counters (monotonic version in boot metadata signed by us).</p></li></ul><p>This is the \u201cyou can steal it off the loading dock, but you can\u2019t turn it into your surveillance robot\u201d guarantee investors love and ops needs.</p><h4 id=\"Spec:SecureThor+OTA-AppendixE.Fleetobservabilitysurface\">Appendix E. Fleet observability surface</h4><p>We ship a tiny <code>/usr/bin/thor-status</code> binary/script with two modes:</p><ol start=\"1\"><li><p>Human-readable summary:</p><ul><li><p>Slot active / pending</p></li><li><p>Version hash</p></li><li><p>Secure boot enforced Y/N</p></li><li><p>LUKS active Y/N</p></li><li><p>Last update result</p></li><li><p>Rollback flag</p></li></ul></li><li><p>Prometheus text mode (<code>thor-status --metrics</code>):</p><ul><li><p><code>thor_slot_active{slot=&quot;A&quot;} 1</code></p></li><li><p><code>thor_os_version{slot=&quot;A&quot;,version=&quot;2025.10.25.def456&quot;} 1</code></p></li><li><p><code>thor_secure_boot_enforced 1</code></p></li><li><p><code>thor_root_encrypted 1</code></p></li><li><p><code>thor_update_success_total 9</code></p></li><li><p><code>thor_update_rollback_total 1</code></p></li></ul></li></ol><p>Vector scrapes that via <code>exec</code> every 30s (same model as tc/qdisc scrape from the QoS spec) and forwards to Mimir. Grafana gives:</p><ul><li><p>fleet-wide version map,</p></li><li><p>% of robots on latest signed build,</p></li><li><p>who rolled back last night,</p></li><li><p>who\u2019s unencrypted (red alert),</p></li><li><p>who\u2019s not fuse-locked yet (yellow alert; dev hardware).</p></li></ul><p>This folds OS integrity into the same monitoring fabric as network QoS, so ops sees not just \u201cis it online\u201d but \u201cis it running something we actually trust.\u201d</p><p>\u2013\u2013\u2013</p><p>Outcome</p><p>Thor boxes graduate from \u201cSD card with dreams\u201d to an updatable, encrypted, signed software appliance:</p><ul><li><p>We can stage a new OS, verify it in RAM via kexec without risking the unit.</p></li><li><p>We can rotate the rootfs on an encrypted NVMe LUKS slot, atomically, with A/B rollback.</p></li><li><p>We can enforce secure boot at the silicon level so nobody can boot unsigned junk or exfiltrate our models.</p></li><li><p>We get per-robot attestation and health metrics in Grafana instead of blind faith.</p></li></ul><p>This gives us safe OTA, post-compromise recovery, IP protection, and auditable configuration drift control \u2014 the grown-up stack you need before you start shipping fleets into angry warehouses.</p>"
        },
        {
          "id": "1177878534",
          "title": "Spec: CPU Pinning and Slices",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1177878534",
          "last_modified": "2025-10-22T22:08:24.812Z",
          "created_at": "2025-10-22T22:07:00.907Z",
          "body_html": "<h1 id=\"Spec:CPUPinningandSlices-Owner:\u2014Date:\u2014Approvers:\u2014\"><strong>Owner:</strong> \u2014<br/><strong>Date:</strong> \u2014<br/><strong>Approvers:</strong> \u2014</h1><hr/><h2 id=\"Spec:CPUPinningandSlices-ProblemStatement\">Problem Statement</h2><p>Realtime control loops, human-facing UIs, and sludge like compiles/backups are fist-fighting on the same CPUs. Linux is great, but \u201cbest effort\u201d isn\u2019t a strategy. We need explicit CPU partitioning so:</p><ul><li><p><strong>RT control</strong> meets jitter budgets.</p></li><li><p><strong>Interactive</strong> (SSH, Grafana, WebRTC signaling) stays snappy.</p></li><li><p><strong>Bulk</strong> (logging, compression, downloads, background jobs) doesn\u2019t poison latency.</p></li></ul><p>Goal: deterministic CPU isolation and priority with zero \u201cwhoops, irqbalance moved it.\u201d</p><hr/><h2 id=\"Spec:CPUPinningandSlices-Scope\">Scope</h2><p><strong>In scope</strong></p><ul><li><p>CPU partitioning via <strong>systemd slices</strong> (<code>rt.slice</code>, <code>interactive.slice</code>, <code>bulk.slice</code>)</p></li><li><p>Kernel boot isolation and IRQ steering for NIC/WireGuard</p></li><li><p>RPS/XPS and workqueue pinning</p></li><li><p>Service placement (drop-ins) for core daemons (control, sshd, vector, docker, nginx, wg-quick)</p></li><li><p>Basic observability (PSI, per-CPU usage, softirq/IRQ stats) exposed to Vector</p></li></ul><p><strong>Out of scope</strong></p><ul><li><p>Hard real-time kernels (PREEMPT_RT tuning beyond policy &amp; affinity)</p></li><li><p>NUMA-aware placement on &gt;1 socket</p></li><li><p>Container orchestrator-level policies (K8s cpusets, etc.)\u2014this spec is host/systemd centric</p></li></ul><hr/><h2 id=\"Spec:CPUPinningandSlices-DesignOverview\">Design Overview</h2><h3 id=\"Spec:CPUPinningandSlices-CPUtopology(example)\">CPU topology (example)</h3><ul><li><p><strong>RT cores:</strong> 2\u20133 (tight, deterministic)</p></li><li><p><strong>General cores:</strong> 0\u20131 (interactive + bulk + IRQs + crypto)</p></li></ul><p>Adjust numbers to your box; the pattern holds.</p><h3 id=\"Spec:CPUPinningandSlices-Kernelbootline\">Kernel boot line</h3><p>Pin kernel noise off RT cores and bias IRQs to general cores:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"c4ca02ab-4897-4c4e-a12b-a5d85bcc8cbd\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">isolcpus=managed,2-3 nohz_full=2-3 rcu_nocbs=2-3 irqaffinity=0-1\n</pre>\n</div></div><ul><li><p><code><span class=\"inline-comment-marker\" data-ref=\"14d3bb55-719c-4530-b5be-403b60ad75c2\">isolcpus=managed</span></code>: lets systemd cpuset manage those cores while keeping scheduler background out.</p></li><li><p><code>nohz_full</code>: ticks off on RT cores (less jitter).</p></li><li><p><code>rcu_nocbs</code>: push RCU callbacks away.</p></li><li><p><code>irqaffinity=0-1</code>: initial IRQ placement.</p></li></ul><h3 id=\"Spec:CPUPinningandSlices-Slices&amp;policies\">Slices &amp; policies</h3><p>We define three slices with cpusets and priorities:</p><p><strong><span class=\"inline-comment-marker\" data-ref=\"502131f3-dbd9-4767-977d-aca686ce10e2\">rt.slice</span></strong></p><ul><li><p><code>AllowedCPUs=2-3</code></p></li><li><p><code>CPUSchedulingPolicy=fifo</code></p></li><li><p><code>CPUSchedulingPriority=90</code> (or whatever your stack needs)</p></li><li><p><code>CPUWeight=</code> not relevant for RT, but keep defaults</p></li><li><p><code>AllowedMemoryNodes=0</code> if single NUMA node (otherwise omit)</p></li></ul><p><strong>interactive.slice</strong></p><ul><li><p><code>AllowedCPUs=0-1</code></p></li><li><p><code>CPUWeight=900</code> (favored over bulk)</p></li><li><p><code>IOSchedulingClass=best-effort</code></p></li><li><p><code>IOSchedulingPriority=2</code></p></li><li><p><code>Nice=-5</code> (optional; don\u2019t fight RT)</p></li></ul><p><strong>bulk.slice</strong></p><ul><li><p><code>AllowedCPUs=0-1</code></p></li><li><p><code>CPUWeight=100</code></p></li><li><p><code>IOSchedulingClass=idle</code></p></li><li><p><code>Nice=10</code></p></li></ul><h3 id=\"Spec:CPUPinningandSlices-IRQs,softirq,andworkers\">IRQs, softirq, and workers</h3><ul><li><p><strong><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\">NIC IRQs</span></strong><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\"> \u2192 CPUs 0\u20131</span><br/><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\">Write </span><code><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\">smp_affinity</span></code><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\"> masks for eth0 (and friends).</span></p></li><li><p><strong><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\">RPS/XPS</span></strong><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\"> \u2192 CPUs 0\u20131</span><br/><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\">Keep NAPI processing off RT cores.</span></p></li><li><p><strong><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\">Workqueues</span></strong><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\"> (</span><code><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\">/sys/devices/virtual/workqueue/cpumask</span></code><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\">) \u2192 0\u20131</span><br/><span class=\"inline-comment-marker\" data-ref=\"c0186908-5b35-45b1-900e-42bd7c0b5ac7\">Crypto/compress/kworkers won\u2019t trespass onto RT cores.</span></p></li><li><p><strong><span class=\"inline-comment-marker\" data-ref=\"2d7edcd0-c530-4803-81f8-8cee752aa768\">WireGuard</span></strong><br/>Kernel datapath obeys IRQ/RPS; userspace <code>wg-quick@wg0.service</code> runs in <code>interactive.slice</code> (or <code>bulk.slice</code> if you prefer).</p></li></ul><h3 id=\"Spec:CPUPinningandSlices-Serviceplacement\">Service placement</h3><ul><li><p><strong>Control loop / robot RT stack</strong> \u2192 <code>rt.slice</code></p></li><li><p><strong>sshd, nginx, grafana-agent, wg-quick, Vector</strong> \u2192 <code>interactive.slice</code></p></li><li><p><strong>docker, package updates, backups, compiles, log processors</strong> \u2192 <code>bulk.slice</code></p></li></ul><p>Everything else defaults to <code>bulk.slice</code> unless promoted.</p><hr/><h2 id=\"Spec:CPUPinningandSlices-Milestones\">Milestones</h2><div class=\"table-wrap\"><table data-layout=\"default\" data-local-id=\"d6c1660d-fbe0-42ec-8583-7b82daf397be\" class=\"confluenceTable\"><tbody><tr><th class=\"confluenceTh\"><p>Phase</p></th><th class=\"confluenceTh\"><p>Deliverable</p></th><th class=\"confluenceTh\"><p>Verification</p></th></tr><tr><td class=\"confluenceTd\"><p><strong>M1 \u2013 Kernel &amp; slices</strong></p></td><td class=\"confluenceTd\"><p>Boot with isolcpus/nohz_full/rcu_nocbs; slices defined</p></td><td class=\"confluenceTd\"><p><code>systemd-cgls</code> shows slices; <code>cat /proc/cmdline</code> matches</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>M2 \u2013 IRQ/RPS/XPS/workqueues</strong></p></td><td class=\"confluenceTd\"><p>IRQ masks + RPS/XPS + workqueue cpumask persisted</p></td><td class=\"confluenceTd\"><p><code>cat /proc/interrupts</code> increments on 0\u20131 only for NIC; RPS/XPS files = 0x3</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>M3 \u2013 Service placement</strong></p></td><td class=\"confluenceTd\"><p>Drop-ins applied for core services</p></td><td class=\"confluenceTd\"><p><code>systemd-cgtop</code> shows services under correct slices</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>M4 \u2013 Observability</strong></p></td><td class=\"confluenceTd\"><p>Vector ingest of CPU/PSI/softirq and IRQ stats</p></td><td class=\"confluenceTd\"><p>Grafana shows stable jitter; alerts wired</p></td></tr><tr><td class=\"confluenceTd\"><p><strong>M5 \u2013 Load test &amp; tune</strong></p></td><td class=\"confluenceTd\"><p>iperf/WebRTC storms don\u2019t degrade RT jitter</p></td><td class=\"confluenceTd\"><p>Control loop jitter &lt; target under stress</p></td></tr></tbody></table></div><hr/><h2 id=\"Spec:CPUPinningandSlices-Observability&amp;Verification\">Observability &amp; Verification</h2><p><strong>Metrics to export (low overhead, exec via Vector):</strong></p><ul><li><p><strong>CPU PSI:</strong> <code>/proc/pressure/cpu</code> \u2192 <code>psi_cpu_some</code>, <code>psi_cpu_full</code> (avg10/60/300)</p></li><li><p><strong>Per-CPU utilization:</strong> deltas from <code>/proc/stat</code> \u2192 <code>cpu_seconds_total{cpu=&quot;N&quot;,mode=&quot;user|system|irq|softirq|idle|steal&quot;}</code></p></li><li><p><strong>IRQ distribution:</strong> <code>/proc/interrupts</code> per-IRQ deltas for NIC/eth0 &amp; wg; verify affinity</p></li><li><p><strong>Softirq pressure:</strong> <code>/proc/net/softnet_stat</code> \u2192 dropped/squeezed counters</p></li><li><p><strong>cgroup CPU usage per slice:</strong> <code>/sys/fs/cgroup/&lt;slice&gt;/cpu.stat</code> (cgroup v2: <code>usage_usec</code>, <code>user_usec</code>, <code>system_usec</code>)</p></li><li><p><strong>Sched latency (optional):</strong> <code>/proc/schedstat</code> deltas to estimate runqueue wait (only if needed)</p></li></ul><p><strong>Acceptance checks</strong></p><ul><li><p>Under bulk upload + docker build, RT loop period and 99.9th percentile latency remain within budget.</p></li><li><p><code>ksoftirqd/*</code> threads run on CPUs 0\u20131 during load (<code>ps -eLo pid,psr,comm | grep ksoftirqd</code>).</p></li><li><p>NIC IRQ counters climb only on CPUs 0\u20131.</p></li><li><p>PSI <code>cpu some</code> for <code>rt.slice</code> \u2248 0 under steady-state (means it isn\u2019t starved).</p></li></ul><hr/><h2 id=\"Spec:CPUPinningandSlices-Appendices\">Appendices</h2><h3 id=\"Spec:CPUPinningandSlices-A)Slicedefinitions\">A) Slice definitions</h3><p><code>/etc/systemd/system/rt.slice</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"d1223694-e0d7-4a47-ac82-03b758a4a40b\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[Slice]\nAllowedCPUs=2-3\nAllowedMemoryNodes=0\n</pre>\n</div></div><p><code>/etc/systemd/system/interactive.slice</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"3da9f3e3-20fd-4023-94af-c6633db8228d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[Slice]\nAllowedCPUs=0-1\nCPUWeight=900\nIOSchedulingClass=best-effort\nIOSchedulingPriority=2\n</pre>\n</div></div><p><code>/etc/systemd/system/bulk.slice</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"3a565c76-98d9-45d7-8cf3-30a6e3744279\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[Slice]\nAllowedCPUs=0-1\nCPUWeight=100\nIOSchedulingClass=idle\n</pre>\n</div></div><p>Reload: <code>systemctl daemon-reload</code></p><h3 id=\"Spec:CPUPinningandSlices-B)Servicedrop-ins(examples)\">B) Service drop-ins (examples)</h3><p><strong>RT control</strong> <code>/etc/systemd/system/robot-rt.service.d/policy.conf</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"aeeb9aa6-d6b5-4342-af32-5af5ccfcd6fb\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[Service]\nSlice=rt.slice\nCPUSchedulingPolicy=fifo\nCPUSchedulingPriority=90\nLimitRTPRIO=95\nLimitMEMLOCK=infinity\n</pre>\n</div></div><p><strong>WireGuard</strong> <code>/etc/systemd/system/wg-quick@wg0.service.d/cpu.conf</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"5fb96699-62d2-4a2e-a765-7a71ec2c9009\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[Service]\nSlice=interactive.slice\n</pre>\n</div></div><p><strong>Vector</strong> <code>/etc/systemd/system/vector.service.d/cpu.conf</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"11f27d08-3bdd-4047-9d79-717a964b0c6b\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[Service]\nSlice=interactive.slice\nNice=-2\n</pre>\n</div></div><p><strong>Docker</strong> <code>/etc/systemd/system/docker.service.d/cpu.conf</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"e014672c-c787-4130-86d3-6653afc6a9f5\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[Service]\nSlice=bulk.slice\n</pre>\n</div></div><h3 id=\"Spec:CPUPinningandSlices-C)IRQ,RPS/XPS,workqueuepinning(persistedoneshot)\">C) IRQ, RPS/XPS, workqueue pinning (persisted oneshot)</h3><p><code>/usr/local/sbin/net_affinity.sh</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"e4af7be4-8c50-4c78-9fc2-3ba693bfa926\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">#!/usr/bin/env bash\nset -euxo pipefail\nIF=&quot;${1:-eth0}&quot;\nGEN_MASK_HEX=3   # CPUs 0-1\n\n# Pin NIC IRQs\nfor IRQ in $(grep -w &quot;$IF&quot; /proc/interrupts | awk -F: '{print $1}'); do\n  printf &quot;%x&quot; &quot;$GEN_MASK_HEX&quot; | tee &quot;/proc/irq/$IRQ/smp_affinity&quot; &gt;/dev/null\ndone\n\n# RPS/XPS\nMASK_HEX=$(printf &quot;%x&quot; $GEN_MASK_HEX)\nfor q in /sys/class/net/$IF/queues/rx-*; do echo &quot;$MASK_HEX&quot; | tee &quot;$q/rps_cpus&quot; &gt;/dev/null; done\nfor q in /sys/class/net/$IF/queues/tx-*; do echo &quot;$MASK_HEX&quot; | tee &quot;$q/xps_cpus&quot; &gt;/dev/null; done\n\n# Workqueues\necho &quot;$MASK_HEX&quot; | tee /sys/devices/virtual/workqueue/cpumask &gt;/dev/null\n</pre>\n</div></div><p><code>/etc/systemd/system/net-affinity@.service</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"f75de9ba-7e1f-4c15-94ba-4481c700b134\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[Unit]\nDescription=Pin IRQ/RPS/XPS/workqueues for %I\nAfter=network-online.target\nRequires=network-online.target\n\n[Service]\nType=oneshot\nExecStart=/usr/local/sbin/net_affinity.sh %I\nRemainAfterExit=yes\n\n[Install]\nWantedBy=multi-user.target\n</pre>\n</div></div><p>Enable: <code>systemctl enable net-affinity@eth0</code></p><h3 id=\"Spec:CPUPinningandSlices-D)Offloadhygiene(latency&gt;throughput)\">D) Offload hygiene (latency &gt; throughput)</h3><p><code>/usr/local/sbin/net_offloads.sh</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"b652d1a5-9cd3-45e0-ac8a-cce5426c0c84\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">#!/usr/bin/env bash\nIF=&quot;${1:-eth0}&quot;\nethtool -K &quot;$IF&quot; gro off gso off tso off lro off || true\nsysctl -w net.core.netdev_max_backlog=1000\n</pre>\n</div></div><p><code>/etc/systemd/system/net-offloads@.service</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"0a38d825-0c1b-43ac-8e01-e09db26e5b10\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[Unit]\nDescription=Disable latency-harmful offloads for %I\nAfter=network-online.target\n\n[Service]\nType=oneshot\nExecStart=/usr/local/sbin/net_offloads.sh %I\nRemainAfterExit=yes\n\n[Install]\nWantedBy=multi-user.target\n</pre>\n</div></div><h3 id=\"Spec:CPUPinningandSlices-E)Vectorexec:CPU/PSI/IRQmetrics(lean)\">E) Vector exec: CPU/PSI/IRQ metrics (lean)</h3><p><code>/usr/local/sbin/cpu_metrics.sh</code></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"e6a5318a-ec61-4055-85e9-18cc75b47c31\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">#!/usr/bin/env bash\nset -euo pipefail\n\n# PSI\nawk '/some/ {print &quot;psi_cpu_some_avg10 &quot; $2 &quot;\\npsi_cpu_some_avg60 &quot; $3 &quot;\\npsi_cpu_some_avg300 &quot; $4}\n     /full/ {print &quot;psi_cpu_full_avg10 &quot; $2 &quot;\\npsi_cpu_full_avg60 &quot; $3 &quot;\\npsi_cpu_full_avg300 &quot; $4}' \\\n  /proc/pressure/cpu 2&gt;/dev/null\n\n# /proc/stat (per-CPU) \u2014 raw counters\nawk '/^cpu[0-9]+ /{\n  cpu=$1; user=$2; nice=$3; system=$4; idle=$5; iowait=$6; irq=$7; softirq=$8; steal=$9; guest=$10; guest_nice=$11;\n  printf &quot;cpu_seconds_total{cpu=\\&quot;%s\\&quot;,mode=\\&quot;user\\&quot;} %f\\n&quot;, cpu, user/100;\n  printf &quot;cpu_seconds_total{cpu=\\&quot;%s\\&quot;,mode=\\&quot;system\\&quot;} %f\\n&quot;, cpu, system/100;\n  printf &quot;cpu_seconds_total{cpu=\\&quot;%s\\&quot;,mode=\\&quot;idle\\&quot;} %f\\n&quot;, cpu, idle/100;\n  printf &quot;cpu_seconds_total{cpu=\\&quot;%s\\&quot;,mode=\\&quot;irq\\&quot;} %f\\n&quot;, cpu, irq/100;\n  printf &quot;cpu_seconds_total{cpu=\\&quot;%s\\&quot;,mode=\\&quot;softirq\\&quot;} %f\\n&quot;, cpu, softirq/100;\n  printf &quot;cpu_seconds_total{cpu=\\&quot;%s\\&quot;,mode=\\&quot;steal\\&quot;} %f\\n&quot;, cpu, steal/100;\n}' /proc/stat\n\n# softnet_stat drops/squeezes (sum over CPUs)\nawk '{d+=strtonum(&quot;0x&quot;$2); s+=strtonum(&quot;0x&quot;$3)} END{\n  print &quot;softnet_dropped_total &quot; d; print &quot;softnet_squeezed_total &quot; s\n}' /proc/net/softnet_stat 2&gt;/dev/null\n\n# cgroup v2 cpu.stat per slice (if present)\nfor S in rt.slice interactive.slice bulk.slice; do\n  P=&quot;/sys/fs/cgroup/$S/cpu.stat&quot;\n  [ -f &quot;$P&quot; ] || continue\n  awk -v s=&quot;$S&quot; '/usage_usec|user_usec|system_usec/{\n    gsub(&quot;_usec&quot;,&quot;&quot;,$1); printf &quot;cgroup_cpu_usec_total{slice=\\&quot;%s\\&quot;,mode=\\&quot;%s\\&quot;} %s\\n&quot;, s,$1,$2\n  }' &quot;$P&quot;\ndone\n</pre>\n</div></div><p>Vector source:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"c1ac97f1-eecd-482c-89ea-3c9ae018fae9\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">[sources.cpu_metrics]\ntype = &quot;exec&quot;\ncommand = [&quot;/usr/local/sbin/cpu_metrics.sh&quot;]\ninterval_secs = 15\ntimeout_secs = 3\n</pre>\n</div></div><h3 id=\"Spec:CPUPinningandSlices-F)Sanitycommands\">F) Sanity commands</h3><ul><li><p>Slices &amp; placement: <code>systemd-cgtop</code> / <code>systemctl status &lt;svc&gt;</code></p></li><li><p>IRQs pinned: <code>grep -E &quot;eth0|mlx|ixgbe&quot; /proc/interrupts</code></p></li><li><p>ksoftirqd on 0\u20131: <code>ps -eLo pid,psr,comm | grep ksoftirqd</code></p></li><li><p>Cores in use by services: <code>taskset -pc $(pidof &lt;proc&gt;)</code></p></li><li><p>RT policy active: <code>chrt -p $(pidof robot-rt)</code></p></li></ul><hr/><h2 id=\"Spec:CPUPinningandSlices-Outcome\">Outcome</h2><p>Three CPU lanes with teeth. RT threads live on clean cores under FIFO policy; interactive stays responsive; bulk can grind without wrecking latency. IRQs, softirq, and workers are shoved off the RT island. Metrics prove it, not vibes.</p>"
        },
        {
          "id": "1151303693",
          "title": "Spec: HMND Core Control Plane",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1151303693",
          "last_modified": "2025-10-21T12:52:24.355Z",
          "created_at": "2025-10-11T00:05:36.975Z",
          "body_html": "<p><strong>Summary</strong>: Production-grade Global Control Plane for Humanoid robots</p><p><strong>Owner</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:15d56293-96ff-40d2-a06d-912f776e2042\" href=\"https://sklvc.atlassian.net/wiki/people/712020:15d56293-96ff-40d2-a06d-912f776e2042?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"893157488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Cody Griffin</a> </p><p><strong>Date</strong>: <time datetime=\"2025-10-12\" class=\"date-past\">12 Oct 2025</time> </p><p><strong>Approvers</strong>: <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:b3825005-5f3b-46cb-ba96-1a283a7f919e\" href=\"https://sklvc.atlassian.net/wiki/people/712020:b3825005-5f3b-46cb-ba96-1a283a7f919e?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"505479187\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Adam Kelsall</a> <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:32a86ac6-b682-430a-8b0d-1fedc3d67ec6\" href=\"https://sklvc.atlassian.net/wiki/people/712020:32a86ac6-b682-430a-8b0d-1fedc3d67ec6?ref=confluence\" target=\"_blank\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Leo Lesin (Deactivated)</a> <a class=\"confluence-userlink user-mention\" data-account-id=\"712020:42e393f5-b6fe-44da-9392-749211795e55\" href=\"https://sklvc.atlassian.net/wiki/people/712020:42e393f5-b6fe-44da-9392-749211795e55?ref=confluence\" target=\"_blank\" data-linked-resource-id=\"1085341714\" data-linked-resource-version=\"1\" data-linked-resource-type=\"userinfo\" data-base-url=\"https://sklvc.atlassian.net/wiki\">Yiannis Levantis</a> </p><p><strong>Informed</strong>: most people\u2026</p><h2 id=\"Spec:HMNDCoreControlPlane-ProblemStatement\">Problem Statement</h2><p>While we currently have a small development fleet, we are already have 3 models spread across 3 engineering sites.  In the future, we\u2019ll have thousands of robots across hundreds of customer sites.  We have the opportunity now to start thinking about a growing fleet while starting small and relatively lean.</p><p>Our current processes involve individual developers setting hostnames and adding lines the the \u201cenv_vars\u201d script which is sourced when you activate a Pixi environment on the robot.  Or setting static IPs in our Unify gear.  Honestly fine for less than a dozen robots, but moving forward we need to start thinking longer term about how we identify, authenticate and authorize users and robots to our cloud infrastructure.</p><p>While for Alpha, we have largely been able to survive with ad-hoc infrastructure and processes, for Beta we should put in place some global \u201ccore\u201d infrastructure supporting:</p><ul><li><p>robot identity and provisioning</p></li><li><p>software updates and release channels,</p></li><li><p>observability - metrics, logs, traces</p><ul><li><p>auditing (future)</p></li><li><p>events (future)</p></li></ul></li><li><p>jurisdiction-scoped concerns like data sovereignty (future)</p></li><li><p>site-local realtime services like robot teleoperation (future scope)</p></li></ul><p>We should maintain our existing \u201clab\u201d infrastructure as-is - the feature-set is different (data collection and training primarily).  Our Core infrastructure will live in London, probably with backups in another region.  At some point we may need to support multiple jurisdictions, but for now we\u2019ll treat our existing lab infrastructure as a default jurisdiction.  Our initial \u201csites\u201d will be London, Boston and Vancouver.</p><p>When robots are built, they will be provisioned with their <strong>static identity</strong>: model, serial number, date, origin - anything we want to track for the lifetime of the robot.  When robots are deployed, they will be provisioned with a <strong>dynamic identity</strong> or lease: site, jurisdiction, account, current software version - things that can change over time as a robot may be transferred repeatedly before decommissioning.</p><p>The key points of this review before we commit to this path:</p><ol start=\"1\"><li><p>Can we leverage a shared, global control plane for all Humanoid robots?  This is a major win operationally for us, and I think its a pre-requisite.</p></li><li><p>What are the reliability requirements?  Arbitrarily I\u2019m shooting for 99.9% to start.</p></li><li><p>Certificate rotations?  How long do we expect robots to exist without connectivity?  </p></li></ol><h2 id=\"Spec:HMNDCoreControlPlane-Scope(Phase1)\">Scope (Phase 1)</h2><p><strong>In-scope</strong></p><ul><li><p>CI-driven AWS infrastructure using Terraform via GitHub OIDC.</p></li><li><p>Core identity, release, and metrics services for fleet management.</p></li><li><p>PKI for static and dynamic identity.  </p></li><li><p>Automated provisioning/claiming and update distribution.</p></li><li><p>Observability stack (Grafana / Loki / Tempo / Mimir / ClickHouse).</p></li><li><p>High availability across multiple AZs.</p></li><li><p>Blue/green deploys and safe schema migrations.</p></li><li><p>Operational visibility even when application Kubernetes clusters are down.</p></li></ul><p><strong>Out-of-scope </strong></p><ul><li><p>Teleoperation or SSH access data plane: control traffic only for now</p></li><li><p>Customer-facing web apps beyond a simple status page (humanoid console should be unaffected).</p></li><li><p>Multi-tenancy or non-anonymized data (currently the scope of existing data pipeline)</p></li></ul><h2 id=\"Spec:HMNDCoreControlPlane-DesignOverview\">Design Overview</h2><p>At the top-most level, we have our AWS root account.  We already have an environment for our lab - we should create a new account in AWS for each core environment we want to support.  We will probably have dev and prod, maybe staging, maybe previews per developer branch.</p><p>Each environment is completely isolated, and we\u2019ll be starting w/ just a <code>core.dev.hmnd.ai</code> for development.  The expectation is we simply clone the infrastructure later when we need a production environment.  Site-specific services can be hung off this core for data sovereignty or latency-related reasons (perhaps in one or more other, customer-centric accounts).  The intent of the core stack is to provide a single, global control plane for Humanoid\u2019s robots.  Its a single pane of glass for Humanoid to manage a fleet of robots, without getting tied up with data sovereignty or performance concerns.</p><p /><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"1291\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1151303693/Untitled%20Diagram-1760271223159.drawio.png?api=v2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1151303693/Untitled%20Diagram-1760271223159.drawio.png?api=v2\" loading=\"lazy\"></span><h3 id=\"Spec:HMNDCoreControlPlane-AccountsandIdentity\">Accounts and Identity</h3><ul><li><p>Root/Management account: hosts <code>hmnd.ai</code> , delegates DNS, manages AWS Org + SSO. </p><ul><li><p>No \u201creal\u201d infrastructure.</p></li><li><p>Break glass - if we need access to our accounts outside of CI or existing roles.</p></li></ul></li><li><p>Dev and Prod accounts: core workload environments.</p><ul><li><p>Google Workspace provides SSO via AWS IAM Identity Center.</p><ul><li><p>sync google groups w/ ssosync or similar</p></li></ul></li><li><p>GitHub Actions assume per-env terraform deployment role via OIDC; no long-lived keys.</p></li><li><p>mTLS and OIDC ALBs for HTTP access to core services</p></li><li><p>Break glass - some manual roles that could be assumed which can bounce instances/services or make administrative changes (no manual infra changes)</p></li></ul></li><li><p>PKI for robot identity</p><ul><li><p>Root CA for each environment - hopefully AWS ACM so we aren\u2019t managing re-issue ceremonies ourselves</p><ul><li><p><a href=\"https://support.hashicorp.com/hc/en-us/articles/5784319448851-Vault-as-an-Intermediate-CA-with-AWS-Certificate-Manager-as-the-Root-CA\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://support.hashicorp.com/hc/en-us/articles/5784319448851-Vault-as-an-Intermediate-CA-with-AWS-Certificate-Manager-as-the-Root-CA</a> </p></li></ul></li><li><p>Intermediate CAs</p><ul><li><p>Global for provisioning robots, signing updates</p></li><li><p>Jurisdiction or customer enrollment for smaller scope (future)</p></li></ul></li><li><p>Mint certificates for static identity - basically a robot birth certificate</p></li><li><p>Mint certificates for dynamic identity - basically deployment paperwork (future)</p></li><li><p>Mint certificates to be imported into ACM for Robot ALB</p></li></ul></li></ul><h3 id=\"Spec:HMNDCoreControlPlane-DeploymentModel\">Deployment Model</h3><ul><li><p>Bootstrap (CloudFormation) \u2014 creates tfstate S3, DynamoDB lock, initial terraform deployment role.</p><ul><li><p>The only \u201cmanual\u201d deployment.</p></li></ul></li><li><p>Terraform (hmnd-core) \u2014 defines all VPCs, ECS clusters, RDS, S3, Vault, observability, etc.</p><ul><li><p>No manual deployments.</p></li></ul></li><li><p>CI/CD \u2014 PR to plan infra (merge to apply), deploy preview service?</p><ul><li><p>hmnd/hmnd_cloud/core - terraform infra</p></li><li><p>slightly different layout from existing hmnd_cloud infra, but we can consolidate later after getting some good habits</p></li></ul></li></ul><h3 id=\"Spec:HMNDCoreControlPlane-CoreEndpoints\">Core Endpoints</h3><ul><li><p>api.core.$env.cloud.hmnd.ai \u2014 registry API (provision, claim, update, events)</p></li><li><p>vault.core.$env.cloud.hmnd.ai \u2014 CA + cert issuance</p></li><li><p>status.core.$env.cloud.hmnd.ai \u2014 internal UI (OIDC protected)</p><ul><li><p>List of units, model + serial, current version, current site</p></li></ul></li><li><p>{grafana, logs, metrics, traces}.core.$env.cloud.hmnd.ai \u2014 observability stack</p></li></ul><p>These endpoints represent what humans would see via the OIDC ALB - robots authenticating w/ mTLS would see slightly different domains for security reasons.</p><div class=\"confluence-information-macro confluence-information-macro-information conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"info\" data-macro-id=\"84098fe7-f23a-4114-86d5-fc97f118ab6c\"><span class=\"aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon\"> </span><div class=\"confluence-information-macro-body\"><p><strong>Note</strong> - we specifically deploy our observability stack on something lower-level than k8s so that we can monitor our k8s clusters more reliably.</p></div></div><h3 id=\"Spec:HMNDCoreControlPlane-DataModel(Postgres/Aurora)\">Data Model (Postgres/Aurora)</h3><p>The data model is relatively standard SQL.  A few tables, a few constraints.  A couple indices.  Maybe the odd materialized view.  Rows are written, updated periodically and queried in batches.  </p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"968\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1151303693/Untitled%20Diagram-1760350354211.drawio.png?api=v2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1151303693/Untitled%20Diagram-1760350354211.drawio.png?api=v2\" loading=\"lazy\"></span><p>Large artifacts stored in S3 (certificates, images) but referenced via sha256 in postgres.  </p><h3 id=\"Spec:HMNDCoreControlPlane-BulkStorage(S3)\">Bulk Storage (S3 )</h3><ul><li><p>images/ - signed release images (multiple gigabytes)</p></li><li><p>certs/ - certificate bundles (current and future)</p></li><li><p>crl/... - revocation lists (maybe)</p></li></ul><h3 id=\"Spec:HMNDCoreControlPlane-ObservabilityDataFlow\">Observability Data Flow</h3><p>Robot uses certificate to establish mTLS to ALB, which can then be used to write events to our observability stack.</p><p>Operators authenticates via OIDC; groups control dashboards.</p><h2 id=\"Spec:HMNDCoreControlPlane-ImplementationDetails\">Implementation Details</h2><h3 id=\"Spec:HMNDCoreControlPlane-Availability/Scaling\">Availability / Scaling</h3><ul><li><p>Vault PKI - replicated across AZs on EC2, backed up to S3 via snapshots.  Rolling upgrades (1 node at a time).</p><ul><li><p>High quality EBS volumes ideally - doing host volumes on ECS defeats the purpose.  No need for autoscaling.</p></li><li><p>If we out-grow a single PKI instance in the global core, we can create additional intermediate CAs later</p></li></ul></li><li><p>API services - scaled out on ECS (fargate) across AZs.  Blue/Green.  No state (easy)</p><ul><li><p>ECR + containers in scope, but give us local testing more easily than lambdas</p></li></ul></li><li><p>RDS Aurora Postgres - MultiAZ, AWS-managed upgrades.  Backups to S3.</p></li><li><p>Grafana Stack - EC2 + local storage for writes, flush to S3.   Rolling restarts (though HA may not be necessary at first)</p></li><li><p>S3 - replicate sensitive data to another bucket</p></li></ul><h3 id=\"Spec:HMNDCoreControlPlane-Security\">Security</h3><ul><li><p>TLS 1.3 everywhere; mTLS robots, OIDC humans.</p></li><li><p>IAM least-privilege roles per service.</p></li><li><p>KMS-encrypted buckets, RDS, EBS.</p></li><li><p>Secrets in AWS Secrets Manager / Vault.</p></li><li><p>Access logs and audit to CloudTrail + S3.</p></li></ul><div class=\"confluence-information-macro confluence-information-macro-information conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"info\" data-macro-id=\"39f78e34-f204-46c0-a8f1-d5b532d4c02d\"><span class=\"aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon\"> </span><div class=\"confluence-information-macro-body\"><p>\u201cEverything encrypted in transit.  Everything encrypted at rest.\u201d - Compliance people love this.</p></div></div><h3 id=\"Spec:HMNDCoreControlPlane-CI/CD\">CI / CD</h3><ul><li><p>GH Actions \u2192 AWS OIDC \u2192 TerraformDeployRole.</p></li><li><p>Plan on PR, Apply on Merge.</p><ul><li><p>All terraform changes serialized via CI</p></li></ul></li><li><p>Environment approvals for prod.</p></li></ul><h1 id=\"Spec:HMNDCoreControlPlane-Milestones\">Milestones</h1><ol start=\"1\"><li><p>Bootstrap complete - CloudFormation stack, CI role</p><ul><li><p>\n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1358\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1151303693_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"06be8f43-a245-4375-8c35-0374a2097fb2\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1358\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1358</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p></li><li><p>Github action\u2019s <code>terraform apply</code> is a no-op</p></li></ul></li><li><p>Core spine (dev) - API, Database, PKI</p><ul><li><p>\n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1359\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1151303693_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"fdace5e4-6f41-48cd-9160-366a0d0aab01\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1359\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1359</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p></li><li><p>\n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1360\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1151303693_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"a0fb44e0-5b3b-43f7-8172-4474f08e21f7\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1360\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1360</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p></li><li><p>\n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1364\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1151303693_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"bacadc59-29f4-4fd9-9599-e9d8c33d430c\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1364\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1364</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p></li><li><p>We can provision new robots - DB rows + certs minted</p></li></ul></li><li><p>ALBs (mTLS + OIDC)</p><ul><li><p>\n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1361\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1151303693_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"fa8dc026-e145-4061-be3c-9e892da3e252\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1361\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1361</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p></li><li><p>\n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1362\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1151303693_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"3938a47b-bb99-44d4-9fe0-45a6d8118df5\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1362\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1362</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p></li><li><p>Robots and Operators can authenticate to the core ALBs</p></li></ul></li><li><p>Observability live</p><ul><li><p>\n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1363\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1151303693_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"e9abf70f-2cb0-46c2-9a80-b9b47abee89c\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1363\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1363</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p></li><li><p>Robots can publish metrics via ALB w/ mTLS</p></li><li><p>Operators can manage dashboards via OIDC login</p></li></ul></li><li><p>Release channels flow</p><ul><li><p>\n\n    \n\n            \n\n\n\n\n    <span class=\"confluence-jim-macro jira-issue conf-macro output-block\" data-jira-key=\"HECO-1365\" data-client-id=\"SINGLE_2bfde1be-5be6-3c74-b2d0-1d02d8dea45d_1151303693_712020:08357394-7b07-4fcf-80fd-241cbe70f231\" data-hasbody=\"false\" data-macro-name=\"jira\" data-macro-id=\"78ac36be-2542-4628-a9d6-4ca073959746\">\n                <a href=\"https://sklvc.atlassian.net/browse/HECO-1365\" class=\"jira-issue-key\"><span class=\"aui-icon aui-icon-wait issue-placeholder\"> </span>HECO-1365</a>\n                    -\n            <span class=\"summary\">Getting issue details...</span>\n                                    <span class=\"aui-lozenge aui-lozenge-subtle aui-lozenge-default issue-placeholder\">STATUS</span>\n            </span>\n </p></li><li><p>Operators (or CI) can publish new releases - signed, stashed images in S3, row in database</p></li><li><p>Operators can promote releases within channels</p></li><li><p>Robots can fetch releases from assigned channel</p></li></ul></li><li><p>HA drills</p><ul><li><p>Survive AZ down</p></li><li><p>No downtime updates</p></li><li><p>Certificate renewals automated</p></li><li><p>Restore from backups (frequent on dev)</p></li></ul></li></ol><p>Estimated: 4\u20138 weeks with 1 core engineer.  Doesn\u2019t need to happen all at once.  </p><h2 id=\"Spec:HMNDCoreControlPlane-StandardOperatingProcedures(SOPs)\">Standard Operating Procedures (SOPs)</h2><p>This infrastructure will require some additional SOPs to be documented.</p><p><strong>Provisioning</strong></p><p>Operator runs a tool which POSTs to api.core.{env}.hmndi.ai/units with model, serial and other static metadata (like a CSR).  API mints certificate and writes to database before responding.  The tool can then write the resulting trust bundles to the robot\u2019s certificate store.</p><p>At this point the Operator has \u201cbootstrapped\u201d the robot\u2019s identity, and now the robot can access core services using mTLS.  </p><p><strong>Release Publishing</strong></p><p>Operator or CI runs a tool which POSTS to api.core.{env}.hmnd.ai/releases with the release image data in the POST body (and release metadata as headers).  The image data is written to S3 while the metadata is written to the DB (with some care being taken to avoid orphaned images).  The image data is written with a suffix containing the signature, and the resulting release manifest is returned in the response.  </p><p>When an image is published it may optionally be set to the current channel version.  All robots assigned to the channel will then pull the image and perform an OTA update.</p><p><strong>Channel Promotion</strong></p><p>Typically newly-published images are added to a \u201cdevelopment\u201d channel, and later promoted to a \u201cstable\u201d channel.</p><p>Metrics should be labeled by current release.</p><p><strong>Cert Rotation</strong></p><p>ALB?  Hopefully we can pick up from S3 or mirror from ACM?  Robots can be re-keyed transparently from the ALB\u2019s perspective, but the intermediate CA or root CA would be difficult.  Ideally overlap.</p><p>Robots?  Probably initiate rekey periodically.   This bounds how long robots can be offline before keys expire.  For dev we will do this very frequently.  For production, probably less often.</p><p><strong>Database Migrations</strong></p><p>Online safe pattern: add nullable column \u2192 backfill \u2192 enforce \u2192 drop old.</p><p>Rollback = drop column if unused.</p><p><strong>Upgrades / Rollouts</strong></p><p>ECS rolling updates (100% healthy min)</p><p><a href=\"https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_UpgradeDBInstance.PostgreSQL.html\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_UpgradeDBInstance.PostgreSQL.html</a> </p><p><strong>Incident Response</strong></p><p>Logs in Loki; traces in Tempo.</p><p>Event lag alarms via Mimir.</p><p>Rollback releases within a channel (opposite of promoting).</p><h2 id=\"Spec:HMNDCoreControlPlane-FutureExtensions(Phase2+)\">Future Extensions (Phase 2+)</h2><p>Teleop plane: OIDC humans \u2194 mTLS robots via regional relays (WebRTC / TURN).</p><p>Multi-region replication: ClickHouse shards per region; Vault intermediate per region.</p><p>Tenant isolation: scoped prefixes in CAS + group-based policy in API.</p><p>SSH Bastion: access robots via SSH, tied to authz + auditing</p><h1 id=\"Spec:HMNDCoreControlPlane-AppendixA:PKIwithVault\">Appendix A: PKI with Vault</h1><p>This appendix defines the public key infrastructure (PKI) architecture used to authenticate and authorize robots, operators, and cloud components. The design leverages AWS Certificate Manager (ACM) as the <em>root of trust</em>, with HashiCorp Vault operating as an <em>intermediate certificate authority (CA)</em>. Certificates issued from Vault are used to establish mutual TLS (mTLS) between robots and backend services, and to secure communication across all control-plane endpoints.</p><h2 id=\"Spec:HMNDCoreControlPlane-RootofTrust(AWSACM)\">Root of Trust (AWS ACM)</h2><p>AWS ACM serves as the system\u2019s root CA.<br/>It is created once and used solely to sign the Vault intermediate. This avoids exposing Vault-generated roots to long-term compromise and provides central visibility and revocation capabilities through AWS.</p><p>ACM\u2019s root certificate is:</p><ul><li><p>Offline by design: keys are never exported or accessible outside AWS.</p></li><li><p>Stored under an AWS account with restricted administrative access.</p></li><li><p>Used only to sign the Vault intermediate CA certificate (no end-entity certificates).</p></li></ul><p>Exported artifacts:</p><ul><li><p>Root certificate (public only) for inclusion in Vault\u2019s trust chain.</p></li><li><p>Optional: export the trust bundle (root + intermediates) for ALB and internal service consumption.</p></li></ul><h2 id=\"Spec:HMNDCoreControlPlane-VaultasIntermediateCA\">Vault as Intermediate CA</h2><p>Vault runs on an EC2 instance within a private subnet across multiple Availability Zones.<br/>The service uses integrated storage and auto-unseal (via AWS KMS) for HA operation. TLS termination is handled by ALB (with OIDC for human access), but mTLS validation happens internally for robots.</p><p>Vault configuration:</p><ul><li><p><code>pki_int</code> mount for issuing short-lived leaf certificates.</p></li><li><p>Intermediate CSR generated from Vault and signed by ACM root.</p></li><li><p>Resulting signed certificate chain imported back into Vault.</p></li><li><p>TTLs are intentionally short (e.g., 30 days) with automated rotation.</p></li></ul><p>Vault EC2 instances:</p><ul><li><p>Spread across \u22652 AZs using an ASG or manual multi-AZ deployment.</p></li><li><p>Bound to a security group permitting only ALB ingress and internal AWS access.</p></li><li><p>IAM instance profiles limited to KMS (for auto-unseal) and CloudWatch (for audit/logging).</p></li></ul><h2 id=\"Spec:HMNDCoreControlPlane-RobotCertificateIssuance\">Robot Certificate Issuance</h2><p>Each robot model (e.g., <code>alpha-wheelbase-v0</code>) has a unique serial number (e.g., <code>a1-00123</code>).<br/>Each physical robot includes <strong>two compute targets</strong>\u2014for example:</p><ul><li><p><code>a1-00123-orin</code></p></li><li><p><code>a1-00123-rtpc</code></p></li></ul><p>Certificates are minted separately for each compute node.<br/>Both share the same <em>authorization scope</em> (same robot identity) but have unique private keys and certificates for better compartmentalization.</p><p>Certificate Subject naming convention:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"ce846da0-5981-45ca-9859-4939d633b7c0\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">CN = robot.serial\nO  = model\nOU = compute_target</pre>\n</div></div><p>Example:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"2700446b-a864-4798-8e07-3a6cfe108d3a\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">CN = a1-00123\nO  = alpha-wheelbase\nOU = orin</pre>\n</div></div><p>Additional metadata (serial/model/compute_target) may also be stored in Vault\u2019s metadata for search and audit.</p><p>Each robot\u2019s certificate is created through a static provisioning workflow:</p><ol start=\"1\"><li><p>Robot generates its own private key and CSR locally.</p></li><li><p>CSR includes robot metadata and is submitted to a provisioning endpoint.</p></li><li><p>Vault signs and returns the certificate chain (cert + intermediate).</p></li><li><p>Private key <strong>never leaves the robot</strong>.</p></li></ol><h2 id=\"Spec:HMNDCoreControlPlane-CertificateRenewal\">Certificate Renewal</h2><p>Renewal is handled by Vault\u2019s PKI lease mechanism or an explicit renewal request from the robot.</p><p>Renewal policies:</p><ul><li><p>Robots renew certificates automatically within 7 days of expiry.</p></li><li><p>If renewal fails or the lease is revoked, the robot reverts to the provisioning workflow.</p></li><li><p>Expired or revoked certificates are invalidated in CRL/OCSP endpoints published by Vault and mirrored to S3 for ALB consumption.</p></li></ul><p>Automated renewal can use:</p><ul><li><p>Vault Agent with <code>auto_auth</code> and <code>template</code> stanzas (preferred for static deployments).</p></li><li><p>Lightweight CLI wrapper in the robot OS that runs as a systemd timer.</p></li></ul><h2 id=\"Spec:HMNDCoreControlPlane-CSRsandKeyHandling\">CSRs and Key Handling</h2><p>Private keys are <strong>always generated locally</strong> on the robot compute node\u2014either by OpenSSL, Rust/Python crypto libraries, or a TPM/HSM backend if available.</p><p>Process summary:</p><ul><li><p>Generate private key (<code>openssl genpkey</code> or library equivalent).</p></li><li><p>Generate CSR (<code>openssl req -new -key &lt;key&gt; -subj ...</code>).</p></li><li><p>Submit CSR to Vault API <code>/v1/pki_int/sign/robot</code>.</p></li><li><p>Receive signed certificate (PEM chain) and store locally.</p></li></ul><p>Vault is <strong>never trusted with private keys</strong>, only CSRs.<br/>This ensures key material cannot be leaked even if Vault is compromised.</p><h2 id=\"Spec:HMNDCoreControlPlane-NamingandMountStructureinVault\">Naming and Mount Structure in Vault</h2><p>Vault uses a structured naming convention for clarity and auditability:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"9dca4083-9efb-435a-b4b6-c7c3b0fbe9ea\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">pki/\n \u251c\u2500\u2500 root/            # ACM Root (read-only reference)\n \u251c\u2500\u2500 pki_int/         # Intermediate CA mount\n \u2502    \u251c\u2500\u2500 roles/\n \u2502    \u2502    \u251c\u2500\u2500 robot\n \u2502    \u2502    \u251c\u2500\u2500 human\n \u2502    \u2502    \u2514\u2500\u2500 service\n \u2502    \u251c\u2500\u2500 certs/\n \u2502    \u2514\u2500\u2500 crl/\n \u2514\u2500\u2500 metadata/\n      \u251c\u2500\u2500 robots/\n      \u2502    \u2514\u2500\u2500 &lt;serial&gt;/&lt;compute_target&gt;\n      \u251c\u2500\u2500 humans/\n      \u2514\u2500\u2500 services/</pre>\n</div></div><p>Role configuration (<code>pki_int/roles/robot</code>):</p><ul><li><p><code>allowed_domains = &quot;robots.dev.hmnd.ai&quot;</code></p></li><li><p><code>allow_subdomains = true</code></p></li><li><p><code>server_flag = true</code></p></li><li><p><code>client_flag = true</code></p></li><li><p><code>max_ttl = &quot;720h&quot;</code></p></li><li><p><code>require_cn = true</code></p></li><li><p><code>key_type = &quot;ec&quot;</code></p></li><li><p><code>key_bits = 256</code></p></li></ul><p>Common Name pattern: <code>*.robots.dev.hmnd.ai</code> (robots signed per compute target).</p><h2 id=\"Spec:HMNDCoreControlPlane-ApplicationLoadBalancer(ALB)mTLSConfiguration\">Application Load Balancer (ALB) mTLS Configuration</h2><p>The ALB serving robot APIs (e.g. <code>api.core.dev.hmnd.ai</code>) enforces mTLS for inbound robot connections.</p><p>Setup:</p><ol start=\"1\"><li><p>Import ACM trust bundle (root + Vault intermediate).</p></li><li><p>Enable <strong>\u201cRequire client certificate\u201d</strong> on the ALB listener.</p></li><li><p>ALB validates the client certificate chain against this trust bundle.</p></li><li><p>Downstream targets (e.g., FastAPI or Grafana Mimir) trust ALB headers indicating verified certificate subject.</p></li></ol><p>AWS CLI example:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"bbe251cf-93a2-42dc-b20d-00f7f60e93dd\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">aws acm import-certificate \\\n  --certificate-chain fileb://vault_chain.pem \\\n  --certificate fileb://root_cert.pem \\\n  --private-key fileb://dummy_key.pem</pre>\n</div></div><p>ALB listener configuration:</p><ul><li><p>HTTPS (443)</p></li><li><p>TLS policy enforcing TLS1.2+</p></li><li><p>Client authentication: required</p></li><li><p>Trust store: ACM bundle (Vault intermediate + root)</p></li><li><p>Forward headers: <code>X-Client-Cert-Subject</code>, <code>X-Client-Cert-Issuer</code></p></li></ul><p>ALB validation is sufficient for access control\u2014robots need no credentials beyond their valid client certificates.</p>"
        },
        {
          "id": "1154548100",
          "title": "Fleets",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1154548100",
          "last_modified": "2025-10-14T16:55:57.244Z",
          "created_at": "2025-10-14T16:21:09.185Z",
          "body_html": "<p>Many of our core business plans rely on selling a fleet of robots rather than individual robots.  This makes sense - building a single robot that can operate with enough uptime to satisfy industrial use-cases is impossible - but selling enough robots so that the aggregate uptime matches is much more feasible.  We won\u2019t really be viable shipping a single robot, and so we shouldn\u2019t worry about selling just a single robot \u201cfleet\u201d.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20251014-162423.png\" width=\"434\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1154548100/image-20251014-162423.png?version=1&amp;modificationDate=1760459065160&amp;cacheVersion=1&amp;api=v2&amp;width=434&amp;height=218\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1154548100/image-20251014-162423.png?version=1&amp;modificationDate=1760459065160&amp;cacheVersion=1&amp;api=v2\" data-height=\"354\" data-width=\"704\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1154548109\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20251014-162423.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1154548100\" data-linked-resource-container-version=\"1\" data-media-id=\"5f59dbaa-4210-48b2-b20b-a468cfb08d68\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1154548100/image-20251014-162423.png?version=1&amp;modificationDate=1760459065160&amp;cacheVersion=1&amp;api=v2&amp;width=704&amp;height=354 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1154548100/image-20251014-162423.png?version=1&amp;modificationDate=1760459065160&amp;cacheVersion=1&amp;api=v2&amp;width=434&amp;height=218 1x\"></span><p>But we won\u2019t have a fleet of robots until we manufacture a lot of robots.  And we won\u2019t be able to manufacture a lot of robots until we have a good robot.  The path to a scalable robotic fleet is through a really really good robot.   I\u2019m going to make the case here that we should probably focus on building a really good robot, and that a good fleet will follow.</p><h2 id=\"Fleets-GestaltTheory\">Gestalt Theory</h2><p>\u201cThe whole is greater than the sum of its parts\u201d.  Notice that greater doesn\u2019t really have a valence associated.  If we build a really good robot, I think its reasonable that a fleet of these robots will be even better.  And if we build a shitty robot, <span class=\"inline-comment-marker\" data-ref=\"d61a2d32-9ac8-44ca-8195-89d9ca0c0fc6\">we should only expect that a bunch of them will be even shittier</span>.  In this way, a fleet is effectively an amplifier.</p><p>So with this in mind - what does a really good robot look like?  Thinking as abstractly as possible, a really good robot is probably one that:</p><ol start=\"1\"><li><p>does what its asked (and nothing more)</p></li><li><p>provides insights into its status and history (how did it get here)</p></li><li><p><span class=\"inline-comment-marker\" data-ref=\"18288d33-b241-4bb2-8f8c-698ad42f13e5\">provides predictions about its future (where is it going)</span></p></li></ol><p>The first point is really about solving the commercially viable work.  The second two points are more about ensuring that some system can effectively \u201ccollaborate\u201d (non-safety context here).  If the robot is a perfectly-executing blackbox, it becomes impossible for humans or other robots to operate around it as there is no real idea of where it is going or what it may have already done.  So we need to expose this context.  This context is important for both HRI and fleet management.  Notice that I didn\u2019t include anything about reliability, performance, flexibility/adaptability - this is trying to just be as high-level as possible.  Of course these other items are important, but I\u2019d argue that they will largely fall under point 1 here (the robot can\u2019t do what its told if its broken or delocalized or whatever).</p><p>So - let\u2019s assume we build a \u201creally good robot\u201d .  What next?</p><h2 id=\"Fleets-TheFleetasaProxy\">The Fleet as a Proxy</h2><p>The overall logic behind fleet management rhymes a lot with the general history of the scalable infrastructure.  <span class=\"inline-comment-marker\" data-ref=\"81b9baec-a210-458a-9e97-afdab78c19af\">Instead of building giant reliable mainframes</span> with 99.999% uptime, just run <span class=\"inline-comment-marker\" data-ref=\"6c18d974-e8d9-467b-8836-664ee2cedad3\">hundreds of cheap servers</span> behind a load balancer.  Instead of building a hard disk that never fails, just store many copies of your data across a bunch of cheap disks and get the overall reliability up.  We are hoping to do the same thing - horizontally scaling our unit of work (the robot) to provide some sort of aggregate performance to the customer.  The key idea is we build a reverse proxy as a facade which provides a single interface over many individual backend components.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"400\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1154548100/Untitled%20Diagram-1760460408316.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1154548100/Untitled%20Diagram-1760460408316.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p>We can do this by effectively thinking of the Fleet Manager as a proxy to a number of robots.  Let\u2019s suppose for a moment that we have a simple \u201clocal\u201d API on each robot for implementing the 3 criteria from above.  We can use this API to task the robot and to retrieve status/history/upcoming tasks.  This API knows nothing about other robots.  We can treat our Fleet API almost like a reverse proxy to this robot API.  The Fleet Manager may need to provide some coordination (don\u2019t give robots the same tasks or the same chargers), but generally these behaviors would be built on top of the baseline robot - just as a large web service is built on top of individual server components.</p><h2 id=\"Fleets-Summary\">Summary</h2><p>Before we can build a great Fleet, we need to build a great robot.  And before we build a great Fleet API, we need to build a great Robot API.  It will be so much easier to scale a really good robot into a massive fleet than to scale a bad robot.   We should be thinking more about how we <span class=\"inline-comment-marker\" data-ref=\"360a2dd9-e916-4803-ac04-05047561ee8c\">deploy and task individual robots</span> with the confidence that layering coordination and group-management is largely a solved problem.  At least compared to building and deploying agentic robots.  </p><p />"
        },
        {
          "id": "1134395462",
          "title": "Wireguard: hmnd-tunnel",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1134395462",
          "last_modified": "2025-10-13T11:49:50.594Z",
          "created_at": "2025-10-01T11:59:18.386Z",
          "body_html": "<p>Our robots have a mini-network onboard across the various computers and sensors, but occasionally we want to extend this network to a developer laptop.  For pre-alpha robots, this was done using NAT where the Jetson computer could communicate with a developer laptop by way of the NUC.  The NUC would simply forward all the traffic to the Jetson.  Easy.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"866\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1134395462/Untitled%20Diagram-1759320225919.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1134395462/Untitled%20Diagram-1759320225919.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p>For Alpha this isn\u2019t so trivial, as we need BOTH the x86 RTPC and the Jetson/Orin to be accessible from the laptop at the same time.  If we want to use DDS, its extremely cumbersome to maintain this NAT since some DDS ports would need to be routed locally to the RTPC and some forwarded to the Orin.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"866\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1134395462/Untitled%20Diagram-1759320719959.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1134395462/Untitled%20Diagram-1759320719959.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p>The root issue here is that to the laptop, both the Orin and Jetson have the same IP (whatever the IP of the robot is), and so how can DDS establish who is who?  Any ROS node running on the Jetson has to advertise itself as something on the external IP of the robot.  Any ROS node on the RTPC must bind to both the external and internal interfaces, but it doesn\u2019t know how to resolve the ambiguities involved with the NAT.  And even worse - we need to somehow know which of the hundreds of ports get bound for each participant.  This is solvable, but removes a lot of flexibility.  Echoing topics or running debugging tools will create new DDS participants which require new ports - do we really expect developers to be tweaking firewall rules and DDS config just to echo topics?  Probably not\u2026</p><p><strong>Wireguard Tunnels</strong></p><p>Enter Wireguard: a simple VPN solution native to Linux where we can tunnel the developer\u2019s laptop over some external interface (WiFi) and then the laptop basically appears on the same routable network as the computers in the robot.  This makes it much easier to setup DDS and such for development use-cases.</p><p /><p><span class=\"inline-comment-marker\" data-ref=\"386d074e-4757-476b-9889-1b924a7446f8\">To simplify setup and management of wireguard, robots have a service running on port 1111 on the RTPC which provides a service for allocating tunnels.</span>  Many developers can all connect and can have visibility to which tunnels are active via the tunnel webpage at port 1111:</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20251001-122025.png\" width=\"857\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1134395462/image-20251001-122025.png?version=1&amp;modificationDate=1759321226837&amp;cacheVersion=1&amp;api=v2&amp;width=857&amp;height=336\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1134395462/image-20251001-122025.png?version=1&amp;modificationDate=1759321226837&amp;cacheVersion=1&amp;api=v2\" data-height=\"337\" data-width=\"857\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1134460982\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20251001-122025.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1134395462\" data-linked-resource-container-version=\"3\" data-media-id=\"6fb45a57-fb79-465d-83c7-263083b69410\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1134395462/image-20251001-122025.png?version=1&amp;modificationDate=1759321226837&amp;cacheVersion=1&amp;api=v2&amp;width=1542&amp;height=606 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1134395462/image-20251001-122025.png?version=1&amp;modificationDate=1759321226837&amp;cacheVersion=1&amp;api=v2&amp;width=857&amp;height=336 1x\"></span><p /><p>Now we can configure all DDS participants to be identical across all robots.  Because of transitive discovery, we should be able to get DDS configuration identical across even the laptops (though this is still a work in progress).</p><p><span class=\"inline-comment-marker\" data-ref=\"aea92ce0-f1a8-4a6a-962b-a27f19eab7c7\">To setup a tunnel, simply run the </span><code><span class=\"inline-comment-marker\" data-ref=\"aea92ce0-f1a8-4a6a-962b-a27f19eab7c7\">hmnd-tunnel</span></code><span class=\"inline-comment-marker\" data-ref=\"aea92ce0-f1a8-4a6a-962b-a27f19eab7c7\"> script from hmnd/tools and point it at the <span class=\"inline-comment-marker\" data-ref=\"3bd9e510-5c7a-4ebf-8687-a211a7433c55\">robot</span>:</span></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"f1ecba31-bcfb-4fa2-8688-5934f0bcb36d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">user@laptop:git/hmnd/tools$ ./hmnd-tunnel 10.44.10.10:1111\nBringing tunnel up: 1c6bbb560a (hmnd-1c6bbb560a via /etc/wireguard)\n[#] ip link add hmnd-1c6bbb560a type wireguard\n[#] wg setconf hmnd-1c6bbb560a /dev/fd/63\n[#] ip -4 address add 192.168.111.2/24 dev hmnd-1c6bbb560a\n[#] ip link set mtu 1420 up dev hmnd-1c6bbb560a\n[#] ip -4 route add 192.168.1.0/24 dev hmnd-1c6bbb560a\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:124,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:0,&quot;ttl_s&quot;:299}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:124,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:10,&quot;ttl_s&quot;:289}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:124,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:20,&quot;ttl_s&quot;:279}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:156,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:30,&quot;ttl_s&quot;:269}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:156,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:40,&quot;ttl_s&quot;:259}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:188,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:51,&quot;ttl_s&quot;:248}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:188,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:61,&quot;ttl_s&quot;:238}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:188,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:71,&quot;ttl_s&quot;:228}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:220,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:81,&quot;ttl_s&quot;:218}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:220,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:91,&quot;ttl_s&quot;:208}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:252,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:101,&quot;ttl_s&quot;:198}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:252,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:111,&quot;ttl_s&quot;:188}\n{&quot;id&quot;:&quot;1c6bbb560a&quot;,&quot;who&quot;:&quot;&quot;,&quot;client_ip&quot;:&quot;192.168.111.2&quot;,&quot;rx_bytes&quot;:180,&quot;tx_bytes&quot;:252,&quot;last_handshake_unix&quot;:1759321190,&quot;age_s&quot;:121,&quot;ttl_s&quot;:178}</pre>\n</div></div><p>As long as this runs, you will be able to access the RTPC and Orin on their internal IPs (192.168.1.1 and 192.168.1.2 respectively).  This should work on both MacOS and Linux (and maybe Windows via WSL2). </p><p><strong>DDS Config</strong></p><p>With <code>hmnd-tunnel</code> we can now use a \u201cuniversal\u201d DDS configuration.  The previous DDS config often required substituting the robot\u2019s external IP (due to NATing on PreAlpha) into the configuration files, or manually configuring some wireguard-related IP on Alpha.  This setup is toilsome and at times frustrating.</p><p><code>./tools/hmnd-provision $robot_type $robot_number</code> can be used to write a simple \u201cprovisioning\u201d file on each computer:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"ecffed6c-3d24-49e5-98e3-bed922ed18e5\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">$ cat /etc/hmnd/hmnd.env\nexport ROBOT=alpha\nexport ROBOT_ID=6</pre>\n</div></div><p>Now, if we connect a tunnel to the robot and pixi shell, we can have a full-mesh DDS setup.  When pixi activates the environment, it will either:</p><ol start=\"1\"><li><p>see <code>sw-internal</code> and configure CycloneDDS with the robot-side configuration (sourcing additional info from the provisioning file above)</p></li><li><p>see <code>hmnd-tunnel</code> and configure CycloneDDS with the laptop-side configuration.</p></li></ol><p>In both cases, the ROS_DOMAIN_ID is set to 200 - which is somewhat arbitrary.</p>"
        },
        {
          "id": "1140654136",
          "title": "Making Jira Tolerable",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1140654136",
          "last_modified": "2025-10-03T16:21:47.210Z",
          "created_at": "2025-10-03T13:42:58.665Z",
          "body_html": "<p><span class=\"inline-comment-marker\" data-ref=\"d6425308-00c0-434b-9ddb-8fd817fc867d\">Jira.  Few words instill more fear or paranoia into developers.</span>  Burn down charts, velocities, sprints, releases, backlogs, linked tickets, epics, stories, tasks, subtasks, initiatives blah blah blah.  \u201cJust let me code\u201d.  As much as we\u2019d love this to be the path, stakeholders DO need some visibility into what\u2019s actually going on.  The only thing worse than not doing anything at all is putting effort into the wrong things - and how can stakeholders be sure that our efforts are going to the right things if there is no visibility?</p><p>Sure - we could ask them to look at GitHub PRs.  But git is highly optimized to the needs of developers at the expense of more managerial types.  And usually Jira is setup for the benefit of managers at the expense of developer workflows.  Unlike Git or Github though, Jira is endless configurable enterprise slop software.  Can we make it work for developers too?</p><h2 id=\"MakingJiraTolerable-GitHubIntegration\">GitHub Integration</h2><p>Because developers are already working with GitHub, we should first explore how to take advantage of automation here.  Using the <a href=\"https://support.atlassian.com/jira-cloud-administration/docs/integrate-with-github/\" class=\"external-link\" rel=\"nofollow\">GitHub/Jira Connector</a> developers can link their branches/PRs with Jira by simply including the ticket number in the branch name or PR description.   <code>codg/xyz-123-work-description</code> would be linked to XYZ-123 for example.</p><p>Automation can be added so that when a PR is opened for a branch, the ticket moves to in-progress, and when the PR is merged, the ticket is resolved as done.  If the PR is closed, you could resolve as canceled, and if the branch is re-opened in another PR, the ticket could be resurrected.</p><p>Just these basic bits of automation can help to meet developers in the middle, making it easier to get accurate information within Jira for management types.  If you really want to make things more strict, you can also add a pre-commit check that ensures that the commit or branch name reference a valid ticket.</p><h2 id=\"MakingJiraTolerable-UsingJira:Developers\">Using Jira: Developers</h2><p>As a developer, using Jira itself is often frustrating.  I don\u2019t care about sprint boards or organizing things or linking epics or any of this nonsense.  I know that I need to write code and solve problems.  I think a big part of this gap is that Jira\u2019s minimal unit is the \u201c<span class=\"inline-comment-marker\" data-ref=\"e8603891-9ff9-45e3-ba83-3b58fca2ec8e\">issue</span>\u201d: a task, a bug, an epic, etc.  So developer throughput becomes issue throughput: creating, updating, closing.  creating, updating closing.  This is wildly inefficient, and doesn\u2019t really represent normal developer workflows.</p><p>Making matters worse is trying to manage releases or sprints in Jira.  This is cognitively a lot for developers to deal with while trying to make sure that everything else (coding, testing, git, etc) are actually happening.  Few things are more frustrating than creating a new ticket, and then not being able to find it since you\u2019re looking at the current sprint and its somewhere in the backlog even though you\u2019re working on it now.</p><p><span class=\"inline-comment-marker\" data-ref=\"05111c3f-de6c-4a2e-a565-9702118d57f1\">Developers ought to be using Jira as a work log, with the primary view being their assigned/reported issues.  They should be able to see all of these issues, sorted in some reasonable way, and manage them easily with as little friction as possible.</span>  Here\u2019s an example:</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20251003-160816.png\" width=\"875\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1140654136/image-20251003-160816.png?version=1&amp;modificationDate=1759507698125&amp;cacheVersion=1&amp;api=v2&amp;width=875&amp;height=818\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1140654136/image-20251003-160816.png?version=1&amp;modificationDate=1759507698125&amp;cacheVersion=1&amp;api=v2\" data-height=\"957\" data-width=\"1022\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1140785259\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20251003-160816.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1140654136\" data-linked-resource-container-version=\"1\" data-media-id=\"7ef0db67-e15b-4e5e-ac70-036e64bf7e22\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1140654136/image-20251003-160816.png?version=1&amp;modificationDate=1759507698125&amp;cacheVersion=1&amp;api=v2&amp;width=1750&amp;height=1636 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1140654136/image-20251003-160816.png?version=1&amp;modificationDate=1759507698125&amp;cacheVersion=1&amp;api=v2&amp;width=875&amp;height=818 1x\"></span><p>This is a dashboard representing the following JQL query in a filtered issue list:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"6bba555d-3257-4597-b413-886e7fc9bd01\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">project in (10097) AND (assignee = currentUser() OR reporter = currentUser())\nORDER BY resolution DESC, status DESC, updatedDate DESC</pre>\n</div></div><p>Not bad, but there are some gaps:</p><ul><li><p>Can\u2019t re-order easily.  You could ORDER BY priority, and change the piority, but this brings the second weakness\u2026</p></li><li><p>No detail issue view or \u201cquick edits\u201d.  You can click on an issue but this context shift is annoying and can slow you down.  </p></li><li><p>No ability to \u201csplit issues\u201d.  Making it easy to split issues means that developers can be encouraged to commit what they have and then save the rest for later.  Here we have no split issue option available\u2026</p></li></ul><p>Some of these features are only available on a Kanban board, which would be sort of ideal if we could control it a bit better.  I\u2019m not sure what addons or configuration changes might be necessary to get us there, but to summarize we should be looking at how to give devs a streamlined URL they can bookmark to see their issues.  They should be able to manage their work like a log as much as possible, with as little thought as possible going to managing issues.</p><h2 id=\"MakingJiraTolerable-UsingJira:ManagersandLeads\">Using Jira: Managers and Leads</h2><p>The view above is also useful for managers and leads to see what individuals are focused on - but we need a bit more.  Managers and leads need a bird\u2019s eye view across engineers to plan work effectively.  Fortunately Jira has the tools necessary for this, and usually they are setup by default.</p><p>For example, in the \u201cmanagement\u201d view, I\u2019d like to be able to assign issues to specific releases for release planning.  I want to be able to see the progress of epics and all the normal stuff.  But 95% of the time, engineers don\u2019t care about any of this and its just getting in the way.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20251003-161958.png\" width=\"875\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1140654136/image-20251003-161958.png?version=1&amp;modificationDate=1759508400301&amp;cacheVersion=1&amp;api=v2&amp;width=875&amp;height=902\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1140654136/image-20251003-161958.png?version=1&amp;modificationDate=1759508400301&amp;cacheVersion=1&amp;api=v2\" data-height=\"1121\" data-width=\"1087\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1140818043\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20251003-161958.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1140654136\" data-linked-resource-container-version=\"1\" data-media-id=\"fc949a0d-0669-46a8-aa03-a15e11421063\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1140654136/image-20251003-161958.png?version=1&amp;modificationDate=1759508400301&amp;cacheVersion=1&amp;api=v2&amp;width=1750&amp;height=1804 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1140654136/image-20251003-161958.png?version=1&amp;modificationDate=1759508400301&amp;cacheVersion=1&amp;api=v2&amp;width=875&amp;height=902 1x\"></span><h2 id=\"MakingJiraTolerable-CommandvsStatus?\">Command vs Status?</h2><p><span class=\"inline-comment-marker\" data-ref=\"b83b333b-f814-4554-8904-1ce146e1ae63\">Jira is better at bottom-up communication than top-down communication.  We shouldn\u2019t expect engineers to do stuff when issues are created or modified: that\u2019s what automation is for.  But if we make it really easy for developers to keep Jira up-to-date, we can provide managers with an accurate picture of where effort is being spent.  Managers can then \u201cclose the loop\u201d directly with individuals or with the team either on Slack or in meetings. </span></p><h2 id=\"MakingJiraTolerable-IndividualTeams\">Individual Teams</h2><p>Individual teams can create their own boards or custom dashboards.  I strongly recommend creating dedicated dashboards with issue filters for each member of the team which can be quickly reviewed at standup meetings or during 1:1s.  This is usually faster and easier than trying to adjust the filter in the view shown above.</p>"
        },
        {
          "id": "1135345776",
          "title": "Sockpuppet: Teleoperation Simplified",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1135345776",
          "last_modified": "2025-10-02T16:59:25.254Z",
          "created_at": "2025-10-01T20:46:29.422Z",
          "body_html": "<p>Sockpuppet is an easy-to-setup application for remote teleoperation.  It's adapted from the existing quest_teleop modules in ROS, but with some nice simplifications:</p><ol start=\"1\"><li><p>UI, including camera streams, is hosted by the robot and accessible with a modern web browser.</p></li><li><p>Standard web interfaces mean we can punch through NATs more easily.</p></li><li><p>No need to setup DDS or ROS on client machines</p></li><li><p>No need to pair laptops with specific robots</p></li></ol><p><strong>Overview</strong></p><p>Sockpuppet contains a few individual pieces working together:</p><ul><li><p>A lightweight proxy running on the laptop to access the Meta Quest</p></li><li><p>The impedance and whole-body controllers running on the x86 RTPC</p></li><li><p>Cameras running on the Orin</p></li><li><p>Data collection on the Orin</p></li><li><p>The sockpuppet server and quest_teleop</p></li></ul><h2 id=\"Sockpuppet:TeleoperationSimplified-UsageGuide\">Usage Guide</h2><p><strong>Setup Laptop</strong></p><p>First you need to prepare the Meta Quest itself:</p><p><a href=\"https://github.com/HumanoidTeam/hmnd/blob/main/hmnd_robot/docs/teleoperation/teleop_quest.md#headset-settings\" class=\"external-link\" rel=\"nofollow\">// instructions here</a></p><p>Once the Quest has been configured, you can install and run the local quest proxy with:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"4fa3e675-0942-4c1d-a3ec-44584e171577\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\"># install UV (this doesn't require a full pixi build on the laptop)\ncurl -LsSf https://astral.sh/uv/install.sh | sh\n\n# launch the proxy\n./hmnd_robot/apps/sockpuppet/sockpuppet/sockpuppet_quest_proxy.py\n\n# or if you don't have a quest:\nMOCK=1 ./hmnd_robot/apps/sockpuppet/sockpuppet/sockpuppet_quest_proxy.py</pre>\n</div></div><p>At this point you are setup.  You can connect to and teleoperate any robots currently running Sockpuppet.</p><div class=\"confluence-information-macro confluence-information-macro-note conf-macro output-block\" data-hasbody=\"true\" data-macro-name=\"note\" data-macro-id=\"c92fbc0f-8b21-4710-aa3c-90b329847145\"><span class=\"aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon\"> </span><div class=\"confluence-information-macro-body\"><p>The MOCK=1 proxy will generate \u201crandom\u201d transformations and should probably not be attached to a real robot (though the motions are small enough that the teleop server will successfully calibrate the headset\u2026 usually)</p></div></div><p><strong>Controller Bringup</strong></p><p>Hopefully automatic</p><p><strong>Sockpuppet Bringup</strong></p><p>On the Orin:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"cf44a084-d4d7-4bc9-8566-51100f4a1a8d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">pixi run sockpuppet_alpha_wheelbase</pre>\n</div></div><p><strong>Connecting to Robot</strong></p><p>Goto http://robot:7777 (robot IPs link)</p><p>** screenshot - show panels</p><p>Verify the quest proxy is connected</p><p>Verify calibration</p><p>Toggle teleoperation </p><p>Collect data</p><p>Have fun!</p><h2 id=\"Sockpuppet:TeleoperationSimplified-DevelopersDevelopersDevelopers\">Developers Developers Developers</h2><p><strong>Launching Alternatives</strong></p><p>Mock and mock quest proxy</p><p>Cameras only</p><p /><p><strong>Implementation Notes</strong></p><p>The proxy is a simple websocket server that reads states from the controllers via oculus_reader/adb and sends haptic commands hosted at localhost:7778</p><p>The Sockpuppet server has a ROS nodes which acts as a bridge between FastAPI/HTTP and ROS.  The controller data is a websocket endpoint, and the images are sent as JPEG streams which constantly replace the contents of img tags.</p><p>The UI is a simple web page which will connect to the Sockpuppet server and attempt to connect to the local quest proxy.  If the connection to the local proxy is established, another websocket to the Sockpuppet server is opened and the data is forwarded both ways.  </p><p>Data collection works because the pedals are just a fancy keyboard device which will trigger service calls via the ROS bridge along with the package and episode IDs.</p><p>The Sockpuppet server+quest proxy basically replaces the existing 'start_trackers' node, the quest_teleop node is largely untouched and the teleop_gui is replaced with the web page.  </p><p><strong>Future Improvements </strong></p><p>We should pipe some of the forward kinematics or TF frames back to the browser so we can do a few things:</p><ul><li><p>Rotate the wrist camera images to keep a consistent horizon</p></li><li><p>Render controller poses from the proxy locally in the camera's frame for immediate operator feedback.</p><ul><li><p>This would require more significant refactoring - the interface via HTTP wouldn't be Quest poses anymore, but Cartesian targets (computed locally either via the proxy or the browser)</p></li></ul></li><li><p>Consolidate quest_teleop and sockpuppet server nodes - simplifies a few things</p></li><li><p>Remove use of parameters as state</p></li><li><p>WebRTC instead of websockets</p><ul><li><p>Lower latency, no head-of-line blocking</p></li><li><p>Requires STUN or TURN infra - not hard just annoying </p></li></ul></li></ul><p />"
        },
        {
          "id": "1071513687",
          "title": "The Case For Vision",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1071513687",
          "last_modified": "2025-09-02T09:30:11.602Z",
          "created_at": "2025-09-01T14:24:15.901Z",
          "body_html": "<p>One of the most vexing problems in robotics is structure-from-motion (SfM) - how do we estimate the structure of a 3D environment from a series of 2D images?  SfM is one of the pillars of computer vision research, and rightfully so.  There have been a number of attempts to side-step this problem.  The root of the challenge is that for any given image produced by a camera, there are an infinite number of scenes that could result in that image.  </p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250901-142817.png\" width=\"384\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1071513687/image-20250901-142817.png?version=1&amp;modificationDate=1756736899347&amp;cacheVersion=1&amp;api=v2&amp;width=384&amp;height=287\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1071513687/image-20250901-142817.png?version=1&amp;modificationDate=1756736899347&amp;cacheVersion=1&amp;api=v2\" data-height=\"567\" data-width=\"758\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1071153242\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250901-142817.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1071513687\" data-linked-resource-container-version=\"1\" data-media-id=\"069efebc-b024-4957-85b0-dcf6b89e6b97\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1071513687/image-20250901-142817.png?version=1&amp;modificationDate=1756736899347&amp;cacheVersion=1&amp;api=v2&amp;width=758&amp;height=567 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1071513687/image-20250901-142817.png?version=1&amp;modificationDate=1756736899347&amp;cacheVersion=1&amp;api=v2&amp;width=384&amp;height=287 1x\"></span><p>This has been used by VFX artists for decades to perform various bits of trickery, but its a major confounding variable for computer vision.  More recently, sensors have been developed which can sense depth directly.  \u201cSparse\u201d depth sensors like LIDARs (or ultrasonics or radar) can probe the environment directly for depth information albeit at relatively poor spatial resolution, and \u201cdense\u201d depth cameras using structured light or time-of-flight which can infer depth directly from an IR image at much higher resolutions.</p><p>Using these depth sensors, the common approach has been to populate some sort of voxel-based occupancy grid.  Each pixel on the depth sensor providing two pieces of information: 1) the voxel corresponding to (x, y, z) is occupied and 2) the ray from the camera TO the voxel at (x, y, z) is clear.  SLAM-based approaches can help to stitch all of this into a global map, though global voxel-based solutions are EXREMELY memory-heavy without a lot of additional heuristics and datastructures like sparse-voxel octrees or other accelerating datastructures (used commonly in Voxel-based games like Minecraft for example).</p><h2 id=\"TheCaseForVision-DepthSensorsandVoxelsKindaSuck\">Depth Sensors and Voxels Kinda Suck</h2><p>Great - we can sense depth directly and now SfM is solved and we don\u2019t have to worry about it, right?  Well - not quite.  In my experience, depth sensors are an enormous pain in the arse.  They have extremely nasty and fickle edge-cases that will ultimately dominate your development time.  Things like glass doors or polished floors causing \u201cghost voxels\u201d to appear in front of the robot, or interference between neighboring sensors, robots or even ambient sources like heat lamps or the sun can result in erroneous readings.</p><p>Another major challenge is that the resulting voxel-based quantization makes marking and clearing an obstacle map extremely challenging.  Using something like 3D Bresenham\u2019s to clear voxels through the grid results in many \u201cstray\u201d voxels that don\u2019t get cleared since everything is being quantized to voxel space, but the robot usually needs to maneuver much more precisely - rotations in particular will result in various bits and pieces being left behind, resulting in false positive obstacles.</p><p>To get around these various issues, developers will spend man-years developing and tuning filters.  How do you filter the \u201cghost voxel\u201d or clear the \u201cstray voxel\u201d without having the robot running into a pole or some other obstacle?</p><p>Finally, interpreting depth images alone is challenging as they usually lack relevant semantic info for labeling or understanding the scene.  This means that depth images often need to be aligned with RGB images anyway - which limits sensor selection and positioning.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250902-092407.png\" width=\"600\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1071513687/image-20250902-092407.png?version=1&amp;modificationDate=1756805049117&amp;cacheVersion=1&amp;api=v2&amp;width=600&amp;height=338\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1071513687/image-20250902-092407.png?version=1&amp;modificationDate=1756805049117&amp;cacheVersion=1&amp;api=v2\" data-height=\"338\" data-width=\"600\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1073840133\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250902-092407.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1071513687\" data-linked-resource-container-version=\"1\" data-media-id=\"11bc0692-d496-4100-b477-58925848ac88\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1071513687/image-20250902-092407.png?version=1&amp;modificationDate=1756805049117&amp;cacheVersion=1&amp;api=v2&amp;width=600&amp;height=338 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1071513687/image-20250902-092407.png?version=1&amp;modificationDate=1756805049117&amp;cacheVersion=1&amp;api=v2&amp;width=600&amp;height=338 1x\"></span><p>There are some reasonable solutions to these problems (for example nvblox: <a href=\"https://nvidia-isaac-ros.github.io/concepts/scene_reconstruction/nvblox/index.html?utm_source=chatgpt.com\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://nvidia-isaac-ros.github.io/concepts/scene_reconstruction/nvblox/index.html?utm_source=chatgpt.com</a> ) but it still requires a whole new modality and eats up a significant amount of processing in addition to the base-level vision processing required for our VLA to work.</p><h2 id=\"TheCaseForVision-TheVisionWay\">The Vision Way</h2><p>Researchers have forever been guided by the knowledge that humans don\u2019t need depth-specific modalities.  A pirate wearing an eyepatch can swashbuckle and navigate around the ship without much issue - so even stereo vision seems more like a nice-to-have in some contexts.  Can we benefit?  (note - a pirate also benefits from an enormous amount of priors and other sensor modalities).</p><p>Going from RGB images to some sort of dense scene representation like a voxel occupancy grid is very challenging, but also probably not what we want to do (given the issues above with voxel-based representations).  The state of the art here revolves around NERF and Splats.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250902-092856.png\" width=\"656\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1071513687/image-20250902-092856.png?version=1&amp;modificationDate=1756805337980&amp;cacheVersion=1&amp;api=v2&amp;width=656&amp;height=365\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1071513687/image-20250902-092856.png?version=1&amp;modificationDate=1756805337980&amp;cacheVersion=1&amp;api=v2\" data-height=\"546\" data-width=\"979\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1073250309\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250902-092856.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1071513687\" data-linked-resource-container-version=\"1\" data-media-id=\"e690c4ef-5b68-4096-b7c9-47f5e554bd04\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1071513687/image-20250902-092856.png?version=1&amp;modificationDate=1756805337980&amp;cacheVersion=1&amp;api=v2&amp;width=979&amp;height=546 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1071513687/image-20250902-092856.png?version=1&amp;modificationDate=1756805337980&amp;cacheVersion=1&amp;api=v2&amp;width=656&amp;height=365 1x\"></span><p /><p>These techniques infer the \u201cradiance\u201d of the environment (meaning the actual lighting - not just the color of an object) using some sort of optimization scheme.  NERF uses differentiable rendering techniques to essentially encode the scene in the weights of a neural network.  This means that learning a new scene means training a new neural network which kinda sucks.  Splats are a significant improvement on this so we\u2019ll focus on this approach.</p><p>Gaussian splatting basically initializing each image with a grid of ellipsoids.  We know that the pixel we see is from somewhere along a ray from the camera, so we can fit a gaussian ellipsoid (the \u201csplat\u201d) along that ray (relatively low variance in the x-y direction, high variance in the z/depth direction).  We can then run a fancy optimizer to solve for camera poses and splats.  Some splats (typically around occluded features) may need to be split into multiple new splats, while others (typically features viewed from many images) will be collapsed into a single splat.  The end result is a solution of the camera\u2019s trajectory through some world space, and all the gaussian splats that best \u201cexplain\u201d the image data.  For a primitive demo you can see here: <a href=\"https://webgl-gaussian-splatting.vercel.app/\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://webgl-gaussian-splatting.vercel.app/</a> </p><p>Splats enable some extremely powerful capabilities.</p><h2 id=\"TheCaseForVision-NovelViewpointSynthesis(NVS)\"><strong>Novel Viewpoint Synthesis (NVS)</strong></h2><p>Because they aren\u2019t just learning the pixels but the view-dependent lighting (fancy anisotropic gaussians) of the scene at each point, you can render the scene from arbitrary viewpoints not in the original dataset.  A robot with a splat-based map could in theory \u201cimagine\u201d what actions it may want to take and choose the best one by playing forward rendered images from an imagined hypothetical trajectory.</p><p>It may also help to bridge the sim-to-real gap - if we only trained on imagery rendered from gaussian splats, we may be able to eliminate sensitivity to camera calibration/placement, scene lighting and more from our training (in the same way that our whole body controller eliminates some kinematic or calibration-related dependencies on the control side).  The artifacts from splat-based rendering can be significant though - and it remains to be seen whether or not we can train or fine-tune image models on this data.</p><p>One of the major challenges with \u201copen-loop\u201d testing is that you often work with recorded datasets.  This puts the robot \u201con rails\u201d, and any changes to the code which take the robot from the recorded trajectories will invalidate all the future recorded data after that change.  NVS allows some amount of variation from the path in these cases, since you can render new viewpoints from the generated model.  It becomes possible to record a canonical behavior of the robot and then randomize it at runtime - without blowing up the amount of data required. </p><h2 id=\"TheCaseForVision-TheDarkSideofSplats\">The Dark Side of Splats</h2><p>Splats are extremely impressive in demos, but creating a product based on these is probably very difficult right now.  You could spend enormous amounts of time collecting huge amounts of video data, all to find that the scene never converges.  These issues exist in general SLAM solutions (lidar slam, VSLAM) but because of the difficult of solving a splat scene its generally much more painful to iterate and tweak until a solution is found.</p><p>The bigger issue is that splats are mostly an offline technology - you need all images from the past, present and future at the same time to solve the world.  This greatly limits their usefulness in the context of realtime mapping and perception.  So you need a huge data and compute commitment just to try to solve.</p><p>There has been some research toward incrementally building splats, but running this in realtime is a major challenge since the solver can take wildly unpredictable amounts of time.</p><h2 id=\"TheCaseForVision-MaybeaPathForward?\">Maybe a Path Forward?</h2><p>There\u2019s a lot of current research in splats attempting to build feed-forward neural networks that can handle the \u201cfrontend\u201d portion of the problem - basically going from an image to an array of reasonably bounded splats in a deterministic amount of time.  Because these guesses are better than the naive initialization used in offline approaches, incrementally optimizing/solving becomes much more tractable.  (<a href=\"https://github.com/nickwzk/StreamSplat\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://github.com/nickwzk/StreamSplat</a> )</p><p>The StreamSplat approach linked above does this by using DINOv2, which is a self-supervised image foundation model that excels at the dense/local tasks like segmentation and depth estimation as opposed to the sparse/global tasks like more general scene understanding that are used to power our VLA.  <a href=\"https://ai.meta.com/dinov3/\" class=\"external-link\" rel=\"nofollow\">DINOv3</a> was recently announced, and I\u2019m confident that teams will be racing to apply it to these problems.</p><p>We should assume that we will need both global scene understanding w/ language at lower temporal resolution (something like Gemma or existing VLMs) in addition to something with local feature understanding at a much higher resolution.  We could use the local models to generate splats, depth or even to do visual servo-ing, while we use the global models to drive the language-conditioned task.  The DINOv3 encoding could also provide other data that could be useful in the context of robots - think reading human poses from vision.</p><h2 id=\"TheCaseForVision-Navigation?ObstacleAvoidance?\">Navigation? Obstacle Avoidance?</h2><p>The splat-based representation provides a sparse model of the world that is both spatial AND semantic in ways that a simple voxel grid is not.  Given some local region of a splat-based map, we can construct a voxel grid from the splat data.  While voxel grids aren\u2019t a great ground-truth datastructure for the world, they are a good accelerated datastructure for spatial queries (planning and obstacle avoidance being the biggest examples).</p><p>One of the major challenges with voxel grids is updating them over time - especially due to quantization or as the robot moves.  Splats don\u2019t have this issue - they are not quantized in any meaningful way, and can be rotated freely.  Planning a path in this space is miserable though.  For navigation-related tasks (global navigation specifically) and other spatial queries, we should process the splat data periodically into a flat \u201cnavigation grid\u201d where we can run something like A* or classic planners to get from point A to point B.</p><p>Most splat engines will already be organizing the splats within some spatial datastructure like an octree or a bounded-volume hierarchy.  This same representation can be used to efficiently generate voxel occupancy grids or navigation grids for more efficient spatial querying while still preserving the splats as the \u201cground truth\u201d.  </p><h2 id=\"TheCaseForVision-Summary\">Summary</h2><p>If we look at all the things the robot needs to do piecewise, things get very expensive, very quickly.  Different sensors for obstacle detection vs semantic scene understanding, different GPU kernels, algorithms or neural networks - it all adds up very quickly.</p><p>Vision allows us to get economies of scale.  We already NEED vision to do the tasks we want to do.  It just so happens that we can ALSO do a bunch of other stuff with vision alone.  To do this, we need to get much fancier in our AI architecture.  We need to consider language embeddings, vision embeddings, action embeddings/tokenizers - all running at potentially different rates - to make the best use of our compute hardware.</p><p /><p />"
        },
        {
          "id": "1069973507",
          "title": "Swinging Big",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1069973507",
          "last_modified": "2025-09-01T09:53:19.775Z",
          "created_at": "2025-08-30T21:44:23.371Z",
          "body_html": "<p>There is a classic debate raging through most startups.  On one side you have Paul Graham's 'incrementalism' - you iterate rapidly with customers in the loop guiding you until you get product-market fit and then scale the business as fast as possible.  On the other side you have Peter Thiel suggesting that you invent the future and create entirely new markets.  The truth is that to succeed a company needs to do a bit of both, but I think a humanoid robotics company should be erring on the side of going big.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250901-092507.png\" width=\"257\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1069973507/image-20250901-092507.png?version=1&amp;modificationDate=1756718708701&amp;cacheVersion=1&amp;api=v2&amp;width=257&amp;height=171\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1069973507/image-20250901-092507.png?version=1&amp;modificationDate=1756718708701&amp;cacheVersion=1&amp;api=v2\" data-height=\"960\" data-width=\"1440\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1071710254\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250901-092507.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1069973507\" data-linked-resource-container-version=\"1\" data-media-id=\"ee76a1f1-93ee-461b-b902-b43e2e516feb\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1069973507/image-20250901-092507.png?version=1&amp;modificationDate=1756718708701&amp;cacheVersion=1&amp;api=v2&amp;width=514&amp;height=342 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1069973507/image-20250901-092507.png?version=1&amp;modificationDate=1756718708701&amp;cacheVersion=1&amp;api=v2&amp;width=257&amp;height=171 1x\"></span><p>The whole point of building humanoid robots is that the general form factor allows us to tackle massive scale because the world is already built for human proportions and morphology.  We should double and triple down on this.  This is such an enormous vision by itself that it almost disqualifies doing anything other than <strong>building the future</strong>.  We can't incrementally build humanoids, because we will probably go bankrupt or be disrupted before we actually get there.</p><h2 id=\"SwingingBig-MinimalInfrastructure\"><span class=\"inline-comment-marker\" data-ref=\"27772865-81eb-4e7d-914e-384fa859708a\">Minimal Infrastructure</span></h2><p>As a starting point, we should assume that we want our robots to be standalone, autonomous agents.  Every additional widget, cable or box we ship adds friction to our growth and ultimately takes time away from building the best possible robot.  We should aim to replace as much physical infrastructure with robot intelligence/behavior - because for the first time in history this is actually sorta possible.</p><p>If we ship networking infrastructure, servers, teleoperator terminals, tablets or dongles we shift away from providing a scalable robotics product toward providing systems integrations.  We become IBM providing professional services and sub-contracting warehouse integrations.  This is probably a bad business given our ambitions.  Probably the difference between 40% growth and 400% growth YoY.  All of this extra infrastructure would gobble up our margins and spread our attention and focus.</p><p>Now of course there will be extra infrastructure - but we should start from a default of zero additional infrastructure and only add when there are no other solutions.  Customers don't want some vendor ops teams lingering around.  They want plug-and-play labor, with an obvious ROI.  </p><h2 id=\"SwingingBig-AligningIncentives\">Aligning Incentives</h2><p>Another major challenge in robotics is about accountability.  Who is actually responsible for our robots doing their job and how do we make sure they want us to succeed?  Consider what happens if our robots get stuck or <span class=\"inline-comment-marker\" data-ref=\"ad0844cf-2386-4e47-be11-48d1a3b0e8f2\">impede access</span> in congested areas within some hypothetical factory:</p><p>If employees have to wait for some teleoperator to notice and solve the issue, they will <strong>HATE</strong> our product and want it to fail.  They may even actively sabotage it. We would be effectively stealing accountability from them and shifting it to ourselves - leaving them frustrated and powerless.  This doesn't scale at all.  We would be fronting enormous amounts of operational risk with little upside (at least compared to alternatives).</p><p><span class=\"inline-comment-marker\" data-ref=\"0fe5a1b6-9a35-46bd-b237-1ae785e18103\">Okay - so we will have them login to an app or a tablet to move the robot or resolve the issue. </span> And again - they will <strong>despise</strong> us for this.  This is a miserable interaction and we are making it difficult (if not impossible) for them to be successful.</p><p>If we layer apps, web interfaces or remote teleoperators between the robots and the people attempting to work alongside them, we are just a really shitty temp agency with extra steps and more complex pricing.  Why would employees want our robots to succeed (they don\u2019t see the benefits).  Why would teleoperators care about the impact to workers in the factory?  The incentives are wildly misaligned and we shouldn\u2019t expect for things to magically work out in our favor.</p><p>Instead of trying to take on all the operational risks ourselves, we should be looking at how to push this accountability to the factory floor where it belongs.  We are transforming a labor problem into a management problem.  So how do we provide the best tools for managing these robots?  I doubt it looks like someone playing Starcraft in the back room.</p><h2 id=\"SwingingBig-RidetheExponential\">Ride the Exponential</h2><p>Our potential customers simply don't know or understand the current trajectory of AI as it applies to robotics.  The capabilities are evolving at a dizzying rate, and the future that we are building cannot even be imagined by customers so we should be sure to put customer feedback into the correct context.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250901-095250.png\" width=\"354\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1069973507/image-20250901-095250.png?version=1&amp;modificationDate=1756720372381&amp;cacheVersion=1&amp;api=v2&amp;width=354&amp;height=289\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1069973507/image-20250901-095250.png?version=1&amp;modificationDate=1756720372381&amp;cacheVersion=1&amp;api=v2\" data-height=\"912\" data-width=\"1116\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1071218710\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250901-095250.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1069973507\" data-linked-resource-container-version=\"1\" data-media-id=\"4c077491-f793-43e9-b8bc-97e2eef27c0d\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1069973507/image-20250901-095250.png?version=1&amp;modificationDate=1756720372381&amp;cacheVersion=1&amp;api=v2&amp;width=708&amp;height=578 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1069973507/image-20250901-095250.png?version=1&amp;modificationDate=1756720372381&amp;cacheVersion=1&amp;api=v2&amp;width=354&amp;height=289 1x\"></span><p><span class=\"inline-comment-marker\" data-ref=\"3df356f3-e1aa-4f14-864a-a614fac84265\">Customers will be all too happy to tell us that they just want the industrial robotics pitches of the last decade to deliver what was actually promised</span> - some fleet manager, feeding tasks from some WMS or other software system, with human-in-the-loop teleoperation for recovering from faults and keeping their operations moving along.</p><p>Our vision should be onboarding robots not <span class=\"inline-comment-marker\" data-ref=\"a9189e3d-fdad-4e51-b4be-83c9caa81c00\">as tools and infrastructure but as agentic workers</span>.  We should assume that models will become increasingly capable and that new techniques will allow us to cram more capabilities into our footprint.  We should be building with enormous thermal and power margins, assuming that our robot's motion will become much faster and more aggressive over time.</p><p>We can't let the industry hold us back if we want to build the future.  We need to pull them along, kicking and screaming.  Or someone else will.</p><h2 id=\"SwingingBig-StrawmanRobot\">Strawman Robot</h2><p>So what should this look like?  I'm going to outline a strawman robot without any regard to safety, hardware or software complexity or even feasibility - the idea is to be bold and ambitious, and our engineers will have an easy(-ish) time dialing it back to make it cost-effective or feasible.  </p><p>The robot is smart and autonomous.  Petaflops of embedded compute, 360 degree RGB vision and two reasonably dextrous arms with grippers at the end.  All on a wheel base that can drive around.</p><p>The robot should have 5G so it can phone home with status, get updates or push novel episodes to expand the skill repertoire - all without any additional infrastructure or setup.  The robot doesn\u2019t need 100% connectivity, because its smart and autonomous - but it knows how to navigate to different areas of the environment with service when needed.</p><p><span class=\"inline-comment-marker\" data-ref=\"5d159e1d-983e-49cc-b43e-b81ae7797629\">The robot should have a touchscreen display </span>so that users can interact with it locally with some reasonable bandwidth.  Voice is probably not feasible in an industrial setting, but this touchscreen could be used to bootstrap other forms of connectivity (pairing a Bluetooth headset, configuring local wifi).  In addition to setup, the touchscreen allows our interfaces to evolve over time.  Just because we can build the future doesn\u2019t mean we know what it looks like right now.</p><p>The robot should have a way to be moved or directed physically.  Pushing the robot around with some handles would be natural and low-friction compared to literally anything else.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250901-094035.png\" width=\"300\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1069973507/image-20250901-094035.png?version=1&amp;modificationDate=1756719637305&amp;cacheVersion=1&amp;api=v2&amp;width=300&amp;height=168\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1069973507/image-20250901-094035.png?version=1&amp;modificationDate=1756719637305&amp;cacheVersion=1&amp;api=v2\" data-height=\"168\" data-width=\"300\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1071349783\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250901-094035.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1069973507\" data-linked-resource-container-version=\"1\" data-media-id=\"ec096958-2d7a-4818-8f57-e0013e8e9789\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1069973507/image-20250901-094035.png?version=1&amp;modificationDate=1756719637305&amp;cacheVersion=1&amp;api=v2&amp;width=300&amp;height=168 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1069973507/image-20250901-094035.png?version=1&amp;modificationDate=1756719637305&amp;cacheVersion=1&amp;api=v2&amp;width=300&amp;height=168 1x\"></span><p>The robot should be able to plug itself into the wall for charging.  No infrastructure needed.  If you want to get crazy, let robots plug into other charging robots.  </p><p>The robot should be able to hot-swap end-effectors.  Grippers, hands, probes, screwdrivers - who knows what capabilities we want in 2028 or 2030.  Plus we probably need to do this for field service anyway.</p><h2 id=\"SwingingBig-StrawmanDeployment\">Strawman Deployment</h2><p>The customer receives a new robot and uncrates it.  Its powered on, and the touchscreen guides them through minimal setup and then they should be able to push the robot through the environment, annotating and labeling via the touch screen. </p><p>A manager should be able to show the robot's workspace and describe its job in natural language.  If we have some sort of in-context learning, a demonstration of the task could be used.  Ideally the robot is capable of learning from human demonstration rather than only teleoperation.  Put items into totes like this.  Unload totes onto conveyors like this.  Sort boxes like this.  </p><p>For very large deployments a shortcut should be possible to quickly onboard individual robots, perhaps by showing the robot a QR code and entering a pin on the touchscreen to provision.  For example, the first robot is setup the \u201cclassic\u201d way, but subsequent robots are registered via fleet management to receive the map and all the necessary context.</p><p>The robot then plugs itself into the wall to charge.</p><h2 id=\"SwingingBig-StrawmanWorkflow\">Strawman Workflow</h2><p>The robot is notified via it's touchscreen by a manager that it's time to get back to work.  The jobs it knows are saved and <span class=\"inline-comment-marker\" data-ref=\"2b720785-b84d-4ec7-999b-25c66453eaba\">can be selected on the screen.  The manager selects the job for filling and stacking totes.</span></p><p>The robot navigates to the appropriate work station for this job and begins loading items from a conveyor into totes.  When the totes are full they are carried and stacked on a pallet.  At various times during the shift the robot may have difficulty loading or stacking totes.  It should improvise to keep working and possibly come back to problematic situations later.  For example, instead of asking for help 5 separate times during a shift, can the robot have a strategy where it makes progress and defers help until the end where one intervention can address all the issues?</p><p>Sometimes new skills may be demonstrated to the robot.  These should be stored via some sort of RAG-like scheme so that the robot can make use of new schemes using in-context learning rather than requiring additional fine tuning.  Managers and employees know that if they continue demonstrating the tasks, the robot will get better fast enough to make it worthwhile (they don't need to wait weeks for a new model).  Periodically these behaviors will be added to training runs to improve the foundation model\u2019s performance.</p><h2 id=\"SwingingBig-StrawmanFleetOps\">Strawman FleetOps</h2><p>With enough robots, some sort of coordination is necessary to avoid congestion and balance work across robots.  <span class=\"inline-comment-marker\" data-ref=\"69a86677-cd2c-463a-a2bd-aaf1d6cf5bf0\">This should be an optimization rather than core to basic interactions and behaviors of the robot.</span></p><p>Robots will need to be aware of one another to avoid congestion around charging locations.  Robots may need to communicate about bulk uploads/downloads to avoid congesting the network.  But generally fleet management is about modulating existing robot behaviors rather than creating entirely new behaviors.</p><h2 id=\"SwingingBig-ADoseofReality.\">A Dose of Reality.</h2><p>Yes - there are ID concerns, and safety and cost.  Maybe outlets can't deliver enough power to enough robots.  Or they are inaccessible.  Maybe we need some markers to help label the world physically because SLAM isn't perfect.  Maybe we need some additional network solution because 5G isn't available at all locations.</p><p>The point isn't to dogmatically build this minimal robot.  The point is to <strong>imagine</strong> it - because that is the future we actually want to build.  It's easy to get distracted by the realities of today, diluting our vision and ultimately tying an anchor to our ambitions.</p><h2 id=\"SwingingBig-Conclusion\"><span class=\"inline-comment-marker\" data-ref=\"a890cb9f-ccdc-4778-b8d9-23f6a8964d60\">Conclusion </span></h2><p>If we can avoid shipping any extra hardware by making the robot smarter, this is probably a good trade.  Infrastructure is not getting easier to deploy at the rate that AI is improving.</p><p>If we can shift operational accountability from Humanoid to the factory floor, we should do this.  It aligns incentives, limits our risk and helps us scale faster.</p><p>We should weigh customer feedback as if they are unaware of the rapid AI progress occurring and as if they are over-fit towards older solutions to automation.  They don't know what's possible, and they don't know <em>specifically</em> what they want.  They want to save money.  They want uptime.  They want transparency.  But they don't know how to make those things happen.  If Steve Jobs had asked every executive in 2005 how important a physical keyboard was on a smartphone, how many would have been fine with a full screen touch screen and virtual keyboard?</p><p><span class=\"inline-comment-marker\" data-ref=\"97ed25ed-8105-4ea3-987d-376d238e4aa9\">We are building a category-defining product and we should have the conviction to follow a bold vision.</span></p><p />"
        },
        {
          "id": "1052508214",
          "title": "Wireless Networking Sucks",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1052508214",
          "last_modified": "2025-08-26T22:15:02.381Z",
          "created_at": "2025-08-21T09:51:28.098Z",
          "body_html": "<p>My time at Viasat (working on Satcom networks) and Cloudflare (more traditional Internet infra) has led me to believe that wireless generally sucks.  We should minimize how much we depend on it.  This doesn\u2019t mean tethered cables or sneaker-net robots - but I think it does involve acknowledging the strengths and weaknesses of wireless technologies and building a solution that fits with reality.</p><p><strong>WiFi</strong></p><p>Wifi was originally created as simply wireless ethernet.  The air is a hub, with modems chirping when its time to send data.  If multiple modems chirp data at the same time on a channel, exponential backoff is used to ensure collision-free communication.  It works, but it introduces a lot of tail latencies.</p><p>More modern WiFi fundamentally works the same way, but is better about packing more collision-free chirps within the allotted bandwidth.  There are a few paths to doing this:</p><ol start=\"1\"><li><p>MIMO - take a faster datastream, break it into two lower-rate streams which are modulated with different codes (separated) on the same channel.  This helps to better utilize the available spectrum (packing more chirps per channel)</p></li><li><p>Beamforming - blasting energy in all directions is wildly inefficient from a power and spectrum perspective.  Every chirp sees every other chirp as interference.  Better if you can direct all the energy toward where it will be received.  This reduces the amount of collisions on channels and allows better utilization of the spectrum (less backoff - more chirps per channel)</p></li><li><p>Higher frequencies - allow for more data to be pushed in the channel.</p></li></ol><p>Modern WiFi is impressive (especially WiFi7) - but for industrial robots there are still some dark corners here.  Beamforming and higher-frequencies mean non line-of-sight (NLOS) use-cases suffer greatly.  What if there is a giant piece of industrial equipment between the AP and your robot?  What if the robot is moving through a space where reflections and equipment change the path rapidly requiring beamforming to repeatedly re-acquire the signal?</p><p>Typically to cover the space you need to have many APs with the robots roaming around between them, or routing WiFi between the robots themselves\u2026</p><p><strong>PTP</strong></p><p>Time-multiplexed ptp links are also possible (see <a href=\"/wiki/spaces/ROBOT/pages/1041399864/Practical+Evaluation+of+Low-Latency+TDMA-based+60+GHz+PtP+Link+for+Robot+Control\" data-linked-resource-id=\"1041399864\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Practical Evaluation of Low-Latency TDMA-based 60 GHz PtP Link for Robot Control</a> ), but here we just trade-off collision backoff for acquisition delays.  And we have more strict requirements about line-of-sight.  Probably not terribly helpful.</p><p><strong>Mesh Networking</strong></p><p>Mesh networking is one of the great lies of the 21st century.  The idea is that instead of having some hub and spoke topology, you instead of a dynamic routing network of peers that can discover and adjust over time.  In some sense, the Internet is a mesh network powered by modern IP routing algorithms like BGP.  Doing this with wireless though?  Madness.</p><p>You\u2019re basically taking all the challenges of WiFi and piling them into a full system.  It would be extremely fragile with extreme tail latencies and lots of intermittent failures.  Each hop in the network means taking on queuing delays and re-transmission delays.</p><p>Any time the topology changes (frequent when you consider the issues above w/ beamforming and acquisition), you have additional latencies and loss - typically not bounded at all.</p><p><strong>5G</strong></p><p>At least modern 5G was built for mobility.  It has a scheduled MAC, which keeps collisions low and avoids the random backoff latencies, it has QoS and it supports hand-over natively.</p><p>5G also supports private spectrum/buildout - but this is probably more of a lift than WiFi even.</p><p><strong>What Could We Do?</strong></p><p>WiFi7.  Many small APs.  Low power.  Maybe a redundant link if we really want to be open, but I\u2019ll try and make the case below that we shouldn\u2019t bother.</p><p>WiFi7 should allow us to get relatively seemless handover between cells.</p><p>We should probably put the robot\u2019s WiFi antennas on the head.  This places them relatively far away from the chonkier metal parts of the robot, but we still run into the situation where the antenna will be coupled to the robot\u2019s body and thus pose.  Meaning that as the robot moves through poses, it will affect the beamforming and overall wireless performance.  I think this would be minimized at the head (a lot more plastic, can get a few cm away from the big metal bits), but this is going to be an issue no matter what.</p><p>APs on the ceiling, antennas on the head would probably give the best performance for commodity WiFi but that would need to be verified.  Perhaps the approach is just to put an AP above every workspace.</p><p>A 5G modem (or slot for one) would be nice\u2026   In theory we could sell standalone robots to areas that need no additional infra (think deployments &lt;6 robots).  This is not a small lift (RF, I/O ports, antennas).</p><p>If we need backhaul from a customer site, we should consider something like Starlink where we can own more of our network infra (as opposed to trying into their network).</p><h2 id=\"WirelessNetworkingSucks-ThinkingBigger\">Thinking Bigger</h2><p>Its obvious why we would want some perfect wireless link to our robots.  It would make a lot of things easier.  Unfortunately, my experience tells me this is a never-ending quagmire and ultimately will bottleneck the growth of our fleet.  I\u2019m confident we could build robots faster than we could perform site surveys and deploy wireless infra for our robots.</p><p>The primary reason for high-quality, reliable wireless comms is to remotely control the robot.  Either via teleoperation or via some remote inference server.  If we move forward with these approaches, we\u2019ll need to solve networking at a very high level - and I think this problem is on the same order of complexity as deploying the robot itself.</p><p><strong>Crappier Networking</strong></p><p>So what if our network is crappier?  Loss of connection, tail latencies \u2192 what does this mean?  If we are running teleoperation, it could lead to operators becoming confused or being unable to accurately control the robot.  If we are running inference, the policy is less likely to \u201cbe\u201d confused (as it experiences time differently than a human would), but the performance of the robot would suffer and generally it would look like crap.</p><p>But a crappier network is still good for non-realtime control.  We could send tasks, get feedback, diagnostics, update software, upload data.  No problem.</p><p><strong>Dealing with Latency</strong></p><p>The problem with latency is that its unpredictable.  Even high predictable latency is problematic for realtime control - ever try to SSH to a server over a satellite connection with 0.5s of latency?  This is a silly example, but I think there is maybe a useful technique here.  In remote terminals with high latency, the trick is to locally echo the characters being typed to provide immediate feedback to the user while the characters are being transferred over the buffer.  Typical user interactions with a remote shell are broken into natural chunks - commands, confirmations, etc etc.  Each of these can be handled easily by locally echoing the characters and then the user can wait for the next step to continue.  Not ideal, but robust.</p><p>Could we do the same?  Could we provide some way to locally confirm teleop commands in a way that decouples the user\u2019s interactive experience from the robot while still allowing us to do the work?  Consider a teleop monitor showing the robot\u2019s view being fed over a less-than-perfect network.  The latency is usually say 100ms, but can spike to 400 or more randomly.  When these spikes happen while the user is still, no problem.  If it happens while the user is controlling some trajectory, it can result in confusion and the user stopping or making unpredictable motions (thus producing garbage data\u2026)</p><p>What if we overlaid a semi-transparent rendering of where we believe the robot should be based on the teleoperation commands?  If not the actual robot positions (challenging with cartesian control running on the robot), we could at least show the targets being controlled in screen space.  This way the operator can get immediate feedback about their inputs even if the robot is susceptible to some issues due to latency.  This may be a much cheaper way to paper over some of the issues with crappier networking without resorting to some complicated networking infrastructure.</p><p><strong>Avoiding the Network</strong></p><p>Of course, we should also consider avoiding the network entirely.  For policy execution, we should be running on the robot\u2019s GPU anyway.  But what about teleoperation?</p><p>One dumb possibility is to put the the controller into LIMP mode where the joints are back-drivable and have the operator manually operate the robot.  The reason this is dumb is because it brings a lot of challenges:</p><ol start=\"1\"><li><p>safety - you are asking an operator to directly manipulate robot joints in certain modes.  this could be challenging to certify\u2026</p></li><li><p>data - the data being generated this way isn\u2019t really going to be the same as data being produced by feeding cartesian targets to the controller. </p></li></ol><p>For the second point, maybe you can just manipulate the end-effectors as targets and run the rest of the thing IK - but again, this produces an interesting safety risk.  Is solving this safety problem more difficult than solving the networking challenge?</p><p>Another possibility is to have the robot watch a demonstration directly.  We have 360 vision around the robot\u2019s head, and only the front/wrist cameras are used for teleoperation and policies currently.  Would it be possible for an operator to stand behind or to the side of the robot looking at a display to control the robot via motion capture from video?  There are obvious challenges with this approach too:</p><ol start=\"1\"><li><p>depth - depending on the demonstration position relative to the robot, capturing depth could be challenging and result in poor-quality data</p></li><li><p>data - tracking these trajectories in mocap is also going to result in some different data characteristics that could be challenging to learn from.</p></li></ol><p>One major benefit to the \u201cdemonstration\u201d aspect is that it sorta generalizes beyond just teleoperation.  If we were to crack in-context, one-shot learning it would map nicely to that.  Or perhaps a robot working among people could observe others working and learn.  This is all scifi - but so is a perfect wireless network.</p><h2 id=\"WirelessNetworkingSucks-Summary\">Summary</h2><p>I\u2019m not sure what the point of this document really is.  Mostly to get out some beliefs around how much wireless networking sucks and what a quagmire it can be.  Maybe a little bit of poking/prodding to see if we can think of ways to meet our product objectives without requiring so much infrastructure and performance out of this network.</p><p>Maybe the robot knows how to plug itself into the wall for tele-op via a cable.  Maybe some fancy ptp laser link.  I really don\u2019t know but there must be some other options here.</p><p /><p /><p />"
        },
        {
          "id": "1052377106",
          "title": "Hardware Abstraction",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1052377106",
          "last_modified": "2025-08-21T09:49:34.517Z",
          "created_at": "2025-08-21T09:19:36.447Z",
          "body_html": "<p>One of the fun challenges about robotics software in particular is the hardware dependency.  Unlike your email or note-taking application, the point of a robot to do something physically in the real world.  To push on the world, and see the changes as photons hitting a sensor as interactively as possible.</p><p>Software is a pain in the arse, but it has some benefits that are worth acknowledging.  You can make perfect copies of software and version it exactly for almost zero cost.  Hardware engineers would love to have this capability, but instead they are plagued with supply chain nonsense, tolerance nonsense and things breaking.  The world of atoms is far less forgiving than the world of bits.</p><p>When we build hundreds or thousands of different robots, these minute differences in hardware \u201cpush\u201d on our software in interesting ways that can wreak havoc if we are not deliberate about our design and architecture.  Tiny configuration changes, and branches can litter your code making it brittle and expensive to maintain or change.</p><h2 id=\"HardwareAbstraction-WhatisaRoboticsHAL\">What is a Robotics HAL</h2><p>Most platforms that sit on top of mass-produced hardware include something known as a hardware abstraction layer or HAL.  Windows 95 had one.  Android has one.  Linux has one (although its fragments under different names).  All of these platforms run on very diverse hardware, yet want application developers to have a stable platform to target for end-users.  When you boot up Chrome to visit websites, you don\u2019t want the website to care about which CPU you have, or how much memory, or which disk vendor or motherboard or ethernet adapters you are using.  The browser only cares about the platform interfaces: threads, buffers, sockets, files.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250821-094827.png\" width=\"333\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1052377106/image-20250821-094827.png?version=1&amp;modificationDate=1755769708399&amp;cacheVersion=1&amp;api=v2&amp;width=333&amp;height=151\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1052377106/image-20250821-094827.png?version=1&amp;modificationDate=1755769708399&amp;cacheVersion=1&amp;api=v2\" data-height=\"151\" data-width=\"333\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1052672036\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250821-094827.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1052377106\" data-linked-resource-container-version=\"1\" data-media-id=\"38656e22-33ca-4186-b22c-7378fa8c0647\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1052377106/image-20250821-094827.png?version=1&amp;modificationDate=1755769708399&amp;cacheVersion=1&amp;api=v2&amp;width=333&amp;height=151 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1052377106/image-20250821-094827.png?version=1&amp;modificationDate=1755769708399&amp;cacheVersion=1&amp;api=v2&amp;width=333&amp;height=151 1x\"></span><p>For a robot, the problem is both more bounded and more difficult.  We don\u2019t necessarily expect robots to plug-and-play different actuators, sensors or be configured in arbitrary morphologies - but we do have a much larger surface area of hardware abstraction than more traditional compute platforms.</p><h3 id=\"HardwareAbstraction-MaybeGodDoesPlayDice\">Maybe God Does Play Dice</h3><p>Hardware is fundamentally concurrent and asynchronous.  Usually hardware peripherals have their own computers, running software on their own clocks and sending messages on their own time.  The environment that the robot operates in is also largely non-deterministic.</p><p>Non-determinism stinks - it makes it extremely difficult to reproduce faults or to debug the system.  It makes testing difficult.  It makes reasoning about the system difficult.  What\u2019s the point of building a bunch of nice deterministic software modules that can be well-tested if we\u2019re just going to bolt them on top of a firehose of random data?</p><p>One way to view something like a HAL is it acts as the boundary between the non-deterministic world of sensors and actuators and the more deterministic world of our software.  By recording the data at this layer, we can reproduce faults and behaviors more-or-less exactly.</p><h3 id=\"HardwareAbstraction-Platforms,SimulationandRecordedData\">Platforms, Simulation and Recorded Data</h3><p>So let\u2019s imagine for a moment that we abstract all the hardware behind a platform-specific HAL which can come in several variants.  One implementation may take recorded data and simply replay it, perfectly reproducing the unique scenario that was captured with running hardware.  Another may run a simulator like Isaac or Mujoco.  And of course we have to have an implementation backed by real hardware drivers running on the target devices (otherwise what\u2019s the point?!)</p><p>The goal would be to cut the HAL interface such that all the software on top runs without a care in the world about which of the variants it is running on.  There shouldn\u2019t be \u201cif simulation\u201d or \u201cif testing\u201d flags littering our software stack - those differences should be on the other side of the HAL.</p><h3 id=\"HardwareAbstraction-Composition\">Composition</h3><p>To support multiple platforms, we\u2019ll likely be re-composing a number of shared elements including things like power mgmt interfaces, actuator interfaces, sensor interfaces and more.  Different application will depend on different platforms, though nothing prevents any specific application from supporting multiple platforms.</p><h2 id=\"HardwareAbstraction-BuildingtheHAL\">Building the HAL</h2><p /><p /><p />"
        },
        {
          "id": "1037435391",
          "title": "Safe Teleoperation",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1037435391",
          "last_modified": "2025-08-21T09:03:16.592Z",
          "created_at": "2025-08-13T11:00:31.564Z",
          "body_html": "<p>Right now we have a significant safety risk where developers can SSH to robots to perform work while others are nearby.  Or perhaps connect to the wrong robot for teleoperation.</p><p>I think the best approach here is physical interlocks/keys which force a human to take accountability for a specific robot before accessing it.</p><p /><p>Goals:</p><ol start=\"1\"><li><p>Robots should have at most 1 operator with exclusive permission to move the robot</p></li><li><p>Robots shouldn\u2019t physically move out of sight from the operator</p><ol start=\"1\"><li><p>impossible to enforce in full - but we can patch w/ process</p></li></ol></li></ol><p /><p><strong>Software Options</strong></p><p>We could do something to limit the number of concurrent SSH connections on the robot, but this does\u2019t really cover the case where an \u201cidle\u201d robot in the lab suddenly comes to life.  We could ensure that robots are powered off when not in use, but it is often the case that some level of access is needed for development work meaning the robots would be powered on and on the network.</p><p>There isn\u2019t really a good way in pure software - what we want is to effectively force an operator to go to the robot to \u201cclaim\u201d it.</p><p /><p><strong>Hardware Options</strong></p><p>Imagine every developer/operator who is expected to operate a robot has a yubikey.  This key has a unique ID and allows for some cryptographic functions - but the primary purpose is that we can prevent the controller stack from operating (for Alpha we could do this all the way down at the ethercat driver layer which should change relatively rarely) and issue a challenge to the key.</p><p>Using a physical key means that a developer has to actually go to the robot to claim it.  If someone else has already claimed the robot, there will already be a key inserted.  Given a key, it should be possible to trace who it was issued to.</p><p /><p><strong>Implementation Plan</strong></p><ol start=\"1\"><li><p>ensure there is a single accessible USB port dedicated for these keys (we can ensure only this port can be used for the locking functions as defined above)</p></li><li><p>issue keys to developers and register each one - at some point we may want to do this for other reasons, so its good to build habits now</p></li><li><p>implement a lockout mechanism in the controller stack:</p><ol start=\"1\"><li><p>libfido2 can be used from C++ to challenge the key and unlock the stack</p></li><li><p>this isn\u2019t trivial, but its also not impossible</p></li><li><p>we can put a time limit on it - so developers have to return to the robot and touch the key every so often to restore access</p></li></ol></li></ol><p /><p><strong>Alpha E-Stop</strong></p><p>This plan above isn\u2019t so different from the Alpha e-stop - which is a physical lock-out paired to the robot needed to operate the robot.  If this isn\u2019t sufficient we can look at some of the options above for more traceability, but I\u2019m not sure we have the engineering bandwidth for this if the wireless e-stop does the trick.</p>"
        },
        {
          "id": "1052442642",
          "title": "The Case For (Some) Hard Realtime",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1052442642",
          "last_modified": "2025-08-21T08:46:55.021Z",
          "created_at": "2025-08-21T08:15:26.438Z",
          "body_html": "<p>Our Alpha robot has a \u201crealtime\u201d PC running x86 with a preempt-able Linux kernel, along with an nVidia Orin which handles the bulk of our higher level compute.  Our usage of EtherCAT for 1000Hz impedance control at the joint level requires us to have low jitter and low latency, so the RT-patched kernel allows us to run this on Linux using commodity Ethernet adapters instead of bulky peripherals.  We can then run the joint-level controller within ROS and communicate via DDS with the Orin. </p><p>The solution has a ton of complexity, without too much benefit.  The realtime Linux isn\u2019t REALLY realtime - but its probably good enough for what we want to do (latencies in the 10s of microseconds) - as long as you don\u2019t have any dodgy drivers that aren\u2019t preempt-able.  But for what we\u2019re trying to do the RTPC is wildly overpowered and requires us to distribute our ROS stack over multiple computers.  This has troubling implications for software updates and core properties of the system like determinism (how can we be sure we aren\u2019t dropping joint states over that network\u2026)</p><h2 id=\"TheCaseFor(Some)HardRealtime-OneComputertoRuleThemAll?\"><strong>One Computer to Rule Them All?</strong></h2><p>One core tenet going into Beta is to simplify the compute architecture, hopefully using a single nVidia Thor.  The Thor is an absolute beast of a machine, and its possible that we can isolate some CPU core just for impedance control and meet our 1000Hz control rates.  Especially if we assume that we have compatible adapters and all that (not a given, nor is it a given that EtherCAT drivers will build on Orin - but for the purposes of this discussion we\u2019ll assume they can).</p><p>But do we even want to close a 1000Hz control loop from Linux with 40-some odd actuators?  Maybe not. </p><h2 id=\"TheCaseFor(Some)HardRealtime-JustMoveImpedanceControlToTheJoints/Actuators\"><strong>Just Move Impedance Control To The Joints/Actuators</strong></h2><p>I\u2019m not convinced we can move impedance control down to the joints or actuators since we are controlling cartesian targets and we rely on complex feed-forward dynamics.  Basically this would require transmitting kinematic and dynamic state (in addition to actuator control) to each actuator which blows up complexity in a different way.  But there is a benefit here - if hypothetically we COULD run impedance control within the actuator itself, then Linux would only need to close a 100Hz loop.  This is much more tolerable.</p><h2 id=\"TheCaseFor(Some)HardRealtime-SafetyController?\"><strong>Safety Controller?</strong></h2><p>We will already need some hard real-time compute on the system to support functional safety.  Currently the scope of this is limited to reacting to data coming over black channels, but this does require strict upper bounds to remain safe.   What if implemented impedance control in our safety controller?  For the moment we\u2019ll ignore the challenges of certification - we\u2019ll look at this only as a compute/software problem.</p><p>Modern MCUs have pretty generous amounts of compute - and if there is hardware floating-point it should be feasible to run impedance control for all our joints at 1000Hz in a hard-realtime setting.  There are some challenges related to getting configuration to the controller, but there are some benefits - some near-term and some further afield:</p><ol start=\"1\"><li><p>The Orin can close a 100Hz loop easily with a safety controller over standard Ethernet</p></li><li><p>The safety controller can bound our latencies and isolate faults better than the Orin ever could under Linux</p></li><li><p>The safety functions can directly control state machines of our impedance control - modulating forces and such as-needed (going into limp mode during certain faults for example)</p></li><li><p>We can force our (soft realtime) whole body controller and VLA to operate within an envelope</p></li><li><p>For future biped platforms, this architecture makes much more sense, as we\u2019ll need the tighter guarantees more and it will be difficult (IMO) to avoid certification of something like impedance control - though we certainly don\u2019t need to do this now for Alpha</p></li></ol><p>In fact, it may even make sense to run a portion of the whole body controller in the safety MCU, but this is a bit out of scope.</p><h2 id=\"TheCaseFor(Some)HardRealtime-Summary\"><strong>Summary</strong></h2><p>We should lean into some of our hard real-time constraints, and see if we can build a more robust, safer system that can get us through beta and future bipeds.  The \u201csafety biped\u201d effort is a totally independent thing at this point, but I\u2019d be surprised if it doesn\u2019t tilt this direction anyway - and even if the underlying implementation is entirely different, setting up this architecture can mean more commonality across platforms and reduce software complexity over the long run.</p><p>We should keep Linux soft real-time (even with pre-empt RT - especially as we add sketchy drivers).  We should have a home for hard real-time, and we should avoid closing &gt;100Hz loops from Linux if at all possible.  This allows each compute platform to play to its strengths, isolate faults and opens the door to more sophisticated functional safety down the road.  </p>"
        },
        {
          "id": "1051361456",
          "title": "The Case for Two Networks on Beta",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1051361456",
          "last_modified": "2025-08-20T18:46:36.263Z",
          "created_at": "2025-08-20T16:48:47.200Z",
          "body_html": "<p>There is a lot of discussion around the network topology for Beta and the discussion has mostly been dominated by the decision around whether or not to use EtherCAT.  I\u2019m not going to bother with this here.  Instead I want to look at the network more generically.  We can assume we are using Ethernet everywhere for this discussion.</p><h2 id=\"TheCaseforTwoNetworksonBeta-OfMiceandMenElephants\">Of Mice and <del>Men</del> Elephants </h2><p>In networking, we often talk about \u201cmice flows\u201d and \u201celephant flows\u201d because mixing these different flows in the same network is generally a very difficult problem.  Its why playing a fast-twitch FPS while your significant other streams Netflix results in a bad time.</p><p>On the Internet, the problem is phrased a little differently: 90% of the FLOWS are mice flows (a flow being a unique TCP connection) and 90% of the BYTES belong to elephant flows (since they are so much bigger).  This results in challenges where the elephant flows unfairly eat up all the queues, causing our little mice flows to get congestion controlled into oblivion.  Whoops.</p><h2 id=\"TheCaseforTwoNetworksonBeta-ButWhataboutRobots\">But What about Robots</h2><p>In all the discussions about network topology, no one (thankfully) has mentioned TCP.  So why does this even matter?  Even if we don\u2019t use TCP, we still have a similar problem.</p><p>Our elephant flows are going to belong to our sensors, and because of our plans to use nVidia Thor, we\u2019ll be using RDMA over Ethernet.  RDMA is just a fancy way to write directly to the Thor\u2019s GPU memory from a remote device - meaning that camera buffers magically show up where they are needed without any CPU or kernel overhead.</p><p>Our mice flows are going to belong to our actuators, and because of our current plans to leverage a 1000Hz control loop (sticking with this assumption for now given we want high-performance impedance control), this isn\u2019t very forgiving about latencies or jitter.  Because we are controlling actuator chains, the jitter and latency of these packets can be very important, as errors at the end effector will grow non-linearly with those timing issues resulting in difficulty with precision control.</p><p>RDMA wants lossless ethernet, as it needs to blast megabytes of data across thousands of packets to write even a single camera frame to the GPU.  To reduce overhead and maximize throughput, you typically want to enable jumbo frames (where ethernet packets can grow to 9000 bytes).  To support lossless ethernet, RDMA typically wants you to configure some sort of congestion control (<a href=\"https://www.juniper.net/documentation/us/en/software/junos/traffic-mgmt-qfx/topics/topic-map/cos-qfx-series-DCQCN.html\" class=\"external-link\" rel=\"nofollow\">DCQCN</a> if you like alphabet soup).</p><p>While we don\u2019t want to lose control packets, with torque-controlled actuators dropping a packet is probably preferable to being late.  Being late is very very bad - and we want to have bounded latency so we can even reason about our control loop performance.  To minimize serialization-related latencies, we want to keep these control packets as small as possible.  Do you see the conflict yet?</p><p>If we have a single Ethernet network, we will be forced to mix giant, lossless RDMA flows for sensors with tiny, bounded control flows for actuators.  I don\u2019t think this problem is worth solving.</p><h2 id=\"TheCaseforTwoNetworksonBeta-PossibleSolution\">Possible Solution</h2><p>If datacenters can solve the \u201cmice and elephants\u201d problem, surely we can too?  Probably\u2026</p><p>In the datacenter the approach is usually to throw VLANs at the problem.  One VLAN for sensor data, another VLAN for control data.  We trunk these VLANs through shared links, and break out access ports for our peripherals in the switches when needed (assuming that peripherals don\u2019t support VLAN) or trunk directly to the devices (if they do support tags).</p><p>There are a number of features that can be configured at the switch level to maybe get what we want.  We want DCQCN for the sensor VLAN so we get explicit congestion notifications and lossless ethernet, while we want our control packets to be marked as <code>strict-priority</code> so that these packets are processed before we move to our sensor flows.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"720\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1051361456/Untitled%20Diagram-1755710935439.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1051361456/Untitled%20Diagram-1755710935439.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p>There is a small issue remaining of serialization latency - along a chain of ~6 actuators in the arm for example, we could possibly need to wait for 6 jumbo frames to transmit before we can get our control packets through.  A 9000 byte jumbo frame would take about 70us to be serialized on a standard 1Gbps link for example, so our worst-cast jitter would be about half a millisecond.  Maybe this is a problem?  I\u2019m not really qualified to say one way or another, but its definitely not really deterministic as there will be a lot of variability on this jitter.</p><p>Some switches allow pre-emption, where you effectively interrupt a jumbo frame to send the smaller packet.  In some cases this can discard/drop the packet, but most 802.1Qbu (TSN-related) allows the serialization to be resumed later - but only if every single path in the network understands this.</p><p><strong>Some Specifics</strong></p><p>As always, we\u2019ll focus on the arms since this is where these points are more clear, though they also apply at the base (drive motors and lidars - though lidars aren\u2019t RDMA so probably no problem there) and the head (neck actuators + cameras).</p><p>A single wrist camera could be producing 16-bit 1080p feeds at 30FPS - which is about 0.99Gbps.  So already this would push us over 1Gbps.  Are we really going to run 10Gbps?  Do we have NBASE-T support in the switches to do 2.5Gbps or 5Gbps?</p><p>Its important to note that we want raw frames from these cameras to show up in the GPU of the Thor, because ultimately we need to process that raw data.  Sending compressed JPEGs is problematic for a few reasons:</p><ol start=\"1\"><li><p>We\u2019d have to take the JPEG and decode it - which okay, this probably isn\u2019t the end of the world\u2026</p></li><li><p>We\u2019d have to allocate buffers for JPEG images since we\u2019re blasting these into the RDMA buffer\u2026. How big do we allocate?</p></li></ol><p>The second point here is a big issue - what is the upper bound for the sizeof a compressed frame?  It will depend on the JPEG quality as well as the scene itself.  A black frame would be very small, while a frame of noise could be very large.   RDMA wants to know how big the buffer should be on the receiving side, but our sender doesn\u2019t know until AFTER we decode - meaning we are suffering additional latency here.  You can also have \u201cpathological\u201d frames which could be LARGER than the actual raw image - meaning we would be over-provisioning buffers or implementing some crazy quality backoff scheme that adds more latency.</p><p>Put simply, we want 1Gbps raw streams from the cameras, and adding JPEG compression w/ RDMA is a bit of a challenge that adds significant latency and complexity to an already complex scheme.  Fixed-size, raw frames are easy, but push us over 1Gbps which could complicate the switching infra of our single fabric.</p><h2 id=\"TheCaseforTwoNetworksonBeta-AlternativeSolution\">Alternative Solution</h2><p>Just run the cables and have two independent networks.  The system will be easier to understand, easier to troubleshoot and easier to debug.  We don\u2019t actually need a fully generic topology because we aren\u2019t building a research platform.</p><p>We can break out two physical interfaces on the Thor - one for sensors and one for control.  We can trunk these to two switches: one configured for RDMA for sensors, and one configured for more deterministic control.  This trades some of the difficult-to-quantify development risk and general \u201cconfiguration risk\u201d of the VLAN solution for a more quantifiable \u201ccable risk\u201d of the extra network.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"720\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1051361456/Untitled%20Diagram-1755711283362.drawio.png?api=v2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1051361456/Untitled%20Diagram-1755711283362.drawio.png?api=v2\" loading=\"lazy\"></span><p>If we have some hypotheses about the true need for determinism or the flexibility of Ethernet, we can prove them out on the control network without worrying about mucking with the RDMA configurations for our sensor stack.  We could even cross-wire them later to prove out that there no more risks and that a unified topology is viable - basically we just stop populating that cable or use it as a redundant trunk or something in later revisions.</p><h2 id=\"TheCaseforTwoNetworksonBeta-TheOptimalNumberofFailedCablesIsNotActuallyZero\">The Optimal Number of Failed Cables Is Not Actually Zero</h2><p>I can already hear it:<strong> \u201cCables are evil!  We will be increasing the failure rates of our robot and increasing connectors/wires!\u201d</strong></p><p>Yep.  But this is a long-term problem as we scale up (more robots, more scale, more failures).  In the short term, I\u2019d argue its much more important to de-risk development and produce a system that\u2019s easier for us to understand. </p><p>Let\u2019s assume that configuring all of these switches to make RDMA and our actuators happy takes 3 months (could be fewer, could be more).  How many failed cables is that worth at the tail end of the program?  The answer is definitely not 0, since 3 months of engineering/integration time is very expensive now.</p><p>Imagine the sort of integration issues we\u2019ll run into during development:  actuators stalling out, loops being delayed, sensor data being dropped/corrupted.  By design, a single shared Ethernet fabric would be at the heart of the entire system - do we really expect that every engineer interfacing with it would fully understand the alphabet soup required to troubleshoot or debug problems?  Or would this all be coming back to a very small group of people?  Contrast this with a world where we have two networks and we can much more quickly root-cause and iterate.  </p><p>Finally - we have a path to removing the cable risk later if we do figure this all out.  If we go all-in on a single topology up front, there is a chance we blow our schedule due to the extra complexity and overhead. </p><p /><p />"
        },
        {
          "id": "1048969226",
          "title": "Simplifying Teleoperation",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1048969226",
          "last_modified": "2025-08-20T12:19:37.159Z",
          "created_at": "2025-08-19T15:19:45.052Z",
          "body_html": "<p>Our existing tele-operation system is very complex, especially on the Pre-Alpha setup.  We have a number of distinct challenges here:</p><ol start=\"1\"><li><p>RemoteSHM - Our realsense cameras are streamed from the robot to the laptop using multi-link wifi, custom transport and shared memory to minimize latency as much as possible (pretty important given how much latency there is with a realsense camera)</p></li><li><p>Laptop + Robot need to have CycloneDDS configured so they can communicate ROS bidirectionally.</p></li><li><p>Need to run/sequence ROS nodes across both the laptop and robot to make sure the setup is stable</p></li><li><p>For VR, also need to attach quest w/ \u201cadb\u201d so the oculus_reader library can read controller poses to be published</p></li></ol><p /><p>This results in a fairly tight coupling between the laptop and the robot, meaning that setting up a teleoperation environment is relatively time-consuming and and difficult to scale.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250819-152241.png\" width=\"751\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1048969226/image-20250819-152241.png?version=1&amp;modificationDate=1755616963564&amp;cacheVersion=1&amp;api=v2&amp;width=751&amp;height=568\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1048969226/image-20250819-152241.png?version=1&amp;modificationDate=1755616963564&amp;cacheVersion=1&amp;api=v2\" data-height=\"569\" data-width=\"751\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1048543266\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250819-152241.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1048969226\" data-linked-resource-container-version=\"3\" data-media-id=\"d8ca6cf6-e06c-48aa-a297-722ce282a137\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1048969226/image-20250819-152241.png?version=1&amp;modificationDate=1755616963564&amp;cacheVersion=1&amp;api=v2&amp;width=1352&amp;height=1024 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1048969226/image-20250819-152241.png?version=1&amp;modificationDate=1755616963564&amp;cacheVersion=1&amp;api=v2&amp;width=751&amp;height=568 1x\"></span><p>I think the root of complexity here is that there is no clear \u201cserver\u201d - the robot and the data collection/teleop laptop form a network of bidirectional peers.</p><p>Another major concern I have is once we start having Alpha and PreAlpha robots - how do we guarantee that someone attaching a laptop configured for PreAlpha data collection to an Alpha robot doesn\u2019t create some sort of unsafe situation?  Or perhaps the other way around?  </p><h2 id=\"SimplifyingTeleoperation-Client\u2192Server\">Client \u2192 Server</h2><p>Let\u2019s start with a simplifying assumption: lets turn the robot into a server and make it as smart as possible, and turn the laptop into a client and make it as dumb as possible.  The idea is that any client can connect to any server without mucking with CycloneDDS or custom UDP transport IPs or ports.</p><p>For the sake of example, we\u2019ll go so far as to assume we can do this in the browser (some problems with this will be outlined below).  So our desired user experience is something like:</p><ol start=\"1\"><li><p>Power up robot</p></li><li><p>Launch teleoperation \u201capp\u201d which exposes our server API</p></li><li><p>Connect laptop to lab network and go to <a href=\"#\" rel=\"nofollow\">http://$</a>{robot_ip}:${api_port} to load the interface</p></li></ol><p>At this point the laptop should be connected to the robot, and ready to show camera images and accept poses/commands.  Easy right?</p><h2 id=\"SimplifyingTeleoperation-VRDataCollection\">VR Data Collection</h2><p>With our shift to cartesian targets via the whole-body controller, we are leveraging Meta Quest VR headsets + controllers to tele-operate the robots.  Due to concerns around comfort, we aren\u2019t using the headset display at the moment.  Continuing with the example client-&gt; server above, <span class=\"inline-comment-marker\" data-ref=\"cb8d1193-20f3-4aa5-848b-37edba47dedf\">we can leverage </span><a href=\"https://developers.meta.com/horizon/documentation/web/webxr-overview/\" class=\"external-link\" rel=\"nofollow\"><span class=\"inline-comment-marker\" data-ref=\"cb8d1193-20f3-4aa5-848b-37edba47dedf\">WebXR</span></a><span class=\"inline-comment-marker\" data-ref=\"cb8d1193-20f3-4aa5-848b-37edba47dedf\"> which allows a quest device\u2019s browser</span> to attach to a server to provide a VR experience.</p><p>Our existing VR teleop makes use of an <code>oculus_reader</code> library, which relies on the headset being enabled for debug mode w/ adb (Meta headsets are just fancy Android devices).  This library is used to read tracked poses and button events from the attached headset which are then published via ROS to the robot.</p><p>Here, we can have a javascript \u201cclient\u201d which is hosted by our robot server which runs in the Quest browser.  <span class=\"inline-comment-marker\" data-ref=\"1fce80ac-344f-46cf-98b5-d2409c7896e7\">The client gets a WebXR session handle, and can provide a GUI (replacing the tele-op gui from above) which can have various state or show camera images from the robot to enable tele-operation.</span></p><p>For data collection specifically, we send \u201cpedal\u201d events to start and stop recording - here our pedal events would be handled as keyboard events by the quest\u2019s client, which would then call endpoints on the server API hos<span class=\"inline-comment-marker\" data-ref=\"37cf85cd-1676-475d-ab20-65d85eae3cbb\">ted by the robot.</span></p><span class=\"inline-comment-marker\" data-ref=\"a1b70f30-35e8-43e5-adc4-cddc9eddcbf9\"><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250819-154253.png\" width=\"743\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1048969226/image-20250819-154253.png?version=1&amp;modificationDate=1755618174312&amp;cacheVersion=1&amp;api=v2&amp;width=743&amp;height=574\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1048969226/image-20250819-154253.png?version=1&amp;modificationDate=1755618174312&amp;cacheVersion=1&amp;api=v2\" data-height=\"574\" data-width=\"743\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1048739860\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250819-154253.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1048969226\" data-linked-resource-container-version=\"3\" data-media-id=\"fd638e4e-1052-449b-bea7-90fb91f16fcb\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1048969226/image-20250819-154253.png?version=1&amp;modificationDate=1755618174312&amp;cacheVersion=1&amp;api=v2&amp;width=1338&amp;height=1034 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1048969226/image-20250819-154253.png?version=1&amp;modificationDate=1755618174312&amp;cacheVersion=1&amp;api=v2&amp;width=743&amp;height=574 1x\"></span></span><p>Note - WebXR is really nice, but I think this may actually be a challenge for us if we don\u2019t want to use the Quest displays.  Mirroring the display/GUI to the laptop is possible, but configuring this appears to be involved - which sorta defeats the whole purpose of simplifying the setup.</p><p>An alternative approach here is a local daemon running along-side the quest to serve poses via HTTP so the robot-served client can tie it all together.  I\u2019ll evaluate this too.</p><h2 id=\"SimplifyingTeleoperation-HTTP\u2192ROSBridging\"><span class=\"inline-comment-marker\" data-ref=\"37cf85cd-1676-475d-ab20-65d85eae3cbb\">HTTP \u2192 ROS Bridging</span></h2><p><span class=\"inline-comment-marker\" data-ref=\"37cf85cd-1676-475d-ab20-65d85eae3cbb\">There are a number of existing \u201cROS bridges\u201d out there which will re-publish your data on websockets - bu</span>t we\u2019ll assume we can do this manually right now so that we can have a \u201ccrisp\u201d API that makes a bit more sense semantically.  We\u2019ll have a uvicorn FastAPI HTTP server running inside a ROS node on the robot which can accept HTTP requests and publish/subscribe to ROS messages, and the client (running on the Quest in this case) only needs to worry about speaking HTTP:</p><ul><li><p><code>GET /mjpeg/wrist_left/compressed</code> - return camera MJPEG as <code>multipart/x-mixed-replace</code> streams.</p></li><li><p><code>POST /recordings/start</code> - initialize a recording episode</p></li><li><p><code>GET /recordings/$id</code> - retrieve websocket for recording feedback</p></li><li><p><code>PUT /recordings/$id/save</code> - save the recording (and end it)</p></li><li><p><code>PUT /recordings/$id/cancel</code> - cancel the recording (and discard it)</p></li><li><p><code>GET /teleop/tracking</code> - intialize a websocket for VR control.  VR controller will be enabled as long as this websocket is alive.  If the websocket is dead, the robot isn\u2019t controllable.</p></li><li><p><code>POST /teleop/reset</code> - reset the robot</p></li></ul><p>The client running in the Quest would have a simple GUI (or use pedals/controller buttons) to call these endpoints.  When its time to tele-operate the robot, the tracking websocket can be created and the current WebXR session can read tracked poses from the quest controllers and send them up the websocket the robot.  The robot can in turn send information like haptics (WBC solve status) and other feedback down the websocket for the client to process.</p><p>Each camera can be retrieved as a low-latency MJPEG stream which can be displayed in an <code>&lt;img&gt;</code> tag without any re-encoding overhead.</p><p>You can see just the camera path (<a href=\"https://github.com/HumanoidTeam/hmnd/pull/703\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://github.com/HumanoidTeam/hmnd/pull/703</a> ) as an example.</p><p>On the robot side, our ROS bridge will maintain the necessary subscriptions and state to feed the client and accept commands.  Incoming VR poses from the tracking websocket can be converted into WBC targets and published using the VR \u201c<a href=\"https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1037304324/Robot+Puppetry?atlOrigin=eyJpIjoiZTBiYzE3MTAxNDAxNGY2OWI5ODEwOTA2NzE2ZDcwMTMiLCJwIjoiYyJ9\" rel=\"nofollow\">puppet</a>\u201d, and mapped buttons can trigger other endpoints which may call services or start actions as needed.</p><p>While this approach does introduce a second transport protocol (HTTP), this cost is paid once but the benefits of reduced setup friction are realized over and over again.  Especially as we scale.</p><h2 id=\"SimplifyingTeleoperation-PostBrowserWorld\">Post Browser World</h2><p>In the example above, I show how we could use WebXR and have the Quest browser act as our client.  This works great as long as our input devices are supported by the Quest.  Or that we are using a Quest at all.  But what if we decide to do something else entirely?</p><p>Fortunately, HTTP clients are far more pervasive and well-supported than ROS clients, so I don\u2019t expect there to be any issues here.  In fact, we could build a tele-op client in whatever language we wanted using whatever tools we wanted because HTTP is supported by practically everything. </p><p>For example, if we decided to move to Vibe wrist-tracking - we could use a PCVR-type setup with a Windows laptop (since we don\u2019t need to worry about ROS networking or anything like that). </p>"
        },
        {
          "id": "1048543355",
          "title": "Configuring Robots",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1048543355",
          "last_modified": "2025-08-20T09:08:54.687Z",
          "created_at": "2025-08-19T17:29:06.655Z",
          "body_html": "<p>Currently our robot stack is configured via soup of YAML files, ROS params and URDF files scattered across our git repository.  As we scale up more platforms and more units, we will need to be more deliberate about how we build and track configuration.  The key goal is that we should have a single unified view of configuration for a given robot, so that we can completely capture the configured state of the robot for data collection activities (in addition to the version of software running on the robot).</p><p>rosparam, the venerable approach to injecting configuration into your nodes, is not exactly what we are going to want.  ROS has no way to validate configuration and with ROS2 there is no longer a global source of truth for params (the old roscore did this), and instead params are managed by each node individually.  One benefit to this approach is that it avoids having nodes reaching across to \u201cunrelated\u201d parameters and coupling the system together in fragile ways.  But the major downside is that there is no good way to capture the \u201creal\u201d state of the system after loading all parameters and applying overrides so that we can track configuration  along with our software version - very important for data collection and evaluation activities.</p><h2 id=\"ConfiguringRobots-CanonicalConfigurationandCalibration\">Canonical Configuration and Calibration</h2><p>To start with, we\u2019ll consider a simple world where we have a few platforms (alpha_wheelbase and alpha_biped) and a few units of each one.</p><p>The Canonical Configuration represents the \u201cstandard\u201d configuration of any given platform.  If we could manufacture with 0 tolerance and everything was exactly the same - this would be our robots' configurations across the fleet.  Typically this will be coming from CAD and various defaults set in version control for a given robot platform.  For example, the Alpha wheelbase may have some default stiffness of its impedance controllers or scaling factors for its actuators.</p><p>Of course, we don\u2019t live in some perfect world - we should expect that each robot will need to be tweaked individually so that the robots behave the same even though their hardware is slightly different.  Camera intrinsics/extrinsics, IMU drift, actuator offsets/scaling, frictions - all of these could be different for each robot.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"699\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1048543355/Untitled%20Diagram-1755678554978.drawio.png?api=v2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1048543355/Untitled%20Diagram-1755678554978.drawio.png?api=v2\" loading=\"lazy\"></span><p>For each robot when we load the software stack, we should load the platform configuration for the robot and then apply the calibration as an override to get our single robot-specific configuration.  This configuration can then be saved when we perform data collection activities to ensure we have full traceability of potential differences per robot. </p><h2 id=\"ConfiguringRobots-ExperimentationandManagingaFleet\">Experimentation and Managing a Fleet</h2><p>We won\u2019t just have two layers of configuration though.  We may have various controller or perception parameters tuned differently to support some ongoing A/B experimentation or perhaps just because some environment or use-case benefits from slight tweaks to configuration.</p><p>So really our configuration is some canonical base, then we layer per-robot calibration (potentially derived from service records or calibration-related activities - but this is out of scope here), then we can layer on additional configuration overrides as needed until we get our final configuration.</p><h2 id=\"ConfiguringRobots-ImportingandExporting\">Importing and Exporting</h2><p>Right now its difficult to think of configuration as anything other than the YAML or XML files on disk.  But we should only consider these as rendered views of our system\u2019s configuration.  We can import from YAML or XML (if necessary), and we can export to these files similarly (or something else).</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250819-174150.png\" width=\"265\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1048543355/image-20250819-174150.png?version=1&amp;modificationDate=1755625311922&amp;cacheVersion=1&amp;api=v2&amp;width=265&amp;height=190\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1048543355/image-20250819-174150.png?version=1&amp;modificationDate=1755625311922&amp;cacheVersion=1&amp;api=v2\" data-height=\"190\" data-width=\"265\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1048739930\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250819-174150.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1048543355\" data-linked-resource-container-version=\"1\" data-media-id=\"eab26eda-abc8-42d8-894e-981173528cee\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1048543355/image-20250819-174150.png?version=1&amp;modificationDate=1755625311922&amp;cacheVersion=1&amp;api=v2&amp;width=265&amp;height=190 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1048543355/image-20250819-174150.png?version=1&amp;modificationDate=1755625311922&amp;cacheVersion=1&amp;api=v2&amp;width=265&amp;height=190 1x\"></span><p>Ideally we use something like Pydantic define our configuration schema in python - so we know not just default values but types, expected ranges, optionality so that we can more effectively validate our configuration.  We can catch typos in keys and ensure that our final configuration is complete.</p><p>When we import configuration from various sources, we can track the provenance of those keys in our internal model so that we know where a given parameter came from.  If some parameter is causing issues with data collection, it should be clear that this parameter is being set from version control or whether it is some override being applied somewhere else.</p><h2 id=\"ConfiguringRobots-NamespacingandPrefixes\">Namespacing and Prefixes</h2><p>At some point, we may be writing all of this configuration to some large database to be managed for the fleet.  You could imagine a world where field service operations are replacing components like actuators and performing partial re-calibration - we\u2019d want these new configuration parameters to be associated with that activity and tracked over time so we can get a full history of the robot configuration.</p><p>Like ROS2, we want to encourage modules to own their local configuration, but at some point these various keys need to be brought under a global namespace so we can manage the whole thing.  Storing hierarchical configuration in a database would be way more complexity than necessary, and so we should consider our paths \u201cflattened\u201d.  Different modules would then be responsible for different \u201cprefixes\u201d in the configuration, which means we can still avoid many of the problems that ROS2 tried to avoid, while still having a flat global namespace for tracking our configuration over time.</p><p>For example, we may import the URDF for alpha wheelbase under <code>hmnd.alpha_wheelbase.description</code>, with description having top-level keys for joints, transmissions, etc.  At some later point, we may apply some alpha-specific simulation overrides to <code>hmnd.alpha_wheelbase.description</code> (some sort of partial URDF or YAML fragment), and then we can ask the configuration system to export <code>hmnd.alpha_wheelbase.description</code> (including overrides) as a new URDF.</p><h2 id=\"ConfiguringRobots-Implementation\">Implementation</h2><p>So this all sounds great in theory - how do we make this happen?  I expect this section to get really fuzzy as we capture various concerns.  Off the top of my head:</p><ol start=\"1\"><li><p>Some nodes load YAML directly in cpp (ethercat, hmnd_vision)</p></li><li><p>Some nodes load params from ROS2</p></li><li><p>Some nodes get params from launch files</p></li><li><p>xacros are used to customize and reduce duplication across a number of XML configs for controllers</p></li></ol><p>We probably need to prioritize calibration over \u201cglobal snapshots\u201d for data collection, so we\u2019ll likely want to start with how we load YAML for actuators and ros2 control that vary per robot.</p>"
        },
        {
          "id": "1037304324",
          "title": "Robot Puppetry",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1037304324",
          "last_modified": "2025-08-13T13:21:51.804Z",
          "created_at": "2025-08-13T12:12:27.928Z",
          "body_html": "<h2 id=\"RobotPuppetry-Control,PolicyandTeleoperation\"><strong>Control, Policy and Teleoperation</strong></h2><p>Ideally, we have a single interface which our various tele-operation schemes can use and which our learned policies can use to control our robot controller.  Our new <a href=\"https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1020264502/Whole+Body+Control+for+Dummies?atlOrigin=eyJpIjoiYTZlMzI3ZGZhOWE0NGMxYjkxNjJkMzlkNWU1NmViMDYiLCJwIjoiYyJ9\" rel=\"nofollow\">whole body controller</a> (WBC) accepts high-level cartesian targets which it will use to generate joint trajectories which satisfy a number of constraints.  But there are some slight differences to these interfaces which can make things challenging.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250813-121306.png\" width=\"523\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1037304324/image-20250813-121306.png?version=1&amp;modificationDate=1755087187957&amp;cacheVersion=1&amp;api=v2&amp;width=523&amp;height=412\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1037304324/image-20250813-121306.png?version=1&amp;modificationDate=1755087187957&amp;cacheVersion=1&amp;api=v2\" data-height=\"412\" data-width=\"523\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1037435478\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250813-121306.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1037304324\" data-linked-resource-container-version=\"4\" data-media-id=\"cd958b54-320c-4845-a67e-2317e393d698\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1037304324/image-20250813-121306.png?version=1&amp;modificationDate=1755087187957&amp;cacheVersion=1&amp;api=v2&amp;width=523&amp;height=412 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1037304324/image-20250813-121306.png?version=1&amp;modificationDate=1755087187957&amp;cacheVersion=1&amp;api=v2&amp;width=523&amp;height=412 1x\"></span><p>The policy for example runs slower than our WBC and when its running off-board has some unpredictable latencies.  <span class=\"inline-comment-marker\" data-ref=\"2d633368-8b9b-4e90-afe3-7a61efe4ac31\">For this reason (and that it generally improves predictions), policies learn to predict \u201cchunks\u201d which are effectively future targets for the WBC.  Tele-operation on the other hand relies on human operators controlling the robot in realtime, meaning we want responsiveness.</span>  Human operators cannot predict or communicate future intent the same way a policy can, yet want the behavior of the trained policy to match the behavior of the demonstrated behavior - even though we often have some \u201chard-coded\u201d mappings in the middle here that can be tricky to untangle. </p><p>Further complicating matters is that these aren\u2019t the only possibilities.  We may have leader arms which directly control joint poses.  Or we may have a number of discrete preset targets we want to use (for example driving simulation), perhaps with some randomization added.</p><h2 id=\"RobotPuppetry-TheRobotisaPuppet\"><strong>The Robot is a Puppet</strong></h2><p>Imagine for a moment that the robot is a puppet.  We may connect strings to it and pull on the various limbs (each string being like a cartesian target), or we may think of it like a sculptor\u2019s manikin which can be posed directly.  Or maybe its a socket puppet where you jam your hand up its backside to control it. The point is that there are a number of different modalities or mappings from intent to the desired action.</p><p>In reality, this is another layer of control - but naming this a \u201ccontroller\u201d I think confuses terminology too much since this isn\u2019t really a controller in the classical sense since we rely on something \u201cabove\u201d to close the loop.  Instead, we should create a new interface in the system and for fun we will call it <strong>Puppet</strong>.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-center\" width=\"585\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1037304324/Untitled%20Diagram-1755088321691.drawio.png?api=v2&amp;version=2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1037304324/Untitled%20Diagram-1755088321691.drawio.png?api=v2&amp;version=2\" loading=\"lazy\"></span><p>A Puppet is simply an interface for a module that converts puppet-specific intents into Cartesian targets suitable for the WBC.  The idea is that the WBC doesn\u2019t care about the specifics - any Puppet can control the WBC and use whatever input is appropriate.</p><p>The primary benefit here is to create a dedicated place for this logic that can be tested, rather than burying it inside the respective higher-level behavior layer code.  Different puppets may perform different amounts of smoothing, interpolation or blending before issuing the targets to the WBC, and this logic is ideally easily identifiable and testable.  Puppets may adjust the mode of the WBC in addition to just sending targets, so the logic here can be quite stateful/complex - the more we can separate this \u201cconversion\u201d logic from the WBC or the actual Policy/Sim/Teleop, the easier it is to test and compose things.</p><p><strong>VR Puppet</strong></p><p>The obvious example here is a VR puppet, which takes VR-specific intent from the Oculus controller (poses and transforms of the controllers, button states) and maps these into Cartesian targets for the WBC.  This may involve setting specific modes in the WBC, specifying constraints or a number of other possible actions - but the goal is that an operator can use the VR controllers to effectively control the robot.  We already have this today, but the logic is buried inside of the QuestTeleopServer.</p><p><strong>Leader Puppet</strong></p><p>For Pre-Alpha we may consider the use of a leader-arm puppet which instead of taking VR-specific intent from a controller, takes leader arm poses from a connected device and maps these to robot joint states.  In this example we\u2019ll assume that the <span class=\"inline-comment-marker\" data-ref=\"3c34da72-dbba-4911-8e87-705b45e77b77\">WBC allows for some form of joint-level control</span> (perhaps maintaining constraints and avoiding self-collisions), but we are more-or-less attempting to control each joint individually.</p><p><strong><span class=\"inline-comment-marker\" data-ref=\"2d0a7c51-b604-488a-a831-09469a1f1f9b\">Simulation or Test Puppet</span></strong></p><p>For simulation or test scenarios, we may want to control the WBC much more directly as we have ground-truth information from the test or simulation environment.  For example, we could have a puppet which knows how to interpolate the end effector targets from some random initialization pose to the sides of a tote.  Or perhaps we can choose from a number of discrete pre-recorded cartesian targets to feed the WBC.  The point here is that these intents can be arbitrarily sparse or simple, while the output of the puppet interface should be roughly equivalent across implementations for the WBC.</p><p><strong>Policy Puppet</strong></p><p>An interesting twist here is to consider the chunks of the VLA as intent for a Policy Puppet, which is responsible for feeding the chunks to the WBC at the correct rate.  It may also be that the Policy is an alternative to the puppet (something that feeds targets to the WBC), but I\u2019m including it here since its not the craziest idea.</p><h2 id=\"RobotPuppetry-Summary\"><strong>Summary</strong></h2><p>The gist here is we can create a dedicated layer in the stack to serve as the interface to the WBC where we can place logic (and test it) which doesn\u2019t necessarily belong in the higher-level modules or within the WBC itself.  <span class=\"inline-comment-marker\" data-ref=\"8571130b-8a4c-418c-a27f-1ce8cdc86f42\">We certainly don\u2019t want the WBC being concerned about Oculusisms or Policyisms</span> - but at the same time, we may not want to couple the logic for how we arrive at these Cartesian targets inside of these very complex policies or teleoperation schemes.  So given something like a VR setup we may have the same Oculus controllers and the same overall software stack, but we may swap out the puppets for different use-cases.  Sure - we could just pile all of this into the QuestTeleop server - but we can probably benefit by pulling this logic out and testing it independently.  We could have puppets for more novice operators performing some simple/directed data collection activities, while having puppets for more expert users that have much more flexibility and responsiveness.</p><p />"
        },
        {
          "id": "1026130021",
          "title": "Building Software",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1026130021",
          "last_modified": "2025-08-08T16:13:23.575Z",
          "created_at": "2025-08-05T15:49:44.808Z",
          "body_html": "<p>A build is a process by which our many <strong>source artifacts </strong>(the shit we\u2019ve checked into GitHub) are transformed into a number of intermediate and final <strong>build artifacts</strong>. \u00a0 Sometimes source artifacts aren\u2019t transformed at all (Python scripts, pre-compiled binaries) while others are compiled, templated, linked or archived into different outputs.\u00a0 The build is one of the most important aspects of the software development lifecycle, and will make or break your system as you scale.\u00a0 So what makes a good build?</p><ul><li><p><strong>Hermetic</strong> - Builds are isolated and unaffected by the local environment, ensuring consistent results across machines and CI.</p></li><li><p><strong>Incremental</strong> - Only rebuild or test what has actually changed, making extensive use of caching to speed things up.</p></li><li><p><strong>Traceable</strong> - All artifacts, configurations, and dependencies can be traced thru a single build graph which explains what depends on what, allowing builds to be run in parallel or even distributed.</p></li><li><p><strong>Extensible</strong> - It should be possible for any engineers writing software to extend the build as-needed (new dependencies, new targets, new artifacts).</p></li><li><p><strong>Reproducible </strong>- multiple builds of the same commit are identical. (this is <em>really</em> hard)</p></li></ul><p>A good build allows developers to focus on building robots rather than fighting environments or dependencies.</p><h2 id=\"BuildingSoftware-\ud83e\udd16Platforms,TargetsandBundles\"><strong>\ud83e\udd16\u00a0 Platforms, Targets and Bundles</strong></h2><p>A modern robot is extremely complex, so we\u2019ll introduce some additional terminology to help explain things:</p><ul><li><p><strong>Platform</strong> - a specific robot configuration.\u00a0 Pre-Alpha, Alpha-Wheelbase, Alpha-Biped, Alpha-SpecialSauce, etc</p></li><li><p><strong>Target</strong> - a specific computer within the platform.\u00a0 Including firmware images, SOMs, FPGAs, safety or even 3rd party sensors.</p></li><li><p><strong>Bundle</strong> - artifacts for all the targets of a platform in a single archive, versioned together</p></li></ul><p>During the course of development, there will be dozens of distinct platforms.\u00a0 For a given program phase (Alpha or Beta) we should expect to support builds running on a number of different variations.\u00a0 The build should be flexible enough to represent all of this in a single build graph so that we can leverage as much commonality as possible across targets.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"612\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1026130021/Untitled%20Diagram-1754556058604.drawio.png?api=v2&amp;version=2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1026130021/Untitled%20Diagram-1754556058604.drawio.png?api=v2&amp;version=2\" loading=\"lazy\"></span><p>When a build is produced, a number of artifacts may be produced across a number of target devices for the platform.\u00a0 These should be bundled together during the build so that there is a single versioned artifact.\u00a0 This artifact can then be deployed to the robot, which should take care of ensuring that all of the target devices are updated correctly.\u00a0 With many target devices, this process is anything but simple, but for now we\u2019ll consider the specifics of OTA out of scope, and only consider how we produce these release bundles.</p><h2 id=\"BuildingSoftware-\ud83d\udce6Environments\"><strong>\ud83d\udce6 Environments</strong></h2><p>To get hermetic builds, it's important to consider the environment in which software is built.\u00a0 We can borrow some terminology from cross-compilation:</p><ul><li><p><strong>Host</strong> - the environment actually running the top-level build.\u00a0 Usually this will be your laptop or some CI runner in the cloud.  We should expect quite a bit of variation here (since we can\u2019t really control the host environment, as much as we\u2019d like to).</p></li><li><p><strong>Build </strong>- the environment which actually runs the build.\u00a0 For hermetic builds, we want this to be distinct from the host.\u00a0 Generally no two host environments are the same, and so having a separate build environment provides a way to get consistency across different hosts.  This would be toolchains and libraries.</p></li><li><p><strong>Target</strong> - the runtime environment on our target hardware or simulation.\u00a0 We separate this from the build environment because we typically only need a small subset of the artifacts to actually be deployed.  We don\u2019t need to ship gcc or clang to the robot (usually\u2026)</p></li></ul><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"653\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1026130021/Untitled%20Diagram-1754555655678.drawio.png?api=v2&amp;version=3\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1026130021/Untitled%20Diagram-1754555655678.drawio.png?api=v2&amp;version=3\" loading=\"lazy\"></span><p>We should be able to simply bootstrap the process on any host, which then produces a hermetic build environment which can then be used to produce a number of artifacts.\u00a0 These artifacts would then be packed into some target-specific artifacts (disk images, firmware images) which can all be bundled together depending on the platform and deployed to some specific robot.</p><h2 id=\"BuildingSoftware-CurrentBuild\"><strong>Current Build</strong></h2><p>Our current build is not really much of a build.  There is no real separation between source and build artifacts and no real separation between build and runtime artifacts.</p><p>Pixi is a tool which does help to isolate the host to a degree by providing a way to manage Conda environments using some more modern tooling.  <span class=\"inline-comment-marker\" data-ref=\"a2d93160-679d-4707-8ce1-41d1dccabb3d\">These environments are pretty fragile though</span>, and can't easily be shipped around.  </p><p>Within this environment, ROS's colcon tool is used to kick off a ROS-flavored CMake build, which in turn actually generates a ninja build which actually produces our ROS build artifacts.</p><p>The Pixi environment is stored under a .pixi folder, the ROS artifacts are stored under an install/ folder and some extra bits and pieces are placed under the build/ folder.</p><p>While it's a decent tool for developers managing their local workspaces, Pixi is not the best choice for a good build since it's not truly hermetic (relying on environment variables and rpath hacks), it's not very traceable or incremental (the caching is wildly unreliable), but it is pretty extensible for developers and so it's not the worst possible choice in the short-term as we rush to bring up Alpha and support our PoCs.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"1265\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1026130021/Untitled%20Diagram-1754552661651.drawio.png?api=v2&amp;version=2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1026130021/Untitled%20Diagram-1754552661651.drawio.png?api=v2&amp;version=2\" loading=\"lazy\"></span><h3 id=\"BuildingSoftware-ReleaseImages\">Release Images </h3><p>To mitigate some of the downsides of Pixi, we can actually build the environment in a hermetic rootfs using Bazel.  This allows the image to be archived as a release and shipped to robots instead of rebuilding the Pixi environment for every deployment.</p><p>A number of custom Bazel rules have been produced to allow rootfs images to be produced which can contain arbitrary packages or run arbitrary build steps.  This allows us to make use of Bazel as a foundation for a more proper build <span class=\"inline-comment-marker\" data-ref=\"5bd1fa7e-ac51-4014-9129-cf09c7ba754b\">without giving up pre-built binaries and existing packages</span> (especially those from Nvidia).  A rootfs image is like a Docker container, only slightly more general.  Eventually the hope is that we can boot these rootfs images produced by the build directly on our target hardware.</p><h2 id=\"BuildingSoftware-NextSteps\">Next Steps</h2><p>The Pixi environment has some major downsides as we scale.  First, it's not very granular or composable.  Unless we subdivide our entire codebase into individual Pixi packages, it's difficult to reuse pieces between different environments like training pipelines and robots.  This lack of granularity also leads to a second major issue - the build cannot be cached effectively.  The Pixi cache is far too coarse and cannot easily be cached in CI or across many machines without introducing the risk of a poisoned cache.  Instead of caching an entire environment, we should be <a href=\"https://bazel.build/remote/caching#overview\" class=\"external-link\" rel=\"nofollow\">caching individual build artifacts</a>.</p><h3 id=\"BuildingSoftware-AptandPyPI\"><strong>Apt and PyPI</strong></h3><p>We should move from Conda dependencies <span class=\"inline-comment-marker\" data-ref=\"5b53061a-a96b-4ff3-9225-58ce4a2f1917\">to Apt and PyPI</span>, and rely on a proper hermetic environment built by Bazel.  This environment can be much more granular and compostable with dependencies being assigned not to the environment as a whole, but individual modules within the environment.  Conda is a fantastic tool for quickly spinning up R&amp;D environments, but the runtime environment on our nVidia-provided compute hardware (like the Orin or future Thor) can make this very difficult as <span class=\"inline-comment-marker\" data-ref=\"e57b6148-8c1d-47b6-9f7f-49cadafb2ca8\">nVidia frequently provides binaries which expect an Ubuntu ABI or specific Python versions</span>.  Given the strategic importance and complexity of the nVidia stack, it makes sense to \u201clean in\u201d and accept these constraints.  We will use the Jetpack-supported versions of Ubuntu, Python, Numpy, Pytorch, etc as much as possible since these versions are largely pre-integrated and widely supported.  Any deviations here (such as those from Conda-built packages) are a significantly liabiltiy and risk subtle ABI-breakage and wasting enormous amounts of developer time troubleshooting and debugging.</p><p>This will still require some additional tooling to support quick iteration and development locally.  One simple solution to this would be to embrace remote SSH workflows via vscode, with Bazel producing and updating a developer image that can be 'booted' into vscode.  Helper scripts can be used to add dependencies in a way that get tracked in the build (similar to <code>pixi add</code>).</p><p>When this phase is complete, we should no longer have a Pixi virtual environment, but we still have entangled build and runtime environments. </p><p>Most of our apt and PyPI-related dependencies exist in public HTTP repos which are not controlled by us.  This represents a risk for build reproducibility and availability.  What happens if someone sneaks a breaking change into the repo?  What if a repo becomes unavailable for some reason, breaking all of our builds?  We should be able to easily setup a read-thru cache for these repositories using S3.  The basic idea is we point our mirror at the upstream repository (<a href=\"http://ports.ubuntu.com\" class=\"external-link\" rel=\"nofollow\">ports.ubuntu.com</a> for example) and an S3 bucket.  When requests come to the mirror, we first look in the bucket for the asset.  If its not there, we proxy the request to the upstream repository, and write it to S3 while we serve it to the user.  We may need to do some locking w/ dynamo to prevent conflicts while writing to S3, but this is a relatively lightweight system that will end up with all of our dependencies \u201ccached\u201d in S3.  If the upstream repo goes offline, then we still have the assets in S3.  If something upstream changes, we can still go back to previous versions since we have everything versioned in S3.  This should give us the benefits of leveraging public repositories without many of the downsides (until some day we standup dedicated repositories ourselves).  </p><h3 id=\"BuildingSoftware-ROSandColcon\"><strong>ROS and Colcon</strong></h3><p>The next steps would be to consolidate our ROS packages, and to get to a single pass build.  Colcon (and ament, the underlying ROS2 build framework) rely on package.xml metadata to order dependencies and run multiple passes over the build.  Meaning that package A must be built before package B\u2019s \u201cfind_package\u201d CMake-isms can successfully locate the package.  This complicates things significantly and means that integrating new dependencies often requires wrapping them up as ROS packages and further couples our stack to ROS.  Our VLA focus will lead to fewer ROS nodes anyway, so it makes sense to simplify here.  <span class=\"inline-comment-marker\" data-ref=\"bc743cc4-3d72-4793-86d7-795c866d6430\">A flat, single-pass build can then be expressed purely as CMake without any colcon or ROS2 specifics</span>.  Rather than relying on topologically sorting packages and using \u201cfind_package\u201d and friends to resolve dependencies, CMake can simply \u201cadd_subdirectory\u201d to build up a single unified build containing all our dependencies.  Some complexity may pop up for certain build dependencies that must exist before we actually run CMake itself (think of something like compiling protobuf from source) but we\u2019ll manage that if it comes up.</p><p>Finally at this point, the CMake targets can be ported to Bazel or wrapped as foreign builds.  This brings the entire granular build graph into Bazel and allows for artifacts to be cached much more effectively.</p><h3 id=\"BuildingSoftware-SeparatingRuntimeandBuild\">Separating Runtime and Build</h3><p>At this point we can finally start to peel apart our build and runtime environments.  Bazel and it's toolchains can produce a build environment with any build dependencies (multi-stage potentially, but ideally not), and then this final build image can be used to produce our runtime artifacts which we can install into our target environments.  Because we want to use Ubuntu-compatible packages, we can treat the build image as a sysroot for compilation - and this could even allow us to build cross-arch, this this isn\u2019t an explicit goal at this point.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"730\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1026130021/Untitled%20Diagram-1754558565374.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1026130021/Untitled%20Diagram-1754558565374.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p>This means we can have 100s of GB of development and build assets while only installing a couple GB on the robot itself.  This optimization will be critical as we start scaling and performing OTA updates.</p><p>The more granular build graph makes it much easier to leverage build caching across many different branches, versions, hosts, architectures, etc to accelerate builds.  The dependencies can be individually traced through the build graph making it easier to share artifacts (libraries, binaries or other tools) across multiple projects.  For example, the ML transformations running on the robot can specify exactly their local dependencies within Bazel and be shared across a number of target configurations including the data pipeline running in the cloud.  </p><h2 id=\"BuildingSoftware-Summary\"><strong>Summary</strong></h2><p>The broad theme here is to go from a coarse-grained build with an R&amp;D environment toward a more fine-grained build graph which is more cacheable, more composable and more traceable.  This is going to be a long-term effort, but incrementally we can get there.  This end-state is going to be necessary if we want to ship and support 100s or thousands of robots.  </p><p />"
        },
        {
          "id": "1028981407",
          "title": "Erecting the Monolith",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1028981407",
          "last_modified": "2025-08-08T15:59:22.051Z",
          "created_at": "2025-08-07T12:33:50.465Z",
          "body_html": "<p>The current robot architecture inherits quite a bit from the pre-alpha scramble for early PoCs.  Many ROS nodes, multiple controllers, behavior trees, configuration spread over a a number of YAML and XML files (with templating/macros of course).  For more traditional robotics stacks, this is generally how things get started:</p><p>You have a number of launch files, which coordinate how the various nodes are started and configured, and then these nodes publish and subscribe to various topics to wire themselves into a graph.  Data flows through this Graph, and can be inspected at various points using command line tooling like <code>ros2 topic echo</code> and friends.  In <a href=\"https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1010335765/Robot+Middleware?atlOrigin=eyJpIjoiYjY0YjBhMTc1MzM2NDM4Y2I4N2FjYThkNmZkOGM1YjYiLCJwIjoiYyJ9\" data-card-appearance=\"inline\" rel=\"nofollow\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1010335765/Robot+Middleware?atlOrigin=eyJpIjoiYjY0YjBhMTc1MzM2NDM4Y2I4N2FjYThkNmZkOGM1YjYiLCJwIjoiYyJ9</a>  I attempted to make the case that this probably isn\u2019t what we want to do, and so in this document we\u2019ll focus more on the \u201chow\u201d rather than the \u201cwhy\u201d.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250807-123523.png\" width=\"1027\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1028981407/image-20250807-123523.png?version=1&amp;modificationDate=1754570126067&amp;cacheVersion=1&amp;api=v2&amp;width=1027&amp;height=465\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1028981407/image-20250807-123523.png?version=1&amp;modificationDate=1754570126067&amp;cacheVersion=1&amp;api=v2\" data-height=\"928\" data-width=\"2048\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1029210113\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250807-123523.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1028981407\" data-linked-resource-container-version=\"3\" data-media-id=\"967ccaee-1657-4f3b-aa12-db4e15047801\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1028981407/image-20250807-123523.png?version=1&amp;modificationDate=1754570126067&amp;cacheVersion=1&amp;api=v2&amp;width=2048&amp;height=928 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1028981407/image-20250807-123523.png?version=1&amp;modificationDate=1754570126067&amp;cacheVersion=1&amp;api=v2&amp;width=1027&amp;height=465 1x\"></span><p>In addition to the points made in the doc referenced above, we should also just simply acknowledge where robotics is going and try to align our long-term roadmap with this trend.  Instead of having a number of hand-crafted modules like \u201cgrasping\u201d, \u201cmanipulation\u201d, \u201cplanning\u201d, etc these systems are overwhelmingly moving toward learned approaches which are defined more by the data than the code.  In this world, having a graph of independent functions doesn\u2019t make much sense,  since some cross-attention layer somewhere is going to be integrating all of this in a massive neural network.  While we will still have other auxiliary processes in addition to the \u201ccore\u201d models used to execute policies on the robot, we should be mindful that the capabilities of these models will grow over time, and the stuff \u201coutside\u201d the model (related to robot behaviors at least) will shrink.</p><p>As a final point before we get started, the goal isn\u2019t so much to remove ROS entirely, but to remove ROS from the \u201ccore\u201d of the system.  We should expect that we\u2019ll be publishing/recording ROS-compatible data even after we complete the transition as described here.</p><h2 id=\"ErectingtheMonolith-Microcosm:TheControllerStack\">Microcosm: The Controller Stack</h2><p>The initial controller stack for alpha has been born from a much more chaotic controller stack from the pre-alpha, which relies on the Rainbow SDK for low-level control and operates with a patchwork of nodes, controllers etc.  We\u2019ll zoom in here with what we have for Alpha today and look at where we should take things in the near future.</p><p><strong>Alpha Wheelbase Controller Stack</strong></p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"1357\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1028981407/Untitled%20Diagram-1754571182500.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1028981407/Untitled%20Diagram-1754571182500.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p>This is a snapshot of the Alpha wheelbase controller stack (part of it) -<span class=\"inline-comment-marker\" data-ref=\"daaab991-b6bc-424c-8fff-81a90d7bf480\"> there are about 15 nodes (across only a couple processes) and about 32 topics here</span>.  For reference, this is just from<span class=\"inline-comment-marker\" data-ref=\"7e2df9f4-2498-4db2-b5b8-2e2175222242\"> booting up the mock controllers in my workspace</span>.  There is a LOT of additional complexity here that is not necessary for our future path - basically a whole-body controller (WBC) driven by a high-level large behavior model like a VLA.  We don\u2019t need to swap controllers, we don\u2019t need to have all these separate interfaces within ROS.  It\u2019s extremely difficult to see the dataflow here, and its very difficult to test individual pieces or to identify the true \u201cboundary\u201d between our hardware interfaces and our core logic (since a lot of this stack depends on what platform/description we launch with).  <span class=\"inline-comment-marker\" data-ref=\"0705ebab-91a3-4574-9766-992bab33d550\">As a simple example, how would we trace which joint states/commands were associated with which controller?</span>  <span class=\"inline-comment-marker\" data-ref=\"c2f81f81-cf65-4d45-899d-acc4b3359fb1\">How would we deal with continuity issues when swapping controllers \u201cunder load\u201d</span>?</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"973\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1028981407/Untitled%20Diagram-1754573671690.drawio.png?api=v2&amp;version=3\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1028981407/Untitled%20Diagram-1754573671690.drawio.png?api=v2&amp;version=3\" loading=\"lazy\"></span><p>Here we can still wrap our control system in a node (<span class=\"inline-comment-marker\" data-ref=\"a2cddc9c-36f4-4a89-b8e5-620e4fea2c43\">and publish data like TF</span>, actuator states, joint states, etc) - but we should try to consolidate into a few clean layers that can be more easily parameterized using the robot model from the URDF.   Many of the individual controllers from the ros2_control_node are holdovers from PreAlpha, and so will be folded into the WBC. <span class=\"inline-comment-marker\" data-ref=\"ba88b0b3-bcd7-4cec-9012-5f21a85b54be\"> The joint control mechanism is ideally an impedance controller</span>, but we may need to swap in an<span class=\"inline-comment-marker\" data-ref=\"cbf77ca0-7274-4764-96c3-44dcb5765f55\"> admittance controller for certain scenarios (</span>low-fidelity simulators like Isaac for example - but ideally we can avoid this with better actuator models).</p><p>We also consider two additional interface layers to consider: the <span class=\"inline-comment-marker\" data-ref=\"faa93231-25e8-4522-8ec9-b0a6488b7464\">HAL</span> and a potential safety boundary.  <span class=\"inline-comment-marker\" data-ref=\"6d9a116c-c05d-4b31-afe9-8666c97233f8\">In the HAL, our actuator control is really just a bag of actuators</span> which may be configured with limits and encoder scaling values and such, but there is no real \u201csemantic\u201d meaning.  Its just a bag of hardware.  Once we get to joint and WBC, the morphology of the robot becomes more important and so these actuators are assigned to specific joints and those joints are arranged in a specific way with inertias, weights, stiffnesses, etc.  <span class=\"inline-comment-marker\" data-ref=\"b22441f7-a138-49f2-b2c4-4b8510e594c5\">In an ideal world, the ONLY thing that changes between simulation and real hardware is below the hardware boundary: same URDF, same controllers - but we have an interface which abstracts over the simulated actuators and the real, EtherCAT actuators.  </span></p><p>there is also a potential safety boundary in here if we consider the future biped.  We may need to run actuator control, impedance control and some portion of WBC in a safety-certifiable way (at least the tasks responsible for keeping the robot from losing balance for example).  Having the safety interface \u201cfurther up\u201d the control stack is more expensive as it increases the scope of the system which must be certified, but because control loops are looser towards the the top it can be easier to manage communication between our soft real-time Linux environment and our hard real-time safety environment if we end up moving this direction.  Put another way, its a bit easier to close a 50Hz loop between Linux and a safety MCU than to close a 1000Hz loop.</p><h2 id=\"ErectingtheMonolith-s/topics/queues\">s/topics/queues</h2><p>We\u2019ll continue with this \u201csimple\u201d example of the system, since it includes full feedback loops from joint states and commands across a number of time-scales.  Without ROS, how do we communicate between our actuator control, joint control and WBC modules?  How do we manage the fact that these things will be operating at different frequencies?</p><p>Because of the 1000Hz update loop, the coupling between the joint control and actuator control is very tight.  I<span class=\"inline-comment-marker\" data-ref=\"886130f7-47d4-4d19-b4a2-72b70ad88fa3\">n ros2_control this doesn\u2019t actually rely on any topic (thankfully)</span>, instead the joint controller \u201creads\u201d the actuator states via the ethercat plugin, and then writes the commands via the same plugin.  This depends on both the EtherCAT master and the ros2_controller running at the same rate (1000Hz), though they aren\u2019t actively synchronized.  The joint controller simply polls the state of the actuators at 1000Hz, and these states are updated at the same rate via the EtherCAT master and latched in some internal buffers.  Similarly, the joint controller will issue commands at 1000Hz, which are polled by the EtherCAT master in its 1000Hz loop and sent to the slaves.</p><h3 id=\"ErectingtheMonolith-InversionofInversionofControl\"><strong>Inversion of Inversion of Control</strong></h3><p>With the ROS datapath, we have callbacks executing at the rate of <strong>other nodes' publishers</strong>, <span class=\"inline-comment-marker\" data-ref=\"604bfbdd-2da3-4374-b6c7-4fbf8e5a5701\">along with some \u201clocal\u201d update loop and we need to synchronize all of this.</span>  This makes it difficult to control timing, as other (presumably misbehaving) nodes can flood a topic and impact the CPU usage of other nodes.  This can make it impossible to even do things like report diagnostics or fail in some safe/predictable manner.  With multi-threaded executors, <span class=\"inline-comment-marker\" data-ref=\"0f79b0ec-a739-423f-87be-b41058f7f9dc\">these callbacks can all be firing concurrently in many different threads</span>, resulting in significant amounts of lock contention (wasting CPU) and significant risk of sneaky race conditions and subtle bugs.  On top of all that, its impossible to control the order that these things happen resulting in nondeterministic behavior - you will never be able to reconstruct the internal state of that node from recorded data or logs since its fundamentally concurrent.  You are at the mercy of the Linux scheduler and DDS QoS.  </p><p>We don\u2019t need to fire some subscriber callback a<span class=\"inline-comment-marker\" data-ref=\"304f9c26-73c1-43c2-b428-830be3ddf5a5\">t 1000Hz in the WBC to respond to joint states</span>.  Instead, the joint controller should write its updates a bounded circular buffer as a queue.  This bounds the latency of the system and memory, while providing a means to decouple the timing of our fast impedance control loop and the slower WBC.  So the joint controller scrapes the HAL for its actuator states at 1000Hz and the WBC scrapes the joint controller\u2019s queue at ~50Hz for its joint states (<span class=\"inline-comment-marker\" data-ref=\"0c494a68-f41a-47d2-ac83-2c1bd7d92068\">each time it scrapes it will get a buffer of ~20 states if we operate at 1000Hz)</span>.  You could get a similar effect by actually having the subscriber writing to a circular buffer in the WBC, but it would still be a thread in the WBC process doing this and so you still run the risk of starving out other tasks (timers, callbacks) on the executor and you still have all the overhead of messaging w/ DDS.</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"879\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1028981407/Untitled%20Diagram-1754579766891.drawio.png?api=v2&amp;version=2\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1028981407/Untitled%20Diagram-1754579766891.drawio.png?api=v2&amp;version=2\" loading=\"lazy\"></span><p>With the alternative datapath, the core logic looks very similar - but we make the queues within ROS explicit at the producer and the consumer scrapes these queues on their own time.  <span class=\"inline-comment-marker\" data-ref=\"913470c9-d524-49cd-9171-769a475c588f\">In the example above, the WBC runs at 50Hz and simply drains the buffer of the joint controller every time it loops resulting in approximately 20 items in the buffer each iteration</span>.  Because the queue is explicit we get a number of other benefits:</p><ul><li><p><span class=\"inline-comment-marker\" data-ref=\"757956b4-92ca-437a-b7b3-8bfc81f86536\">deterministic execution </span>- the WBC controls the rate at which it drains and can do this predictably compared to a number of concurrent callbacks</p></li><li><p>explicit queue semantics - if the WBC is slow, th<span class=\"inline-comment-marker\" data-ref=\"07b2551b-0efb-4821-b0a3-0ef6101e73f6\">e joint controller overflows the queue which allows us to trigger faults easily</span>.  if the WBC is fast (or the joint controller is slow), <span class=\"inline-comment-marker\" data-ref=\"6aa693c7-014c-4f6b-8620-72d70706ad25\">the WBC will underflow the queue which can trigger other behaviors</span>.</p></li><li><p>only one queue per producer - much easier to reason about reliability and latency.</p></li><li><p>each module runs at a consistent rate - the WBC code runs at 50Hz and the Joint Controller runs at 1000Hz - no mixing/matching - also easier to reason about latencies and performance.</p></li></ul><p>The primary downside of this approach is that fan-out is slightly more difficult (meaning having multiple \u201cdownstream\u201d consumers of the joint state queue). <span class=\"inline-comment-marker\" data-ref=\"9af64dc4-2512-4cd9-aef7-e36b149b8c50\"> In practice this can be mitigated easily by consolidating to a linear datapath</span> which avoids fanning out in the first place.  In the case of logging data, you could either log the data which is produced as its written to the joint state queue, or you could dump the buffer as its consumed after its used to update the internals of the WBC.  But even better is to log only at the HAL boundary which is the interface between the software stack and the outside world and rely on a deterministic stack to ensure we can reconstruct any intermediate state purely from this HAL data.  So in this example we\u2019d log the actuator states, and pass them to our joint controller during replay to reconstruct the joint states.  This is much easier said than done, and so there is no problem logging intermediate streams as an alternative (I/O budgets permitting).  In that case, logging the consumer side of the queue within the WBC is preferred for two reasons:</p><ol start=\"1\"><li><p>its done much slower compared to the update - so we can log at 50Hz instead of 1000Hz</p></li><li><p>it happens AFTER any drops (overflows) in the queue, meaning we are recording exactly what the WBC is seeing rather than what it SHOULD be seeing - which is super useful for trouble-shooting edge-cases in the future.</p></li></ol><h3 id=\"ErectingtheMonolith-Testing\"><strong>Testing</strong></h3><p>By far the biggest win here comes with testing.  With a ROS node, testing logic can be difficult due to the interaction and timing of the various subscriber threads and callbacks.  You can \u201cspin\u201d the node manually, but this really fights against what ROS is trying to abstract by even introducing the executors and callbacks in the first place.</p><p>Consider testing the WBC.  We have some JointStates, and we want to make sure that the WBC\u2019s internal state updates correctly.  With ROS, we\u2019d have to spin up some sort of mock environment or a real ROS runtime and publish our JointStates so that we can execute the subscriber callback logic.  All the while, our WBC is firing at some other rate (nominally 50Hz) in this example.  Does this mean we are limited to testing our node in real-time only?  Or perhaps we drive the WBC loops from only the subscriber callback of the JointStates (calling some internal \u201cupdate\u201d every 20ms).  This is a lot of complexity and overhead for the task at hand.</p><p>Instead we can simply assume our WBC has some update function that takes a vector of time-stamped joint states.  We should be able to take our test data, and feed it in 20 items at a time, and assert on the state produced after each update.  No need to reason about callbacks, synchronization, topics, test publishers - just call the logic in a loop.  These tests are much faster (can be run faster than real-time)</p><p><strong>Explicit Goal: Synchronous, functional components.  </strong>Give inputs, assert on outputs.</p><h3 id=\"ErectingtheMonolith-Agents\"><strong>Agents</strong></h3><p>We should begin giving more consideration about how we are organizing our software for the benefit of AI coding agents like Claude Code or OpenAI\u2019s Codex.  In a ROS system with many nodes, callbacks, topics it will be difficult for the agent to have enough context to meaningfully contribute, as so much of the behavior of the system can only be inferred by looking at the whole thing.  For example, looking at just the WBC ROS node (in this contrived example above), it would be impossible to know that the joint state subscriber callback would be firing at 1000Hz without also having full context of the joint controller and its configured rates.</p><p>The good news is that organizing code for agents ALSO makes it easier for humans to understand, and also makes it easier to support testing and such due to solid abstractions and module boundaries.</p><p><strong>Explicit Goal: Flat structure.  Modular.  Local-Context.  </strong>Easy to reason about the part separately from the whole.<strong> </strong></p><h3 id=\"ErectingtheMonolith-Configuration\">Configuration</h3><p>Another challenge we need to overcome is tracking and managing configuration.  ROS typically organizes configuration in a way that makes sense for the ROS graph, but generally makes things very difficult for the organization as a whole.  Consider the problem of training pipelines:</p><p>We will have many robots operating across different platforms and many different software versions.  How do we trace these changes back to the data pipeline?  We can version the code of course with a single commit (already in progress<a href=\"https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1005027354/Integration+and+the+Monorepo?atlOrigin=eyJpIjoiNzk4YTkxNzY3OWY1NDllYjkxMmU3NDQ4OGIwN2MyYjEiLCJwIjoiYyJ9\" data-card-appearance=\"inline\" rel=\"nofollow\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1005027354/Integration+and+the+Monorepo?atlOrigin=eyJpIjoiNzk4YTkxNzY3OWY1NDllYjkxMmU3NDQ4OGIwN2MyYjEiLCJwIjoiYyJ9</a> ) and this is necessary, but not sufficient.  What about \u201cextra\u201d parameters coming from configuration management?  What about overrides provided on the command line?  We should expect there to be configuration changes outside of version control for things like A/B testing and experimentation.</p><p>In this case, having a soup of YAML files, launch files and XML files spread across many nodes is very difficult to check.  ROS also introduces \u201cdynamic reconfiguration\u201d which allows parameters to be changed at runtime - we should generally just forbid this.  We should strive to have a relatively unified configuration architecture across all platforms which, together with the versioned code, perfectly captures the behavior of the robot.</p><p>With a more monolithic approach (fewer ROS nodes), this means having some per-platform URDF (static, version-controlled), some HAL-related configuration (static, per hardware environment like mocks, simulation, real hardware), some configuration params (all the various parameters in the system which we want to control outside of code) and overrides.  At runtime, we should be able to render this into a single consistent view which can be archived during data collection.</p><p><strong>Explicit Goal: Unified, data-driven configuration parameters.  </strong>Easy to trace configuration differences even with same software version.</p><h2 id=\"ErectingtheMonolith-ConceptofaPlan\">Concept of a Plan</h2><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250808-102616.png\" width=\"318\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1028981407/image-20250808-102616.png?version=1&amp;modificationDate=1754648778085&amp;cacheVersion=1&amp;api=v2&amp;width=318&amp;height=159\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1028981407/image-20250808-102616.png?version=1&amp;modificationDate=1754648778085&amp;cacheVersion=1&amp;api=v2\" data-height=\"159\" data-width=\"318\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1030488323\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250808-102616.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1028981407\" data-linked-resource-container-version=\"3\" data-media-id=\"78a4ea15-14e4-4146-8e70-e8c671885ee5\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1028981407/image-20250808-102616.png?version=1&amp;modificationDate=1754648778085&amp;cacheVersion=1&amp;api=v2&amp;width=318&amp;height=159 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1028981407/image-20250808-102616.png?version=1&amp;modificationDate=1754648778085&amp;cacheVersion=1&amp;api=v2&amp;width=318&amp;height=159 1x\"></span><p><strong>Phase 1:  Consolidation and Organization</strong></p><p>Both Alpha and the PreAlpha system have a number of launch files in the monorepo which can boot up nodes for controllers, perception, or policy execution.  The more nodes we have, the more junk we have between them.  If we reduce the number of nodes, we reduce the complexity of trying to coordinate them.  Think of it as reducing the ratio of surface area to volume.</p><p>Things that are PreAlpha-specific, should be marked as such and eliminated from the Alpha stack.  Superfluous nodes and configurations should be removed.  Code and config related to low-level control should be \u201cclose\u201d together in the repository but distinct fr<span class=\"inline-comment-marker\" data-ref=\"49b77ad1-7203-4eb0-9965-4fd9648fd420\">om code related to actuator control drivers or WBC.</span></p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"fe34bff2-a76d-4053-9b6a-da965ab0503d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">ros/\n    control/\n        actuator_control/\n            ethercat\n            mocks\n            issac\n        joint_control/\n            impedance\n            admittance\n        whole_body_control/\n            wbc_solver\n            &quot;stray&quot; controllers (left arm, right arm, head, torso, etc)\n    platforms/\n        alpha/\n            alpha_configuration</pre>\n</div></div><p><span class=\"inline-comment-marker\" data-ref=\"bff97aac-9c59-4196-89fb-93e450fbe3be\">This is a slight simplification, but the main idea is that even within ROS, we should be able to organize things to reflect the sort of organization we want to see longer-term, and we should begin better separating code from configuration.  More specifically, the joint controllers and WBC ought to be separate from the configuration which is going to be more platform-specific.</span></p><p>We should also consider renaming/organizing some of our existing core/ functionality too.  For instance, hmndlib_pinocchio is more than just a pinocchio wrapper \u2013 its basically the beginnings of our core WBC (with pinocchio just being one of many possible dependencies used to solve some of the rigid body dynamics needed in a WBC solution). </p><p>The primary result of this phase is less ROS to deal with and slightly better organization to help us reason about the next steps.</p><p><strong>Phase 2: Isolation and Separation</strong></p><p>We should be able to start separating our core functionality from the ros2_control framework and internals at this point, resulting in much more testable and understandable code.  </p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"115b83e1-9fc7-4849-9761-54ea94e5b14d\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">ros/\n    control/\n        ROS-specific controller stuff\n    platforms/\n        alpha/\n            alpha_configuration\n\ncore/\n    hmndlib_hal/\n        actuator_control/\n            ethercat\n            mocks\n            issac\n\n    hmndlib_control/\n        joint_control/\n            impedance\n            admittance\n        whole_body_control/\n            wbc_controller </pre>\n</div></div><p>The main shift here is that instead of having the core logic embedded into ROS nodes and controllers (and all the problems from above), we have isolated the core functionality into more functional (input \u2192 output) modules under the core/ folder - free of any ROS-related messaging or threading.</p><p>For example, you should be able to instantiate an ImpedanceJointController with some parameters, and then update it synchronously within a test.  Even better, this core interface should be wrapped w/ Python bindings so we can test w/ pytest and along with performing analysis with Python tooling like notebooks.  If we need to keep the ros2_control framework around a bit longer, it should simply wrap the core function.  Then we can at least be sure that our core implementations have test coverage (though we ideally have SOME end-to-end coverage over ROS as well to sanity check the integration into the framework).</p><p><strong>Phase 3: Collapsing the Graph</strong></p><p>At this point we should have some core (non-ROS) functionality for actuator control, joint control and whole-body control, along with a means for configuring them and booting them within ROS.  We should have test coverage for our individual core pieces and hopefully some sort of end-to-end integration test (perhaps some sort of simulation) for the stack as a whole.</p><p>It should be fairly obvious that we should be able to simply connect the basic functionality directly together, without any middleware or frameworks at all.</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"a19289e2-3566-4453-a8a3-97823598dbc3\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: py; gutter: false; theme: Confluence\" data-theme=\"Confluence\">from hmndlib_common import RingBuffer\nfrom hmndlib_hal import EthercatActuatorDriver          # has .poll() -&gt; ActuatorState, .send(cmd)\nfrom hmndlib_control import ImpedanceJointController    # .update(traj?, state) -&gt; (JointState, ActuatorCommand)\nfrom hmndlib_control import WholeBodyController         # .update(task?, joint) -&gt; (TaskState, JointTrajectory)\nfrom hmndlib_control import ActuatorState, ActuatorCommand\nfrom hmndlib_control import JointState, JointTrajectory\nfrom hmndlib_control import TaskState, TaskCommand\n\njoint_states  = RingBuffer(100)         # joint ctrl -&gt; WBC\njoint_trajectories  = RingBuffer(100)   # WBC -&gt; joint ctrl\ntask_commands = RingBuffer(10)          # upstream app -&gt; WBC\ntask_states = RingBuffer(10)            # WBC -&gt; downstream app\n\ndriver   = EthercatActuatorDriver()\njointctl = ImpedanceJointController()\nwbc      = WholeBodyController()\n\n# just for illustration - running a 1KHz control loop in python is... not okay\n\ndef joint_loop(period_s: float = 0.001):\n    next_t = time.perf_counter()\n    while True:\n        traj = join_trajectories.pop_latest()\n        act_state = driver.poll()\n        # underflow logic here\n\n        # our core joint controller update\n        js, act_cmd = jointctl.update(traj, act_state)\n\n        # overflow logic here\n        joint_states.push(js)\n        driver.send(act_cmd)\n\n        next_t += period_s\n        time.sleep(max(0, next_t - time.perf_counter()))\n\n\ndef wbc_loop(period_s: float = 0.02):\n    next_t = time.perf_counter()\n    while True:\n        task_cmd = task_commands.pop_latest()\n        js = joint_states.pop_latest()\n        # underflow logic here\n\n        # our core WBC update\n        task_state, traj = wbc.update(task_cmd, js)\n\n        # overflow logic here\n        task_states.push(task_state)\n        joint_trajectories.push(traj)\n\n        next_t += period_s\n        time.sleep(max(0, next_t - time.perf_counter()))\n\n\nif __name__ == &quot;__main__&quot;:\n    threading.Thread(target=joint_loop, daemon=True).start()\n    threading.Thread(target=wbc_loop,   daemon=True).start()\n\n    while True:\n        time.sleep(1)  # main thread parked for this example</pre>\n</div></div><p>This is of course a simplified example, and we are taking some significant liberties by mixing the loops in this way.  But this does show roughly how we can re-compose our individual core building blocks without ROS.  Of course, we could still publish all of the data from these queues, but this isn\u2019t demonstrated above.</p><p>In the example above, the layer writing TaskCommands to the queue could be our trained policy or it could be some teleoperation app.  </p><h2 id=\"ErectingtheMonolith-Appendix/RandomShit\">Appendix/Random Shit</h2><p><strong>TF Nonsense </strong></p><p>The ROS2 joint controller accepts joint trajectories at a rate significantly slower than the joint controller itself runs, and reports JointStates at 1000Hz.   The robot_state_publisher will subscribe to these JointState messages and publish transforms for all the joints so that other parts of the system can convert between the various coordinate frames.   This is where a lot of the complexity of the ROS solution comes into play - we have 14 DoF in the arms alone being updated at 1Khz - this is 14,000 updates per second to the robot_state_publisher callback internally which then get broadcast (I think at 20Hz) so that all so that other nodes (via TransformListener) can reconstruct the state that already exists inside the WBC.</p><p>This is so dumb, and a perfect example of why smashing a robot into a distributed system is a bad idea.  Why would we re-compute the forward kinematics AGAIN outside of our controller, with lower-resolution data?  Why would we worry about the realtime clock and bag replay issues while doing this?</p><p>If we were in the same process, we could simply \u201cask\u201d the <span class=\"inline-comment-marker\" data-ref=\"7438154c-cf7e-4d6e-a34b-a6a031ed4bd0\">WBC to transform coordinates for us, since it already has all this information (and much more).</span>  The rate of these queries will be far lower than the rate of updates necessary attempting to keep TF state clean across TransformListeners and multiple processes.</p><p />"
        },
        {
          "id": "1027899618",
          "title": "MacOS Linux Development - Lima + VSCode Remote SSH",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1027899618",
          "last_modified": "2025-08-06T14:30:04.993Z",
          "created_at": "2025-08-06T14:04:24.838Z",
          "body_html": "<p>This guide lets you use <a href=\"https://github.com/lima-vm/lima\" class=\"external-link\" rel=\"nofollow\">Lima</a> + VSCode\u2019s \u201cRemote - SSH\u201d extension to treat an x86_64 or ARM64 VM like a remote dev machine. Clean, fast, reproducible builds. No Docker hell.</p><h2 id=\"MacOSLinuxDevelopment-Lima+VSCodeRemoteSSH-Why\">Why</h2><ul><li><p>Isolated, reproducible build envs.</p></li><li><p>Works with VSCode like it\u2019s a remote machine.</p></li><li><p>Use your normal editor, not weird container shells.</p></li></ul><h2 id=\"MacOSLinuxDevelopment-Lima+VSCodeRemoteSSH-\ud83d\udee0\ufe0fPrereqs\">\ud83d\udee0\ufe0f Prereqs</h2><p>Install:</p><ul><li><p><code>limactl</code></p></li><li><p>VSCode</p><ul><li><p>VSCode extension: <strong>Remote - SSH</strong></p></li></ul></li></ul><h2 id=\"MacOSLinuxDevelopment-Lima+VSCodeRemoteSSH-LimaSetup\">Lima Setup</h2><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"3d2acbd4-9749-470f-a1da-5462494fe204\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\"># install lima\nbrew install lima\n\n# create VM\nlimactl create --name ubuntu-arm64 --arch aarch64 --cpus 8 --memory 16 --disk 100 --vm-type vz --rosetta --mount-writable template://ubuntu\n\n# start VM\nlimactl start ubuntu-arm64\n\n# get a shell\nlimactl shell ubuntu-arm64  </pre>\n</div></div><p>Now you have a reasonably fast/performance Linux system on your Mac.</p><h2 id=\"MacOSLinuxDevelopment-Lima+VSCodeRemoteSSH-SSHSetup\">SSH Setup </h2><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"1bccba0c-c207-488a-9208-d31a1327a4f7\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">cat ~/.lima/ubuntu-arm64/ssh.config\nHost lima-ubuntu-arm64\n  &lt;contents dumped here&gt;</pre>\n</div></div><p>\u201cSplice\u201d the contents of this file into your <code>~/.ssh/config</code> so that you can SSH to your Lima VM with:</p><div class=\"code panel pdl conf-macro output-block\" style=\"border-width: 1px;\" data-hasbody=\"true\" data-macro-name=\"code\" data-macro-id=\"8d81e2cd-827c-4c4f-97b5-5a53e9c5560a\"><div class=\"codeContent panelContent pdl\">\n<pre class=\"syntaxhighlighter-pre\" data-syntaxhighlighter-params=\"brush: python; gutter: false; theme: Confluence\" data-theme=\"Confluence\">ssh lima-ubuntu-arm64</pre>\n</div></div><p>Then from VSCode:</p><ol start=\"1\"><li><p><code>Cmd+Shift+P</code> \u2192 <code>Remote-SSH: Connect to Host...</code></p></li><li><p>Select <code>lima-ubuntu-arm64</code></p></li></ol><p>Done. You\u2019re in.</p>"
        },
        {
          "id": "1027506232",
          "title": "Bushwhacking Software",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1027506232",
          "last_modified": "2025-08-06T09:17:39.727Z",
          "created_at": "2025-08-06T08:45:01.786Z",
          "body_html": "<p>Planning software projects is hard.  Really really hard.  Typical project plans attempt to break down some large deliverable into pieces, organize those pieces on a timeline, assign resources and probably also divide time into large-scale phases.  In reality, software development requires doing all of these things concurrently, constantly.  There is no line between development and testing.  There is no line between development and integration.   Planning activities for software shouldn\u2019t focus on timelines or work breakdowns as much as they should seek to clarify goals, ownership and define feedback.</p><h3 id=\"BushwhackingSoftware-Hardwarevs.Software\">Hardware vs. Software</h3><p>Hardware development is traditionally expensive, slow, and physically constrained. You have limited shots, each cycle costs real money, and you have real-world constraints - gravity, thermals, friction, EMI, supply chains - all providing neat boundaries. Sure, there\u2019s complexity, but it\u2019s a bounded complexity. Each iteration can take weeks or months and has <em>significant</em> material costs. Because of this, extensive planning, careful requirements gathering, and rigorous V-model methodologies really do help reduce your risk.</p><p>Software is fundamentally different. It has no such guardrails, no material costs to speak of (ignoring training costs), and iteration speed can be made arbitrarily fast. Without the constraints of physics, complexity grows combinatorially.  Threads, shared memory, distributed systems, configuration - it's an explosion of dimensionality. You can't realistically predict every interaction or failure mode ahead of time. It\u2019s pure chaos, unbounded.</p><p>In short:</p><ul><li><p><strong>Hardware:</strong> Iterations are expensive and necessarily slower \u2192 Planning pays off.</p></li><li><p><strong>Software:</strong> Iterations are cheap and can be faster \u2192 Planning yields diminishing returns quickly.</p></li></ul><p>Planning is the best way to mitigate hardware development risks.  Fast iteration is the best way to mitigate software development risks. </p><h3 id=\"BushwhackingSoftware-PlanningisGood-UptoaPoint\">Planning is Good - Up to a Point</h3><p>Planning is still valuable in software, but its primary role is to clarify goals and expectations, not to micromanage every implementation detail. If your software plans look like hardware plans, you\u2019ve probably gone too far. At some point, you're just fooling yourself into thinking complexity can be perfectly predicted and managed upfront - it just can\u2019t.</p><p>Instead, your plan should focus on three things:</p><ol start=\"1\"><li><p><strong>Clearly defined goals </strong>- what are we doing?<strong> </strong></p></li><li><p><strong>Well-structured, rapid feedback loops </strong>- how do we know we are succeeding at the goal?</p></li><li><p><strong>Ownership </strong>- who is accountable for the goal?</p></li></ol><p>If your team knows what the software is supposed to achieve (goal clarity), and you have solid feedback mechanisms (data, metrics, observable results), you have everything you need. Excessive upfront specification - trying to capture every requirement before iteration - just wastes time, creating a false sense of certainty.</p><p>Its also important to consider staffing of course.  How can you reason about how many engineers should be working toward a goal?  During planning activities, owners should be assigned to goals and these owners are responsible for end-to-end progress toward the goal and the resulting feedback signals.  This is less of an exercise of breaking down work items and assigning to individuals on a timeline, and more about giving owners the authority and accountability to delegate and rapidly adjusting priorities within the team.  There will never be enough staff to do 100% of what we want to do, and so this is a constant negotiation as priorities shift and new lessons are learned over time.</p><h3 id=\"BushwhackingSoftware-SolvingAnalyticallyvsNumerically\">Solving Analytically vs Numerically</h3><p><span class=\"inline-comment-marker\" data-ref=\"44da753e-82ce-4c19-a8e4-89460f3ee681\">Think of it like inverse kinematics:</span></p><p>For a simple, planar two-joint arm, sure, you can easily solve analytically. You have clear constraints, no redundancy, and an obvious solution.   Now consider a full-body humanoid robot with 40-some redundant joints. The analytical approach is madness - you\u2019d waste years just formulating the problem, and for what? Infinite solutions exist. You instead solve <em>numerically</em>. You pick a small timestep (fast iteration), clear constraints (goals), and use strong gradients (feedback from reality) to quickly converge on a workable solution.</p><p>Software is exactly this: a hyper-redundant , high degree-of-freedom system with infinite possible solutions. You don\u2019t win by meticulously planning every motion; you win by iterating faster and better than your competition.</p><h3 id=\"BushwhackingSoftware-Summary\">Summary</h3><p>Planning isn't useless - it\u2019s just limited. Do just enough to define your goals clearly and set up strong, fast feedback loops. Then get out of your team's way and let them iterate rapidly. They\u2019ll reach the right solution faster, and the solutions they find will be more robust precisely because they're grounded in real data rather than brittle, outdated assumptions.</p><p>Plan just enough to frame the problem - then iterate as fast as humanly possible.</p><p />"
        },
        {
          "id": "1020264502",
          "title": "Whole Body Control for Dummies",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1020264502",
          "last_modified": "2025-08-05T09:45:23.097Z",
          "created_at": "2025-08-01T15:07:13.822Z",
          "body_html": "<p>In part 1 (<a href=\"https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1017905442/Actuator+Control+for+Dummies?atlOrigin=eyJpIjoiOWNmZTY4MzM1YzJiNGQ4NTg0NWY5ZmVlNzc5NDA2MDAiLCJwIjoiYyJ9\" data-card-appearance=\"inline\" rel=\"nofollow\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1017905442/Actuator+Control+for+Dummies?atlOrigin=eyJpIjoiOWNmZTY4MzM1YzJiNGQ4NTg0NWY5ZmVlNzc5NDA2MDAiLCJwIjoiYyJ9</a>), we looked at how standard actuators are controlled.  In part 2 (<a href=\"https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1019543565/Joint+Control+for+Dummies?atlOrigin=eyJpIjoiYWUzMmQwOWI3NGNlNGZmNWIyZDRlZGRmNTQ3MzU4YzAiLCJwIjoiYyJ9\" data-card-appearance=\"inline\" rel=\"nofollow\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1019543565/Joint+Control+for+Dummies?atlOrigin=eyJpIjoiYWUzMmQwOWI3NGNlNGZmNWIyZDRlZGRmNTQ3MzU4YzAiLCJwIjoiYyJ9</a>), we look at how we can better control not just the actuator, but the interactions the actuator has with its environment.  Here in part 3 we will look at how we can control many joints simultaneously in order to achieve specific tasks while maintaining a prioritized list of constraints.</p><h1 id=\"WholeBodyControlforDummies-ForwardKinematics\">Forward Kinematics</h1><p>Once we start arranging joints in a chain, interesting things start to happen.  In addition to the Coriolis effects we need to compensate for in impedance control, we need to also propagate reference frames up the chain in order to compute where the end effector (usually the end of the chain) will be located.</p><p>Let\u2019s consider a simple 2D robot arm where we have a shoulder and elbow, with the end effector being at the point of the wrist (though no articulation here).</p><span class=\"confluence-embedded-file-wrapper image-left-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image confluence-external-resource image-left\" width=\"735\" src=\"https://sklvc.atlassian.net/wiki/download/attachments/1020264502/Untitled%20Diagram-1754061178160.drawio.png?api=v2&amp;version=1\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1020264502/Untitled%20Diagram-1754061178160.drawio.png?api=v2&amp;version=1\" loading=\"lazy\"></span><p>We won\u2019t be digging too far into the math here, but the rough shape of the challenge with robotics is given some robot configuration (the lengths of the links L<sub>1</sub> and L<sub>2</sub>) and the angles of the joints (the red dots with angles <strong>\u03b8</strong><sub>1</sub> and <strong>\u03b8</strong><sub>2</sub>), how do we compute where the end effector at the end of the arm will be located with respect to our base coordinate system?</p><p>The basic strategy is that we treat this as a chain of transformations.  The rotation <strong>\u03b8</strong><sub>1</sub> and translation L<sub>1</sub> allow us to place the location of the second joint with respect to the first joint.  Then the rotation <strong>\u03b8</strong><sub>2</sub> and L<sub>2</sub> allow us to do the same for the end effector with respect to the location of the second joint.  To get the position of the end effector with respect to our base coordinate system, we just need to apply these transformations one after the other.  Obviously this gets a bit more complex once we have 7DoF, differential joints and end effector orientations to worry about, but the basic math is just a chain of transformations.</p><h1 id=\"WholeBodyControlforDummies-InverseKinematics\">Inverse Kinematics</h1><p>Forward kinematics is useful, but the real magic starts when you consider the inverse problem: given some desired end effector location, what joint angles do we need?  This is unfortunately a much more difficult to problem to solve, as there usually isn\u2019t a clean analytical solution for this.</p><p>The location of our end effector is what we would refer to as our <strong>task space</strong> and in this example above it has 2 degrees of freedom (x and y).  The configuration of the angles is referred to as our <strong>joint space </strong>and also has 2 degrees of freedom (<strong>\u03b8</strong><sub>1</sub> and <strong>\u03b8</strong><sub>2</sub>).  In this example, the degrees of freedom of the joint space and the task space are the same, meaning that the robot isn\u2019t \u201credundant\u201d (though there may be multiple solutions to the IK problem such as \u201celbow-up\u201d or \u201celbow-down\u201d.  This sorta like solving a quadratic equation and choosing which of the two solutions to use.</p><p>If we have more degrees of freedom in our joint space than our task space (such as adding another link in the arm above), our system becomes redundant and there are now an infinite number of solutions to the IK problem.  At this point analytical approaches break down entirely and we must use solvers or optimizers.  A major challenge here is solving the IK solution for each time-step while ensuring motion remains smooth and continuous.</p><p>We also need to worry about singularities - solutions where the robot loses degrees of freedom.  In the double-linkage arm above, if the arm is fully extended or fully-collapsed, the links become co-linear and so we lose a degree of freedom.  This can cause major challenges when planning trajectories, and so usually we need to do a lot of trickery to avoid singularities.</p><h1 id=\"WholeBodyControlforDummies-NullSpace\">Null Space</h1><p>When we have redundancy, things get much more fun.  Redundancy is what allows you to keep your elbows out of the way when trying to use a screwdriver in a tight-space, or why you don\u2019t tip over when you try to pick a sock up off the floor.  You effectively operate within two spaces: what is the task you are trying to solve, and what \u201cother\u201d degrees of freedom do you have to avoid any nasty side-effects like tipping over or smacking your elbows.</p><p>When we introduce redundancy, we can \u201cfix\u201d the end effector (the thing we are trying to move to accomplish some specific task) which then gives us some <strong>null space</strong> which is a continuous manifold of \u201cother shit\u201d we can do without impacting the actual task.  Hold your handout in front of you on the wall, and then move your whole body around while keeping your hand fixed: that\u2019s your null space for that task.</p><h1 id=\"WholeBodyControlforDummies-WholeBodyControl\">Whole Body Control</h1><p>So our robot needs to move its arms in front to pick an object up.   This represents about 12 degrees of freedom (position + orientation of 2 end effectors in 3d space).  The robot also has degrees of freedom in the base, the bendy leg/legs and some extra in the arm to create a pretty complicated null space where we can optimize for some secondary or tertiary tasks.</p><p>In the most simple and crude terms, whole-body control allows the robot to prioritize these tasks and plan within the null space of each one until we use all our degrees of freedom (or run out of tasks).  A biped for example may try to control where its center of mass lies on the ground to maintain balance.  This only requires a few degrees of freedom, leaving significant amounts left for the task to be solved.  There may also be tasks related to maintaining constraints (both arms picking up some rigid object), optimizing joints (keeping them from limits or distributing torques over more joints) or optimizing manipulability (ensuring that the robot doesn\u2019t maneuver near singularities).</p>"
        },
        {
          "id": "1022394482",
          "title": "Welcome to the Jungle",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1022394482",
          "last_modified": "2025-08-04T12:17:26.957Z",
          "created_at": "2025-08-04T09:57:39.166Z",
          "body_html": "<p>Sure, testing proves your code actually works.  Functional correctness, requirements coverage - blah, blah, we've heard it before.  But in a monorepo shared by dozens developers, your tests aren\u2019t just correctness checks.  They are your way of communicating expectations and guarding your code against well-meaning but clueless invaders. </p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250804-121602.png\" width=\"259\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1022394482/image-20250804-121602.png?version=1&amp;modificationDate=1754309764306&amp;cacheVersion=1&amp;api=v2&amp;width=259&amp;height=194\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1022394482/image-20250804-121602.png?version=1&amp;modificationDate=1754309764306&amp;cacheVersion=1&amp;api=v2\" data-height=\"194\" data-width=\"259\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1022591112\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250804-121602.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1022394482\" data-linked-resource-container-version=\"1\" data-media-id=\"e60b9de1-8a90-4e63-8670-3d49c297ca36\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1022394482/image-20250804-121602.png?version=1&amp;modificationDate=1754309764306&amp;cacheVersion=1&amp;api=v2&amp;width=259&amp;height=194 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1022394482/image-20250804-121602.png?version=1&amp;modificationDate=1754309764306&amp;cacheVersion=1&amp;api=v2&amp;width=259&amp;height=194 1x\"></span><h2 id=\"WelcometotheJungle-TestingasCommunication\">Testing as Communication</h2><p>Let\u2019s reframe testing for a second.  In a monorepo:</p><ul><li><p>Tests aren't just checks - they're <strong>communication channels</strong>.</p></li><li><p>Tests show your teammates (clearly, loudly, sometimes aggressively) how your code expects to be treated.</p></li><li><p>Tests document the assumptions you made about inputs, outputs, and behavior, making your implicit expectations explicit.</p></li></ul><p>In other words, testing is your defense against someone else\u2019s bad day becoming your bad day.</p><h2 id=\"WelcometotheJungle-WriteTestsasifYou\u2019reTalkingtoYourTeammates\">Write Tests as if You\u2019re Talking to Your Teammates</h2><p>When writing tests, think about your fellow developers:</p><ul><li><p><strong>Readable tests</strong>: If someone new lands in your module, your tests should scream, \u201cHey! Here\u2019s exactly how this thing is supposed to behave:\u201d</p></li><li><p><strong>Explicit assertions</strong>: Leave no room for guesswork.  Every test is a strong opinion about your component\u2019s behavior.</p></li><li><p><strong>Obvious failure modes</strong>: If your test fails, it shouldn\u2019t whisper - it should loudly and clearly point to exactly what's wrong or what assumptions have been violated.</p></li></ul><p>Your tests are part of your module\u2019s API.  Write them like a good README: opinionated, concise, and impossible to misinterpret.</p><h2 id=\"WelcometotheJungle-ProtectYourTurf-ContinuousTestingandCI\">Protect Your Turf - Continuous Testing and CI</h2><p>The moment you merge your code, it enters the jungle. Other developers, rushing towards deadlines, might unknowingly stomp through your delicate assumptions. Your testing strategy should:</p><ul><li><p>Be integrated into the CI pipeline - run tests early and often.</p></li><li><p>Leverage incremental test execution - only run the tests that are impacted by code changes (because no one has time for full runs every commit).</p></li><li><p>Fail loudly and immediately - make sure breakages get attention fast.</p></li></ul><p>If someone breaks your shit, make sure everyone knows it quickly.</p><h2 id=\"WelcometotheJungle-LayersofProtection:Unitvs.Integrationvs.SmokeTests\">Layers of Protection: Unit vs. Integration vs. Smoke Tests</h2><p>Each test type has a role to play:</p><p><strong>Unit </strong>- \u201cTouch this function incorrectly, and I will immediately complain.\u201d</p><p><strong>Integration </strong>- \u201cYou broke the communication between these components - fix your wiring!\u201d</p><p><strong>Smoke/Acceptance </strong>- <strong> </strong>\u201cIf this fails, something is seriously wrong - come fix it ASAP.\u201d</p><p>This layering isn\u2019t just about catching bugs - it\u2019s about clear communication to your teammates.  If an integration test fails, someone immediately knows they broke a contract.</p><h2 id=\"WelcometotheJungle-MaintainingSanityatScale\">Maintaining Sanity at Scale</h2><p>Monorepos can turn into chaos without clear testing strategies.  If tests are flaky, slow, or cryptic, people will stop respecting them.  Keep your tests:</p><ul><li><p>Fast enough to run frequently.</p></li><li><p>Reliable enough that they\u2019re trusted and provide high signal.</p></li><li><p>Clear enough to quickly pinpoint responsibility.</p></li></ul><p>If you don\u2019t trust your tests, neither will anyone else - a recipe for chaos.</p><p>Testing in a monorepo isn\u2019t so much about quality control as it is about survival.  Make your assumptions explicit, your expectations clear, and your defenses strong.</p><p>Welcome to the jungle.</p>"
        },
        {
          "id": "1007976535",
          "title": "Software",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1007976535",
          "last_modified": "2025-08-04T09:30:23.848Z",
          "created_at": "2025-07-25T15:54:36.728Z",
          "body_html": "<p>This is meant to be a dumping ground for all things software at Humanoid.  Specifically, I\u2019ll be trying to capture more general software guidance here, including things related to how we work, what we are doing and where we are going. </p><h2 id=\"Software-ReadingList\">Reading List</h2><p /><ul class=\"childpages-macro conf-macro output-block\" data-hasbody=\"false\" data-macro-name=\"children\" data-macro-id=\"6c304a22d41f215b29597d1586403463374934e0e3ef2ea973e79fd00adee909\" data-layout=\"default\" data-local-id=\"995fe135-91de-475a-9d5d-5bdb26c8d65c\"><li><a href=\"/wiki/spaces/ROBOT/pages/1005027354/Integration+and+the+Monorepo\" data-linked-resource-id=\"1005027354\" data-linked-resource-version=\"4\" data-linked-resource-type=\"page\">Integration and the Monorepo</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1004666903/Trunk-Based+Development\" data-linked-resource-id=\"1004666903\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Trunk-Based Development</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1004732467/Move+Fast+and+Merge+Things\" data-linked-resource-id=\"1004732467\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Move Fast and Merge Things</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1010335765/Robot+Middleware\" data-linked-resource-id=\"1010335765\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">\ud83e\udea4 Robot Middleware</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1022394482/Welcome+to+the+Jungle\" data-linked-resource-id=\"1022394482\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Welcome to the Jungle</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1027506232/Bushwhacking+Software\" data-linked-resource-id=\"1027506232\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Bushwhacking Software</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1529577477/Platform+Software\" data-linked-resource-id=\"1529577477\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">Platform Software</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1776386116/Immutable+Operating+Systems+Applications+Developer+Guide\" data-linked-resource-id=\"1776386116\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Immutable Operating Systems Applications Developer Guide</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1783889921/FAQ+-+Platform+Software\" data-linked-resource-id=\"1783889921\" data-linked-resource-version=\"6\" data-linked-resource-type=\"page\">FAQ - Platform Software</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1783889930/Platform+VM+Development\" data-linked-resource-id=\"1783889930\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Platform VM Development</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1833107496/What+Actually+Is+Jetson+Linux\" data-linked-resource-id=\"1833107496\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">What Actually Is &quot;Jetson Linux&quot;</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/folder/1019412488\" data-linked-resource-id=\"1019412488\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Control For Dummies</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1017905442/Actuator+Control+for+Dummies\" data-linked-resource-id=\"1017905442\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Actuator Control for Dummies</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1019543565/Joint+Control+for+Dummies\" data-linked-resource-id=\"1019543565\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Joint Control for Dummies</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1020264502/Whole+Body+Control+for+Dummies\" data-linked-resource-id=\"1020264502\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Whole Body Control for Dummies</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/folder/1027997845\" data-linked-resource-id=\"1027997845\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Guides</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1027899618/MacOS+Linux+Development+-+Lima+VSCode+Remote+SSH\" data-linked-resource-id=\"1027899618\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">MacOS Linux Development - Lima + VSCode Remote SSH</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1022918657/ROS+DDS+testing\" data-linked-resource-id=\"1022918657\" data-linked-resource-version=\"9\" data-linked-resource-type=\"page\">ROS DDS testing</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1018658840/Torso+Bendy-Leg+Hardware+Bringup+WIP\" data-linked-resource-id=\"1018658840\" data-linked-resource-version=\"11\" data-linked-resource-type=\"page\">Torso Bendy-Leg Hardware Bringup (WIP)</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1034649858/Implementing+a+new+PoC+Demo+or+Deployment\" data-linked-resource-id=\"1034649858\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Implementing a new PoC, Demo, or Deployment</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1134395462/Wireguard+hmnd-tunnel\" data-linked-resource-id=\"1134395462\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Wireguard: hmnd-tunnel</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1135345776/Sockpuppet+Teleoperation+Simplified\" data-linked-resource-id=\"1135345776\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">Sockpuppet: Teleoperation Simplified</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1161232387/Credentials+on+our+Robots\" data-linked-resource-id=\"1161232387\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">Credentials on our Robots</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1184759859/Using+our+UMI+Grippers\" data-linked-resource-id=\"1184759859\" data-linked-resource-version=\"4\" data-linked-resource-type=\"page\">Using our UMI Grippers</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1653407830/Robostore+Demo+Setup+Instructions+-+DEPRECATED\" data-linked-resource-id=\"1653407830\" data-linked-resource-version=\"28\" data-linked-resource-type=\"page\">Robostore Demo Setup Instructions - DEPRECATED</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1821671441/Robot+Observability\" data-linked-resource-id=\"1821671441\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Robot Observability</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1967685711/APPS+Symphony+2+Demo+Bringup\" data-linked-resource-id=\"1967685711\" data-linked-resource-version=\"19\" data-linked-resource-type=\"page\">APPS Symphony 2 Demo Bringup</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1039335426/How+To+Slack\" data-linked-resource-id=\"1039335426\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">How To Slack</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1264517154/Please+please+don+t+DM+me+personally\" data-linked-resource-id=\"1264517154\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">\ud83d\ude4f Please, please don\u2019t DM me personally! \ud83d\ude4f</a></li></ul></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/folder/1048641559\" data-linked-resource-id=\"1048641559\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Short-term Plans</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1048969226/Simplifying+Teleoperation\" data-linked-resource-id=\"1048969226\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Simplifying Teleoperation</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1048543355/Configuring+Robots\" data-linked-resource-id=\"1048543355\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Configuring Robots</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1037304324/Robot+Puppetry\" data-linked-resource-id=\"1037304324\" data-linked-resource-version=\"4\" data-linked-resource-type=\"page\">Robot Puppetry</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1343914056/Image+Boot+Process+Alpha\" data-linked-resource-id=\"1343914056\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">Image Boot Process (Alpha)</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1361674259/HMND+Console+Infrastructure\" data-linked-resource-id=\"1361674259\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">HMND Console Infrastructure</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1914470451/Build+Improvements+-+Removing+Colcon\" data-linked-resource-id=\"1914470451\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Build Improvements - Removing Colcon</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1929904147/hmnd-cloud+-+hmnd\" data-linked-resource-id=\"1929904147\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">hmnd-cloud -&gt; hmnd</a></li><li><a href=\"/wiki/spaces/ROBOT/folder/1033306503\" data-linked-resource-id=\"1033306503\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Long-term Plans</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1026130021/Building+Software\" data-linked-resource-id=\"1026130021\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Building Software</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1028981407/Erecting+the+Monolith\" data-linked-resource-id=\"1028981407\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Erecting the Monolith</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1037435391/Safe+Teleoperation\" data-linked-resource-id=\"1037435391\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Safe Teleoperation</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1052377106/Hardware+Abstraction\" data-linked-resource-id=\"1052377106\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Hardware Abstraction</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1823735863/Road+to+Pilot+Epic-Level+Plan\" data-linked-resource-id=\"1823735863\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Road to Pilot \u2014 Epic-Level Plan</a></li></ul></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1037926527/Overview+of+the+codebase\" data-linked-resource-id=\"1037926527\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Overview of the codebase</a></li><li><a href=\"/wiki/spaces/ROBOT/folder/1052442654\" data-linked-resource-id=\"1052442654\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Things That Should Be Under a Personal Space</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1051361456/The+Case+for+Two+Networks+on+Beta\" data-linked-resource-id=\"1051361456\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">The Case for Two Networks on Beta</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1052442642/The+Case+For+Some+Hard+Realtime\" data-linked-resource-id=\"1052442642\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">The Case For (Some) Hard Realtime</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1052508214/Wireless+Networking+Sucks\" data-linked-resource-id=\"1052508214\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Wireless Networking Sucks</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1069973507/Swinging+Big\" data-linked-resource-id=\"1069973507\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Swinging Big</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1071513687/The+Case+For+Vision\" data-linked-resource-id=\"1071513687\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">The Case For Vision</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1140654136/Making+Jira+Tolerable\" data-linked-resource-id=\"1140654136\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Making Jira Tolerable</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1154548100/Fleets\" data-linked-resource-id=\"1154548100\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Fleets</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1372160012/Robot+Mapping+and+Deployment\" data-linked-resource-id=\"1372160012\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Robot Mapping and Deployment</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1740079107/Workflow+Compilation+from+Map+Data+and+High+Level+Metadata\" data-linked-resource-id=\"1740079107\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Workflow Compilation from Map Data and High Level Metadata</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/whiteboard/1559855175\" data-linked-resource-id=\"1559855175\" data-linked-resource-version=\"1\" data-linked-resource-type=\"whiteboard\">Untitled whiteboard 2026-01-26</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1705705482/Thoughts+from+a+tour+in+the+Bosch+manufacturing+lines\" data-linked-resource-id=\"1705705482\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Thoughts from a tour in the Bosch manufacturing lines</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1733066757/Symphony+Phase+2+Brain+Dump\" data-linked-resource-id=\"1733066757\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">Symphony Phase 2 Brain Dump</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1793425450/The+Problem+With+Central+Planning\" data-linked-resource-id=\"1793425450\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">The Problem With Central Planning</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1968111692/Capability+Planning\" data-linked-resource-id=\"1968111692\" data-linked-resource-version=\"10\" data-linked-resource-type=\"page\">Capability Planning</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/folder/1073545275\" data-linked-resource-id=\"1073545275\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Ethernet for Robots</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1073020986/Start+here+Why+Use+Ethernet\" data-linked-resource-id=\"1073020986\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Start here: Why Use Ethernet</a></li><li><a href=\"/wiki/spaces/ROBOT/folder/1092550718\" data-linked-resource-id=\"1092550718\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Elevator Pitch</a></li><li><a href=\"/wiki/spaces/ROBOT/folder/1092517944\" data-linked-resource-id=\"1092517944\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Performance and Functional Validation</a></li><li><a href=\"/wiki/spaces/ROBOT/folder/1092517945\" data-linked-resource-id=\"1092517945\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Hardware Requirements</a></li><li><a href=\"/wiki/spaces/ROBOT/folder/1093402660\" data-linked-resource-id=\"1093402660\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Protocol Design</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1097564196/Beta+Ethernet+Node+Proposal\" data-linked-resource-id=\"1097564196\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">Beta Ethernet Node Proposal</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/whiteboard/1100185607\" data-linked-resource-id=\"1100185607\" data-linked-resource-version=\"5\" data-linked-resource-type=\"whiteboard\">Untitled whiteboard 2025-09-13</a></li></ul></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/folder/1152516123\" data-linked-resource-id=\"1152516123\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Specs</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1151303693/Spec+HMND+Core+Control+Plane\" data-linked-resource-id=\"1151303693\" data-linked-resource-version=\"8\" data-linked-resource-type=\"page\">Spec: HMND Core Control Plane</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1636925456/Control+Plane+PKI+and+Secrets\" data-linked-resource-id=\"1636925456\" data-linked-resource-version=\"4\" data-linked-resource-type=\"page\">Control Plane PKI and Secrets</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1637417000/AI+Proxy\" data-linked-resource-id=\"1637417000\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">AI Proxy</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1636827169/SSH+Bastion\" data-linked-resource-id=\"1636827169\" data-linked-resource-version=\"6\" data-linked-resource-type=\"page\">SSH Bastion</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1672478731/Observability+Stack+Grafana+Loki+Tempo+Mimir\" data-linked-resource-id=\"1672478731\" data-linked-resource-version=\"4\" data-linked-resource-type=\"page\">Observability Stack (Grafana/Loki/Tempo/Mimir)</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1670250545/Spec+Push-Based+Operational+Metrics+for+Devices+aka+Edge+Inference\" data-linked-resource-id=\"1670250545\" data-linked-resource-version=\"20\" data-linked-resource-type=\"page\">Spec: Push-Based Operational Metrics for Devices (aka Edge Inference)</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1846870017/Backbone+OTA\" data-linked-resource-id=\"1846870017\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Backbone OTA</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1998553090/Upcoming+OTA+API+Contract\" data-linked-resource-id=\"1998553090\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Upcoming OTA \u2014 API Contract</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2086699063/OTA+User+Guide\" data-linked-resource-id=\"2086699063\" data-linked-resource-version=\"11\" data-linked-resource-type=\"page\">OTA User Guide</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1963851838/Spec+Nexus+Cloud+Control+Plane+Sandbox+Capability\" data-linked-resource-id=\"1963851838\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">Spec: Nexus Cloud Control Plane: Sandbox Capability</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1964048510/Nexus+Sandbox+Implementation+Notes\" data-linked-resource-id=\"1964048510\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Nexus Sandbox Implementation Notes</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1963819106/Nexus+Sandbox+Ops+Validation\" data-linked-resource-id=\"1963819106\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Nexus Sandbox Ops &amp; Validation</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1964310609/Nexus+Sandbox+Cost+Estimate\" data-linked-resource-id=\"1964310609\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Nexus Sandbox Cost Estimate</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1981972550/Spec+Signer+Service\" data-linked-resource-id=\"1981972550\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Signer Service</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2165211158/Research+Plan+Delta+Image+Updates+for+Robot+OS\" data-linked-resource-id=\"2165211158\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Research Plan: Delta Image Updates for Robot OS</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/2227601435/Result+Deterministic+OS+Image+Builds+Tier-1+Before+After\" data-linked-resource-id=\"2227601435\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Result: Deterministic OS Image Builds \u2014 Tier-1 Before/After</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2236186627/Design+hmndimg+v2+Direct-Install+Format+dm-linear+fixed+offsets\" data-linked-resource-id=\"2236186627\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Design: hmndimg v2 Direct-Install Format (dm-linear + fixed offsets)</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2236219394/Decision+Delta+Transport+Needs+No+Image-Format+Change+casync-range-v1\" data-linked-resource-id=\"2236219394\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Decision: Delta Transport Needs No Image-Format Change (casync-range-v1)</a></li></ul></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1170341889/Spec+HMND+Fleet+Control+Plane\" data-linked-resource-id=\"1170341889\" data-linked-resource-version=\"16\" data-linked-resource-type=\"page\">Spec: HMND Fleet Control Plane</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1619853323/Spec+Switchboard+Coordinator\" data-linked-resource-id=\"1619853323\" data-linked-resource-version=\"4\" data-linked-resource-type=\"page\">Spec: Switchboard Coordinator</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/2232549385/Spec+Fleet+Alerts+in+Switchboard\" data-linked-resource-id=\"2232549385\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Spec: Fleet Alerts in Switchboard</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1740767238/Thinking+outside+the+box\" data-linked-resource-id=\"1740767238\" data-linked-resource-version=\"4\" data-linked-resource-type=\"page\">Thinking outside the box</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1877311495/Agentic+Robotics+Context-Aware+Chat+as+the+Operator+Interface\" data-linked-resource-id=\"1877311495\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Agentic Robotics: Context-Aware Chat as the Operator Interface</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1931476998/System+2+vs+System+3\" data-linked-resource-id=\"1931476998\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">System 2 vs System 3</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2064842814/Spec+Switchboard+State+Model+Fleet+Registry\" data-linked-resource-id=\"2064842814\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">Spec: Switchboard State Model &amp; Fleet Registry</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/2138374220/Spec+Switchboard+Fleet+Identity+Enrollment\" data-linked-resource-id=\"2138374220\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Switchboard Fleet Identity &amp; Enrollment</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/2080407559/Spec+Studio+System-3+Agents+for+Workflow+Operations+Deployment\" data-linked-resource-id=\"2080407559\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Spec: Studio \u2014 System-3 Agents for Workflow Operations &amp; Deployment</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1672577044/Spec+Insight+-+Fleet+Observability\" data-linked-resource-id=\"1672577044\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">Spec: Insight - Fleet Observability</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2115043376/Spec+Standardized+Cloud+Communication+High+level\" data-linked-resource-id=\"2115043376\" data-linked-resource-version=\"19\" data-linked-resource-type=\"page\">Spec: Standardized Cloud Communication (High level)</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/2135916559/Standardized+Cloud+Communication+Companion+Doc\" data-linked-resource-id=\"2135916559\" data-linked-resource-version=\"4\" data-linked-resource-type=\"page\">Standardized Cloud Communication Companion Doc</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/2140962821/Spec+Passport+Robot+Workload+Identity\" data-linked-resource-id=\"2140962821\" data-linked-resource-version=\"13\" data-linked-resource-type=\"page\">Spec: Passport Robot Workload Identity</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2145484811/Spec+Local+Envoy+Workload+Proxy\" data-linked-resource-id=\"2145484811\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Local Envoy Workload Proxy</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1712324676/Spec+Dev+Tooling+Agent+Substrate\" data-linked-resource-id=\"1712324676\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Spec: Dev Tooling &amp; Agent Substrate</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1667268609/Spec+Shared+Filesystem+for+Pintel+Kubernetes+Cluster\" data-linked-resource-id=\"1667268609\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Spec: Shared Filesystem for Pintel Kubernetes Cluster</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1501626408/Spec+Kubernetes+Simulation+Service\" data-linked-resource-id=\"1501626408\" data-linked-resource-version=\"10\" data-linked-resource-type=\"page\">Spec: Kubernetes Simulation Service</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/2099871761/Spec+Simulation+Service+API+and+CLI+Compatibility\" data-linked-resource-id=\"2099871761\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Simulation Service API and CLI Compatibility</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2099806230/Spec+Simulation+Runtime+on+EKS\" data-linked-resource-id=\"2099806230\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Simulation Runtime on EKS</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2099904528/Spec+Simulation+Catalog\" data-linked-resource-id=\"2099904528\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Simulation Catalog</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2099871787/Spec+Simulation+Workflow+Runs\" data-linked-resource-id=\"2099871787\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Simulation Workflow Runs</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1712324702/AI+org+overnight+agents\" data-linked-resource-id=\"1712324702\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">AI org overnight agents</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1818624031/Cloud+Agents+Options+Analysis\" data-linked-resource-id=\"1818624031\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Cloud Agents: Options Analysis</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1819705397/Agent+Substrate+Implementation+Plan\" data-linked-resource-id=\"1819705397\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Agent Substrate: Implementation Plan</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1177911301/Spec+Wifi+QoS\" data-linked-resource-id=\"1177911301\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Wifi QoS</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1177878534/Spec+CPU+Pinning+and+Slices\" data-linked-resource-id=\"1177878534\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Spec: CPU Pinning and Slices</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1186627652/Spec+Secure+Thor+OTA\" data-linked-resource-id=\"1186627652\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Secure Thor + OTA</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1417478145/Spec+Booting+Alpha+With+kexec\" data-linked-resource-id=\"1417478145\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Spec: Booting Alpha With kexec</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1485275162/Spec+Single-Shot+Deployment+MVP\" data-linked-resource-id=\"1485275162\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">Spec: Single-Shot Deployment MVP</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1715994636/Studio+Agentic+Workflow+Updates\" data-linked-resource-id=\"1715994636\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Studio: Agentic Workflow Updates</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1713373231/Robot+Posing+and+Deployment\" data-linked-resource-id=\"1713373231\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Robot Posing and Deployment</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1718878287/Mapping+and+Tagging\" data-linked-resource-id=\"1718878287\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Mapping and Tagging</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1803386953/Potential+Deployment+MVP+for+Symphony\" data-linked-resource-id=\"1803386953\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Potential Deployment MVP for Symphony</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1839726604/Reverb+workflow+pattern+library\" data-linked-resource-id=\"1839726604\" data-linked-resource-version=\"8\" data-linked-resource-type=\"page\">Reverb workflow pattern library</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1501986854/Spec+Video+Compression+for+Cameras\" data-linked-resource-id=\"1501986854\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Spec: Video Compression for Cameras</a></li><li><a href=\"/wiki/spaces/ROBOT/whiteboard/1508769803\" data-linked-resource-id=\"1508769803\" data-linked-resource-version=\"1\" data-linked-resource-type=\"whiteboard\">Untitled whiteboard 2026-01-14</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1533018204/Spec+Data+Recording+and+Upload\" data-linked-resource-id=\"1533018204\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Data Recording and Upload</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1562247185/Spec+data+collection+in+the+application+loop\" data-linked-resource-id=\"1562247185\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Spec: data collection in the application loop</a></li><li><a href=\"/wiki/spaces/ROBOT/whiteboard/1564311554\" data-linked-resource-id=\"1564311554\" data-linked-resource-version=\"6\" data-linked-resource-type=\"whiteboard\">Untitled whiteboard 2026-01-27</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1558904878/Spec+Software+Faults+Surfacing+Them\" data-linked-resource-id=\"1558904878\" data-linked-resource-version=\"16\" data-linked-resource-type=\"page\">Spec: Software Faults &amp; Surfacing Them</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1511358474/Spec+Proposed+Scope+of+Work+for+Voice+Interaction+in+Q1+2026\" data-linked-resource-id=\"1511358474\" data-linked-resource-version=\"26\" data-linked-resource-type=\"page\">Spec: Proposed Scope of Work for Voice Interaction in Q1 2026</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1610612739/Spec+Who+commands+what+On+teleoperation+policy+execution+and+joint+resource+management\" data-linked-resource-id=\"1610612739\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Who commands what? On teleoperation, policy execution, and joint resource management</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1616248960/WIP+Spec+Robotless+data+collection+with+the+Quest\" data-linked-resource-id=\"1616248960\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">WIP Spec: Robotless data collection with the Quest</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1634107407/Spec+Cloudflare+R2+and+AWS+s3\" data-linked-resource-id=\"1634107407\" data-linked-resource-version=\"6\" data-linked-resource-type=\"page\">Spec: Cloudflare R2 and AWS s3</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1644134403/Spec+Data+pipeline+for+Bosch+POC\" data-linked-resource-id=\"1644134403\" data-linked-resource-version=\"30\" data-linked-resource-type=\"page\">Spec: Data pipeline for Bosch POC</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1659174916/Spec+Devices+Telemetry+Data+Collection+Contract\" data-linked-resource-id=\"1659174916\" data-linked-resource-version=\"8\" data-linked-resource-type=\"page\">Spec: Devices Telemetry Data Collection Contract</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1658748938/Spec+Robot+Data+Upload+Flow\" data-linked-resource-id=\"1658748938\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">Spec: Robot Data Upload Flow</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/2231664646/Rclone+Control+GUI+Prototype\" data-linked-resource-id=\"2231664646\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Rclone Control GUI Prototype</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1681555475/Spec+policy+evaluation+framework\" data-linked-resource-id=\"1681555475\" data-linked-resource-version=\"6\" data-linked-resource-type=\"page\">Spec: policy evaluation framework</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1712193562/SPEC+Recording+Data+Without+Pre-registration\" data-linked-resource-id=\"1712193562\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">SPEC: Recording Data Without Pre-registration</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1711898664/SPEC+Recording+Data+without+Pre-registration+Details\" data-linked-resource-id=\"1711898664\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">SPEC: Recording Data without Pre-registration [Details]</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1711571015/Spec+Dev+vs+Release+Images\" data-linked-resource-id=\"1711571015\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Spec: Dev vs Release Images</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1722744873/Spec+K8S+-+Priorities+and+Resource+Management\" data-linked-resource-id=\"1722744873\" data-linked-resource-version=\"13\" data-linked-resource-type=\"page\">Spec: K8S - Priorities and Resource Management</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1840709745/GPU+Capacity+Planning\" data-linked-resource-id=\"1840709745\" data-linked-resource-version=\"34\" data-linked-resource-type=\"page\">GPU Capacity Planning</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1943207938/Spec+Volcano+Queues\" data-linked-resource-id=\"1943207938\" data-linked-resource-version=\"13\" data-linked-resource-type=\"page\">Spec: Volcano Queues</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1731624971/Spec+Multi+Robot+Navigation+Symphony+2\" data-linked-resource-id=\"1731624971\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Spec: Multi Robot Navigation (Symphony 2)</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1732411463/Fault+Systems+on+Robots\" data-linked-resource-id=\"1732411463\" data-linked-resource-version=\"4\" data-linked-resource-type=\"page\">Fault Systems on Robots</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1795883026/Replacing+our+data+collection+recorder+with+hmnd_recorder\" data-linked-resource-id=\"1795883026\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Replacing our data collection recorder with `hmnd_recorder`</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1797357640/Module+Health+Service+and+Fault+Service\" data-linked-resource-id=\"1797357640\" data-linked-resource-version=\"25\" data-linked-resource-type=\"page\">Module Health Service and Fault Service</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1839071314/Spec+Internal+Apps+Platform\" data-linked-resource-id=\"1839071314\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Spec: Internal Apps Platform</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1853554693/Spec+Cloudflare+R2+and+AWS+S3+page+v2\" data-linked-resource-id=\"1853554693\" data-linked-resource-version=\"22\" data-linked-resource-type=\"page\">Spec: Cloudflare R2 and AWS S3 page v2</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1860272150/HMND+Quest+Tracker+App+-+Test+Plan\" data-linked-resource-id=\"1860272150\" data-linked-resource-version=\"16\" data-linked-resource-type=\"page\">HMND Quest Tracker App - Test Plan</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1868628037/Spec+Machine+Orchestrator+Design+Proposal\" data-linked-resource-id=\"1868628037\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Spec: Machine Orchestrator Design Proposal</a></li><li><a href=\"/wiki/spaces/ROBOT/folder/1899986950\" data-linked-resource-id=\"1899986950\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Spec: Deployment Metric Collection (MVP)</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1969029148/Spec+launching+training+jobs+from+Humanoid+Console\" data-linked-resource-id=\"1969029148\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: launching training jobs from Humanoid Console</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1984102468/Spec+speculative+simulation+and+caching+for+system+2+agents\" data-linked-resource-id=\"1984102468\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">Spec: speculative simulation and caching for system 2 agents</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2002059272/Spec+Pose+-+Approach+-+Prompt\" data-linked-resource-id=\"2002059272\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Spec: Pose -&gt; Approach -&gt; Prompt</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2061434886/Spec+HMND+Outpost+Site+Authority\" data-linked-resource-id=\"2061434886\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Spec: HMND Outpost &amp; Site Authority</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2101542926/Spec+Make+Coordinator+IPs+Runtime+Configurable\" data-linked-resource-id=\"2101542926\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">Spec: Make Coordinator IPs Runtime Configurable</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2119303195/WIP+Spec+CI+Simulation+Testing+Spec+Isaac+Sim+Isaac+Lab\" data-linked-resource-id=\"2119303195\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">WIP Spec: CI Simulation Testing Spec (Isaac Sim / Isaac Lab)</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2130575473/Phase+2+Componentizing+Sockpuppet\" data-linked-resource-id=\"2130575473\" data-linked-resource-version=\"6\" data-linked-resource-type=\"page\">Phase 2: Componentizing Sockpuppet</a></li><li><a href=\"/wiki/spaces/ROBOT/folder/2203353089\" data-linked-resource-id=\"2203353089\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Spec: Factory</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/embed/2202665033\" data-linked-resource-id=\"2202665033\" data-linked-resource-version=\"2\" data-linked-resource-type=\"embed\">Systems Engineering | Platform Software - Sync and Diagrams</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/2202599550/Spec+Sensor+Library\" data-linked-resource-id=\"2202599550\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Spec: Sensor Library</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/2228125698/Spec+Humanoid+Console+-+Thor+integration\" data-linked-resource-id=\"2228125698\" data-linked-resource-version=\"9\" data-linked-resource-type=\"page\">Spec: Humanoid Console - Thor integration</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/whiteboard/2240970782\" data-linked-resource-id=\"2240970782\" data-linked-resource-version=\"2\" data-linked-resource-type=\"whiteboard\">Option 1</a></li><li><a href=\"/wiki/spaces/ROBOT/whiteboard/2240151614\" data-linked-resource-id=\"2240151614\" data-linked-resource-version=\"2\" data-linked-resource-type=\"whiteboard\">Option 2</a></li><li><a href=\"/wiki/spaces/ROBOT/whiteboard/2240151620\" data-linked-resource-id=\"2240151620\" data-linked-resource-version=\"2\" data-linked-resource-type=\"whiteboard\">Option 3</a></li><li><a href=\"/wiki/spaces/ROBOT/whiteboard/2241167382\" data-linked-resource-id=\"2241167382\" data-linked-resource-version=\"4\" data-linked-resource-type=\"whiteboard\">Option 4</a></li><li><a href=\"/wiki/spaces/ROBOT/whiteboard/2241232958\" data-linked-resource-id=\"2241232958\" data-linked-resource-version=\"2\" data-linked-resource-type=\"whiteboard\">Untitled whiteboard 2026-07-20 (5)</a></li></ul></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1167294522/Synapse\" data-linked-resource-id=\"1167294522\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">Synapse</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1179516973/Motivation\" data-linked-resource-id=\"1179516973\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Motivation</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1178599484/Ethernet+Performance\" data-linked-resource-id=\"1178599484\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">Ethernet Performance</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1678770202/AM2612+Internal+Switch+Performance\" data-linked-resource-id=\"1678770202\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">AM2612 Internal Switch Performance</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1179910202/Synapse+Protocol+Overview\" data-linked-resource-id=\"1179910202\" data-linked-resource-version=\"30\" data-linked-resource-type=\"page\">Synapse Protocol Overview</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1835401222/How+to+run+Synapse+on+the+host+device+with+4+fake+devices\" data-linked-resource-id=\"1835401222\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">How to run Synapse on the host device with 4 fake devices</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1935048906/System+Software+Architecture\" data-linked-resource-id=\"1935048906\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">System Software Architecture</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/folder/1531543626\" data-linked-resource-id=\"1531543626\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Embracing the Slop: AI Agents</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1521811588/Quickstart+and+Tooling\" data-linked-resource-id=\"1521811588\" data-linked-resource-version=\"14\" data-linked-resource-type=\"page\">Quickstart and Tooling</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/folder/1566343187\" data-linked-resource-id=\"1566343187\" data-linked-resource-version=\"1\" data-linked-resource-type=\"folder\">Boot and release process</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1119518753/Release+process\" data-linked-resource-id=\"1119518753\" data-linked-resource-version=\"7\" data-linked-resource-type=\"page\">Release process</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1565130824/RFC+OCB.1+-+Boot+and+update+process\" data-linked-resource-id=\"1565130824\" data-linked-resource-version=\"30\" data-linked-resource-type=\"page\">RFC OCB.1 - Boot and update process</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/whiteboard/1623293965\" data-linked-resource-id=\"1623293965\" data-linked-resource-version=\"7\" data-linked-resource-type=\"whiteboard\">Boot and update architecture</a></li><li><a href=\"/wiki/spaces/ROBOT/whiteboard/1624145925\" data-linked-resource-id=\"1624145925\" data-linked-resource-version=\"4\" data-linked-resource-type=\"whiteboard\">Software image</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1679491114/RFC+OCB.2+-+Config+management\" data-linked-resource-id=\"1679491114\" data-linked-resource-version=\"9\" data-linked-resource-type=\"page\">RFC OCB.2 - Config management</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/whiteboard/2096463925\" data-linked-resource-id=\"2096463925\" data-linked-resource-version=\"3\" data-linked-resource-type=\"whiteboard\">HMND OS Overview</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/2079916039/RFC+OCB.3+-+OS+release+images\" data-linked-resource-id=\"2079916039\" data-linked-resource-version=\"34\" data-linked-resource-type=\"page\">RFC OCB.3 - OS release images</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/1670709288/Robot+Software+Architecture+Current+State\" data-linked-resource-id=\"1670709288\" data-linked-resource-version=\"3\" data-linked-resource-type=\"page\">Robot Software Architecture (Current State)</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1734115331/Sockpuppet+WebRTC+Investigation+and+Learnings\" data-linked-resource-id=\"1734115331\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">Sockpuppet WebRTC Investigation and Learnings</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1840054289/OSS+Licensing+Audit\" data-linked-resource-id=\"1840054289\" data-linked-resource-version=\"4\" data-linked-resource-type=\"page\">OSS Licensing &quot;Audit&quot;</a><ul class=\"childpages-macro\"><li><a href=\"/wiki/spaces/ROBOT/pages/1839038509/OSS+Audit+hmnd_robot\" data-linked-resource-id=\"1839038509\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">OSS Audit: hmnd_robot</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1840807951/OSS+Audit+hmnd_training\" data-linked-resource-id=\"1840807951\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">OSS Audit: hmnd_training</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1840775181/OSS+Audit+hmnd_sim\" data-linked-resource-id=\"1840775181\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">OSS Audit: hmnd_sim</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1840873486/OSS+Audit+hmnd_flywheel\" data-linked-resource-id=\"1840873486\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">OSS Audit: hmnd_flywheel</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1839071263/OSS+Audit+hmnd_locomotion\" data-linked-resource-id=\"1839071263\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">OSS Audit: hmnd_locomotion</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1839235107/OSS+Audit+hmnd_wholebody\" data-linked-resource-id=\"1839235107\" data-linked-resource-version=\"2\" data-linked-resource-type=\"page\">OSS Audit: hmnd_wholebody</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1840807976/OSS+Audit+hmnd_fleet+hmnd_services+hmnd_update\" data-linked-resource-id=\"1840807976\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">OSS Audit: hmnd_fleet, hmnd_services, hmnd_update</a></li><li><a href=\"/wiki/spaces/ROBOT/pages/1839693858/OSS+Audit+hmnd_design+hmnd_playground+Root+Bazel\" data-linked-resource-id=\"1839693858\" data-linked-resource-version=\"1\" data-linked-resource-type=\"page\">OSS Audit: hmnd_design, hmnd_playground, Root/Bazel</a></li></ul></li><li><a href=\"/wiki/spaces/ROBOT/pages/2105475136/Fleet+Software+Requirements+Services+Mapping\" data-linked-resource-id=\"2105475136\" data-linked-resource-version=\"5\" data-linked-resource-type=\"page\">Fleet Software: Requirements \u2192 Services Mapping</a></li></ul><h2 id=\"Software-MiroBoardsandOtherResources\">Miro Boards and Other Resources</h2><p><a href=\"https://miro.com/app/board/uXjVIjzyrI0=/\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://miro.com/app/board/uXjVIjzyrI0=/</a> </p><p />"
        },
        {
          "id": "1019543565",
          "title": "Joint Control for Dummies",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1019543565",
          "last_modified": "2025-08-01T10:25:26.878Z",
          "created_at": "2025-08-01T08:22:00.665Z",
          "body_html": "<p>In part 1, <a href=\"https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1017905442/Actuator+Control+for+Dummies?atlOrigin=eyJpIjoiNmQxZGI5ZDA4NDJjNDRlYTkzNjYwYjFhZTY5ZWNhZWMiLCJwIjoiYyJ9\" data-card-appearance=\"inline\" rel=\"nofollow\">https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1017905442/Actuator+Control+for+Dummies?atlOrigin=eyJpIjoiNmQxZGI5ZDA4NDJjNDRlYTkzNjYwYjFhZTY5ZWNhZWMiLCJwIjoiYyJ9</a>, we looked at how our off-the-shelf actuators allow for position, velocity and torque control over standardized \u201cCANopen\u201d interfaces using EtherCAT.  At the very end, I mentioned how this isn\u2019t quite good enough.</p><p>With a motor sitting on the workbench, the actuator control is probably good enough for anything you\u2019d want to do with the motor.  But once you actually put a load on the motor (especially if that load exerts some force via moment arm), we need to be concerned with how these actuators interact with the environment.  In robotics we often call this \u201ccompliant control\u201d.</p><p>Compliant control allows us to model the interaction between the robot and the environment as if there is some virtual spring with some configurable stiffness.  A very compliant (low stiffness) controller will be noodle-y and limp, yielding to the environment easily and exerting very little force.  A less compliant (high stiffness) controller will move quickly and with precision, but may exert much more force on the environment in order to do so.  Compliant controllers often require mode sophisticated dynamics models to work, since they are attempting to control a virtual \u201cdynamic\u201d system (the spring dynamics mentioned earlier).</p><h1 id=\"JointControlforDummies-ImpedanceControl\">Impedance Control</h1><p>In electrical systems, we say that impedance is a circuit's resistance to current (its a slightly more general form of resistance that can include capacitance or inductance for AC or RF circuits but we\u2019ll ignore this for now).  If you remember Ohm\u2019s law, V = IR, you can basically see how impedance works if you pretend the R is a Z and ignore the imaginary numbers involved.</p><p>Because a lot of controls engineers have electrical backgrounds, they couldn\u2019t resist (lol) the analogy here where the impedance controller is attempting to \u201cresist\u201d some mechanical motion given some force.  We can crudely re-write Ohm\u2019s law for our motor with something like Force = Movement * Impedance.</p><p>So given some desired movement (a position and velocity target perhaps along a trajectory), an impedance controller will compute an error from the currently measured movement, and from this compute some inferred torque as if this were the displacement in some spring.  This tells the controller how hard to push back so that the error goes to zero.  The higher the error, the more the controller will push back (just like a spring).  </p><h1 id=\"JointControlforDummies-AdmittanceControl\">Admittance Control</h1><p>Again, electrical engineers can\u2019t resist the temptation, and so the inverse of impedance in electrical systems is known as admittance and is represented with a Y. This is analogous to the \u201cconductance\u201d of the circuit, or how easily current can move.</p><p>Instead of giving the controller a movement and generating a torque, an admittance controller will take a force and determine a movement.   In order to close the loop, admittance control will need some way to sense force - either an external force sensor or perhaps a crude approximation by measuring motor currents.</p><p>So we measure the external forces/torques, and then compute the expected displacement of our virtual spring (gross oversimplification - sorry) and apply this to the actuator using something like CSP mode.  We tell the actuator how to move in response to some external force.</p><p>Admittance control is useful in scenarios where you have extremely high-friction, non-backdriveable actuators that you want to simulate some sort of compliance with.  You can slap on a torque or force sensor and use admittance control to allow the system to be pushed around in a more compliant mode.</p><h1 id=\"JointControlforDummies-Feed-ForwardDynamics\">Feed-Forward Dynamics</h1><p>Let\u2019s imagine a robot arm being held straight out in front of the robot, being impedance controlled with a very low stiffness.  Gravity will be pulling the arm down, generating some pretty hefty torques on the shoulder joint and resulting in sagging.  Or imagine the robot swinging its arm out to pick something up, the resulting Coriolis forces would be generating torques for many of the joints that are along the chain.</p><p>These external torques can cause some major issues with impedance control, making precision control very difficult if not accounted for.  Unlike the simpler actuator control, impedance control requires much better models of the robot\u2019s dynamics and morphology so that we can properly cancel out these dynamics when controlling our robot.</p><p />"
        },
        {
          "id": "1017905442",
          "title": "Actuator Control for Dummies",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1017905442",
          "last_modified": "2025-07-31T18:06:19.321Z",
          "created_at": "2025-07-31T17:32:44.778Z",
          "body_html": "<p>This is part 1 of a series of posts here about control.  I\u2019m not a controls engineer, so a lot of this is to help me organize my thoughts on matters, but also to help other SWEs unfamiliar with the details of controls to get up to speed.</p><h1 id=\"ActuatorControlforDummies-Positions,VelocitiesandTorques\"><strong>Positions, Velocities and Torques</strong></h1><p>Many of us probably attached a DC motor directly to a battery at some point as kids to make it spin.  The battery energizes the electromagnetic windings of motor and generates a torque which spins the motor.  The higher the voltage, the more current and thus more torque generated.  In this fashion, the motor is operating in an open loop configuration (without feedback), and so its difficult (impossible) to control for precise torques.</p><p>With closed-loop feedback, we measure torque (or rather infer it from actual current consumption) and use some PID loop to feed this back and control the input so that we get some target target.  Easy right?  Well - in practice this is actually pretty challenging, usually requiring some fancy \u201c<a href=\"https://en.wikipedia.org/wiki/Vector_control_(motor)\" class=\"external-link\" rel=\"nofollow\">field-oriented control</a>\u201d because the motors we use are typically brushless and much more efficient that the simple DC motors we hooked up to batteries as children.  These torque loops operate at 10s - 100s of KHz for smooth control, because it needs to keep up with the inductance and switching frequencies required to drive the motor windings (which requires a very high speed and low-latency).  For these reasons, torque control is often implemented directly within the actuator itsef.</p><p>Once you have a core torque loop, you can wrap it with a velocity controller which attempts to match some specific speed.  You can use an encoder to get the current speed of the motor, and adjust the target torque up or down until you get the desired speed.  This can run much slower than the torque loop, 100s of Hz to KHz range, because unlike torque control the feedback here is the mechanical spinning of the motor itself rather than the actual electrical properties of the windings and such.</p><p>Finally, you can wrap this velocity controller with a position controller which given some specific position will command the velocity required to get there.  This will operate typically around the same speed as the velocity control loop (maybe a little slower but not much).</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250731-180330.png\" width=\"664\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1017905442/image-20250731-180330.png?version=1&amp;modificationDate=1753985011847&amp;cacheVersion=1&amp;api=v2&amp;width=664&amp;height=334\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1017905442/image-20250731-180330.png?version=1&amp;modificationDate=1753985011847&amp;cacheVersion=1&amp;api=v2\" data-height=\"425\" data-width=\"844\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1018167352\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250731-180330.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1017905442\" data-linked-resource-container-version=\"1\" data-media-id=\"910b58a4-e4d1-4655-bfd0-0a0bb7c42599\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1017905442/image-20250731-180330.png?version=1&amp;modificationDate=1753985011847&amp;cacheVersion=1&amp;api=v2&amp;width=844&amp;height=425 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1017905442/image-20250731-180330.png?version=1&amp;modificationDate=1753985011847&amp;cacheVersion=1&amp;api=v2&amp;width=664&amp;height=334 1x\"></span><p /><p>This stack of controllers is called a \u201ccascade controller\u201d, and it lies at the heart of the actuators used on our robots.  If you\u2019re controlling position, it will go to the position controller which will generate a velocity target, which goes to the velocity controller which generates a torque target which goes to the torque controller which ultimately controls the actuator with FOC.  If you\u2019re controlling velocity, you can set the velocity target directly and skip the position controller.  If you\u2019re controlling torque you only drive the last layer in the controller.</p><h1 id=\"ActuatorControlforDummies-EtherCAT,CANandDS402\">EtherCAT, CAN and DS402</h1><p>In the world of industrial automation, there is no shortage of demand for precision actuation.  Conveyor belts, servos, robot arms, doors, wheels - endless possibilities.  To help manufacturers out, some open standards were created.</p><p>DS402 defines the device profile for a generic actuator using the cascade controller above.  These devices have a standardized state machine, control words/addresses and modes including CSP, CSV and CST (cyclic synchronous position, velocity and torque respectively) which allow different applications with the same profile.  You can also configure limits, homing and all that, but we\u2019ll conveniently forget about all this for now.</p><p>Originally the communication bus was CAN (controller area network) which was originally used in automotive for networking the components of the car.  CAN has robust cabling, simple integration but (compared to more modern stacks at least) low data rates.  You can set velocities or positions over CAN, but anything force sensitive requiring direct torque control is going to be impossible\u2026</p><p>So some clever industrial folks decided to lift the protocols from the limited CAN bus to Ethernet and called it EtherCAT.  Orders of magnitude more bandwidth, deterministic switching and microsecond latencies allow for multi-KHz update loops for dozens of actuators.</p><h1 id=\"ActuatorControlforDummies-Necessary,ButNotSufficient\">Necessary, But Not Sufficient</h1><p>Having solid actuator control is critical to building a humanoid robot, but its not enough.  For example, compliant interfaces or force-sensitive tasks like picking up fruit or other fragile objects requires driving the torque directly and skipping the CSP or CSV modes (usually - there are exceptions of course).</p><p>This means we need ANOTHER layer of control sitting above our actuator cascade control operating at the KHz range to make sure our motions are smooth and safe.</p>"
        },
        {
          "id": "1010335765",
          "title": "\ud83e\udea4 Robot Middleware",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1010335765",
          "last_modified": "2025-07-28T14:23:07.664Z",
          "created_at": "2025-07-28T14:05:26.077Z",
          "body_html": "<p>If you\u2019ve built real robots, you\u2019ve probably tripped over the same architectural pothole: middleware. ROS, DDS, some custom pub-sub nonsense - take your pick. Each promises modularity, scalability, and discoverability. But in reality? You get a mess of launch files, mismatched message definitions, time sync gremlins, and mysterious data black holes between nodes that <em>should</em> be talking.</p><p>Robotics middleware like ROS can be useful early in prototyping as researchers and engineers cobble together pre-existing modules, but it quickly becomes a liability under the pressures of shipping a real product.</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250728-142158.png\" width=\"460\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1010335765/image-20250728-142158.png?version=1&amp;modificationDate=1753712519607&amp;cacheVersion=1&amp;api=v2&amp;width=460&amp;height=337\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1010335765/image-20250728-142158.png?version=1&amp;modificationDate=1753712519607&amp;cacheVersion=1&amp;api=v2\" data-height=\"337\" data-width=\"460\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1010335778\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250728-142158.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1010335765\" data-linked-resource-container-version=\"1\" data-media-id=\"1a80ea86-25de-48dc-84b2-50a0b5846e09\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1010335765/image-20250728-142158.png?version=1&amp;modificationDate=1753712519607&amp;cacheVersion=1&amp;api=v2&amp;width=920&amp;height=674 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1010335765/image-20250728-142158.png?version=1&amp;modificationDate=1753712519607&amp;cacheVersion=1&amp;api=v2&amp;width=460&amp;height=337 1x\"></span><p /><p>It doesn\u2019t take long before the magic middleware is fighting you and teams are swimming upstream to ship anything at all.\u00a0 At some point, the question isn\u2019t \u201cwhich middleware should we be using?\u201d It\u2019s: <strong>Why are we using middleware at all?</strong></p><h1 id=\"id-\ud83e\udea4RobotMiddleware-\ud83e\udea4ThePromiseofMiddleware\">\ud83e\udea4The Promise of Middleware</h1><p>Middleware exists to \u201cpre-solve\u201d integration. Every module is nicely encapsulated and exposes a strict set of messages that can be used to communicate with it.\u00a0 You can find research labs who have published ready-to-go modules and put everything together like Lego and get a working robot.\u00a0 You can swap out controllers or camera nodes or SLAM nodes with minimal impact to the rest of the system.\u00a0 As long as each node adheres to the middleware interface, everything fits together.\u00a0 Very Nice!</p><p>The most common sort of middleware with robotics systems is some sort of message bus.\u00a0 You hang various nodes covering different functions of the robot on this bus, and they communicate by publishing messages on various topics.\u00a0 This sort of architecture has been proven to be effective in large-scale data systems in the cloud (event sourcing basically), but is it the correct choice for a robot?</p><p>In cloud-based systems, message buses are almost exclusively used for unidirectional communication.\u00a0 System A notifies system B that something happened, which then triggers some action and then it notifies some downstream System C.\u00a0 These systems are usually very large scale, with billions of messages spread over hundreds or thousands of hosts.</p><p>Automobiles also make extensive use of a message bus, though this is the CAN interface.\u00a0 It operates across dozens of nodes and has many orders of magnitude fewer messages.\u00a0 Because of the way that automotive supply chains have been distributed over the last couple decades, these interfaces are fairly standardized and largely plug &amp; play.</p><p>So if a message bus can work for a large-scale cloud system and a smaller-scale automobile (or fly-by-wire aircraft or a number of other vehicles), why not for a robot?</p><h1 id=\"id-\ud83e\udea4RobotMiddleware-\ud83d\udca5MiddlewareGoneWild\">\ud83d\udca5Middleware Gone Wild</h1><p>What makes middleware challenging for robotics is that the state of the system doesn\u2019t really partition naturally.\u00a0 At some point, you need to build a world model.\u00a0 And at some point, you need to decide how the robot as a whole will act given this model.\u00a0 These are fundamentally global things, and partitioning this state over many separate nodes communicating via pubsub (or any other messaging interface) means that you spend an enormous amount of time trying to reconstruct that global state from these smaller fragments.</p><p><strong>Concurrency and Non-Determinism</strong></p><p>By smashing nodes up and decoupling everything, you effectively transform your robotics stack into a distributed system.\u00a0 This means that every node will not be able to agree on a common global \u201chistory\u201d of events within the system.\u00a0 <span class=\"inline-comment-marker\" data-ref=\"357e06b4-90dc-4c41-92ed-ea88de80ebe9\">Different nodes may see events in different orders (across topics) or different sets of events (within a topic) due to scheduling differences or QoS.</span></p><p>Consider camera data - usually \u201cold\u201d data is not useful, and so to avoid increasing latency when the system is temporarily overwhelmed you want to enable the KEEP_LAST QoS policy which means that subscribers will keep the last N messages only, bounding the queues (and thus latency).\u00a0 What this means is that while a message may be published on some camera topic, there is no guarantee that all the subscribers would see that message.\u00a0 <span class=\"inline-comment-marker\" data-ref=\"8260a6ff-a76f-4767-bee8-2f1086ea6d0e\">You may have a camera message that isn\u2019t seen by your perception stack, but it IS logged by data collection.</span>\u00a0 Or perhaps the opposite scenario. In these cases, it is difficult to reason about the data that has passed through each node without logging everything within each node and doing extensive post-processing.</p><p>This makes it impossible to replay an episode from recorded data and guarantee that you can reproduce the same behavior.\u00a0 When it comes to tracking down long-tail reliability issues, this is a major impediment to progress.\u00a0 <span class=\"inline-comment-marker\" data-ref=\"f5728597-b0d2-47f5-9c60-a3c905ad7ce4\">In order to reconstruct the same behavior, you need to be able to reconstruct the same global state.\u00a0 But if that global state is distributed over independent processes which may see different subsets of data, it's nearly hopeless.\u00a0 </span>This is made worse by the fact that robots are inherently chaotic in that tiny changes to the input can result in significant changes to the output.\u00a0\u00a0\u00a0</p><p><strong>Observability</strong></p><p>One benefit of middleware is that it often provides a way to \u201csniff\u201d the message bus, making it possible to observe the communication between nodes.\u00a0 But only a tiny amount of the state of the system is actually exchanged on these topics (at least that\u2019s the hope - otherwise the system would never work as you\u2019d quickly overwhelm the message bus).\u00a0 But <em>which history</em> are you seeing?\u00a0 When you subscribe to a topic to see what\u2019s going on, this is NOT the same data stream that other nodes are seeing.\u00a0 They could be dropping or queuing those messages internally in ways that are not directly observable from your temporary subscriber.</p><p>And what about performance analysis, profiling or debugging the actual nodes themselves?\u00a0 This can get challenging - as attaching a debugger to a single node often changes the performance of the node and can trigger cascading failures around the system.\u00a0 You often need to dump the message bus AND collect profiling data from all the nodes and then do some sort of extensive analysis to line everything up to see how the system as a whole is performing.\u00a0\u00a0</p><p>Related to the above,<span class=\"inline-comment-marker\" data-ref=\"06a0276c-d651-4898-85c8-3666793b2574\"> if a random node crashes or segfaults, it can be fiendishly difficult to reproduce this behavior in isolation since you can\u2019t be guaranteed that you can reproduce exactly the internal state</span>.\u00a0 You can maybe grab crash dumps, but loading that dump into a single node and trying to figure out what happened without the context of the rest of the system is extremely difficult.</p><h1 id=\"id-\ud83e\udea4RobotMiddleware-\ud83e\uddd8FindingPeaceWithoutMiddleware\">\ud83e\uddd8Finding Peace Without Middleware</h1><p>ROS2 does indeed offer a ton of useful tooling including visualizers and data logging - but we don\u2019t actually need to leverage ROS2 as core middleware to make use of these things.\u00a0 What would a system look like if we chose NOT to use something like ROS2?</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250728-142227.png\" width=\"662\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1010335765/image-20250728-142227.png?version=1&amp;modificationDate=1753712548303&amp;cacheVersion=1&amp;api=v2&amp;width=662&amp;height=168\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1010335765/image-20250728-142227.png?version=1&amp;modificationDate=1753712548303&amp;cacheVersion=1&amp;api=v2\" data-height=\"172\" data-width=\"674\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1009549415\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250728-142227.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1010335765\" data-linked-resource-container-version=\"1\" data-media-id=\"9a0df12e-1f5b-4792-a08b-f0645f4c3f90\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1010335765/image-20250728-142227.png?version=1&amp;modificationDate=1753712548303&amp;cacheVersion=1&amp;api=v2&amp;width=1324&amp;height=336 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1010335765/image-20250728-142227.png?version=1&amp;modificationDate=1753712548303&amp;cacheVersion=1&amp;api=v2&amp;width=662&amp;height=168 1x\"></span><p /><p>First, consider that each topic is really a publish queue attached to N subscriber queues with a \u201clossy channel\u201d in the middle (the topic).\u00a0 The lossiness of the channel is determined by how QoS is configured within DDS (and ultimately depends on the latency vs reliability tradeoffs necessary for the topic or nodes).\u00a0 Consider a case where one subscriber runs much slower than the others - there are only a couple possibilities:</p><p /><ol start=\"1\"><li><p>Apply backpressure all the way to the publisher, slowing <strong>everything </strong>down - this almost ensures that any data seen at the publisher is seen by all subscribers, but it means that the slowest subscriber will control the pace of all data on the topic.\u00a0 <span class=\"inline-comment-marker\" data-ref=\"cc8ea426-481a-4edb-b368-0be554ebacd4\">Say goodbye to performance.</span></p></li><li><p>Drop messages at the slowest subscribers - this keeps the publish rate up, but now we are deliberately choosing a scenario where some nodes see a different set of data than others.\u00a0 Say goodbye to determinism.</p></li></ol><p /><p>Instead of leaving the management of these queues up to some abstract middleware, we should own them.\u00a0 <span class=\"inline-comment-marker\" data-ref=\"d8640f39-4ed2-468a-b371-36d81849ddb8\">Instead of forcing everything to be serialized and transported over a socket, we should just enqueue native data and call functions</span>.\u00a0 If we are going to introduce IPC, it should not be the default - it should only be introduced for a good (and specific) reason.\u00a0 For example, we may need to communicate between multiple hosts or language runtimes, or we may want to isolate some I/O heavy workloads like data logging from the actual core autonomy stack to avoid any sort of interference.</p><p /><p>Imagine that instead of trying to shoot our data all over various topics and nodes, we instead have a monolithic application where we queue up all of our sensor data with a unified and integrated QoS policy and we log exactly the messages that are processed:</p><span class=\"confluence-embedded-file-wrapper image-center-wrapper confluence-embedded-manual-size\"><img class=\"confluence-embedded-image image-center\" alt=\"image-20250728-142254.png\" width=\"662\" loading=\"lazy\" src=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1010335765/image-20250728-142254.png?version=1&amp;modificationDate=1753712575855&amp;cacheVersion=1&amp;api=v2&amp;width=662&amp;height=357\" data-image-src=\"https://sklvc.atlassian.net/wiki/download/attachments/1010335765/image-20250728-142254.png?version=1&amp;modificationDate=1753712575855&amp;cacheVersion=1&amp;api=v2\" data-height=\"357\" data-width=\"662\" data-unresolved-comment-count=\"0\" data-linked-resource-id=\"1010368554\" data-linked-resource-version=\"1\" data-linked-resource-type=\"attachment\" data-linked-resource-default-alias=\"image-20250728-142254.png\" data-base-url=\"https://sklvc.atlassian.net/wiki\" data-linked-resource-content-type=\"image/png\" data-linked-resource-container-id=\"1010335765\" data-linked-resource-container-version=\"1\" data-media-id=\"7a7759c4-ff17-4173-a17d-6b91ec90e85f\" data-media-type=\"file\" srcset=\"https://sklvc.atlassian.net/wiki/download/thumbnails/1010335765/image-20250728-142254.png?version=1&amp;modificationDate=1753712575855&amp;cacheVersion=1&amp;api=v2&amp;width=1324&amp;height=714 2x, https://sklvc.atlassian.net/wiki/download/thumbnails/1010335765/image-20250728-142254.png?version=1&amp;modificationDate=1753712575855&amp;cacheVersion=1&amp;api=v2&amp;width=662&amp;height=357 1x\"></span><p /><p>This more linear datapath forces a total ordering of all data in the system, which brings us closer to deterministic execution.\u00a0 If you play the same log of sensor messages into the system, you should get the same actions.\u00a0 This isn\u2019t trivial, but it's a worthwhile goal since storing all of the state is intractable - but if we can reliably recreate the state from recorded observations then we can have many of the same capabilities.</p><p /><p>Just because this linear datapath exists doesn\u2019t mean that the whole loop has to operate at the same frequency.\u00a0 There may be high-frequency and low-frequency paths in here, but as long as the data itself can be ordered reliably, then we should be able to reproduce those states.</p><p /><p><span class=\"inline-comment-marker\" data-ref=\"51840d42-176e-4383-b2a1-f346e67d302c\">The logging above could in fact still be ROS2</span>, meaning we can still leverage rviz and other ROS2 tooling to help accelerate development.\u00a0 The point isn\u2019t to avoid ROS2 entirely - it's to avoid fragmenting our system up into many pieces and obfuscating the overall state and dataflow in the system.\u00a0 It\u2019s to avoid introducing tight, bi-directional coupling over a message bus <span class=\"inline-comment-marker\" data-ref=\"c4375ca8-47e0-4a1d-9faf-95028e840883\">when we can instead have modules integrated more directly using simpler primitives like threads and queues.\u00a0\u00a0</span></p><h1 id=\"id-\ud83e\udea4RobotMiddleware-\ud83e\udd16Summary\">\ud83e\udd16 Summary</h1><p>You want to swap perception modules, pipe planning into control, log data without polluting your control loop. Abstractions sound helpful - until they start abstracting away determinism, observability,<span class=\"inline-comment-marker\" data-ref=\"eb48ddd6-0636-4831-8db0-e022e943e764\"> and sanity</span>. The minute you insert a message bus between two components, you stop owning their behavior. Timestamps drift. Buffers overrun. QoS policies silently drop your data.\u00a0 Nodes may not agree on what data has been sent through the system, and thus the true global state of the system becomes more difficult to pin down.</p><p>That\u2019s not a bug in your system. That <em>is</em> your system.\u00a0 Distributed systems are fundamentally this way, and we choose to build them because oftentimes the tradeoff is worthwhile.\u00a0 Maybe all the algorithms don\u2019t fit in a single computer.\u00a0 Or maybe we need to isolate something for safety or performance reasons - the point is that when we choose to distribute state, it should be for a good reason rather than being the default choice as it often is when we choose some middleware.</p><p>The problem isn\u2019t that ROS2 is <em>bad</em> (though it has its quirks). The problem is what middleware encourages: fragmentation disguised as flexibility. You\u2019re forced to build around the middleware\u2019s assumptions - types, lifecycles, transports - until your architecture is shaped more by the message format than by what the robot actually needs to do.\u00a0 The architecture doesn\u2019t serve the product - it serves the middleware you\u2019ve chosen.</p><p>And sure, you <em>could</em> write your own lightweight protocol. Many do. But that\u2019s not the real choice either. The deeper point is: <strong>every middleware stack is a solution to problems created by introducing middleware in the first place.</strong></p><p />"
        },
        {
          "id": "1005027354",
          "title": "Integration and the Monorepo",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1005027354",
          "last_modified": "2025-07-25T16:01:03.615Z",
          "created_at": "2025-07-24T08:55:59.870Z",
          "body_html": "<p><strong>TL;DR </strong>- Your code goes here: <a href=\"https://github.com/HumanoidTeam/hmnd\" data-card-appearance=\"inline\" class=\"external-link\" rel=\"nofollow\">https://github.com/HumanoidTeam/hmnd</a> </p><p>In robotics, integration is <em><strong>everything</strong></em>.\u00a0 Without integration, you have a number of interesting parallel research tracks.\u00a0 But to get to a working robot that does commercially viable work, you need to painstakingly integrate the dozens of different subcomponents and subsystems.\u00a0 In almost every facet, the whole is much much greater than the sum of its parts:</p><p /><ul><li><p>Most of your <em>time</em> will be spent integrating</p></li><li><p>Most of your <em>bugs</em> will be found during integration</p></li><li><p>Most of the <em>value</em> is created by integrating</p></li></ul><p /><p>Integration represents a massive risk for the project - how can we be sure that all these individual pieces will fit together correctly at some point in the future?\u00a0 You can write ICDs, interface specs, APIs all you want, but until you actually put it all together you can\u2019t really be sure.</p><p /><p>Integration therefore should be front-and-center during development.\u00a0 Each change should be integrated with the entire system as soon as possible.\u00a0 The longer we go without integrating, the more costly it ultimately becomes.\u00a0 <strong>The way we organize, build and release our software should be oriented around delivering an integrated robot rather than individual team productivity.</strong></p><h2 id=\"IntegrationandtheMonorepo-1\ufe0f\u20e3TheMonorepo\">1\ufe0f\u20e3 The Monorepo</h2><p>Simply placing all components in the same repository puts us into an \u201cintegration-by-default\u201d environment.\u00a0 Of course there are <em>many</em> tradeoffs involved.\u00a0 With a multi-repo environment, each team is free to move very quickly, unburdened by others\u2019 modules.\u00a0 Each repo is smaller and therefore can be cloned and tested more quickly.\u00a0 Each repo is fundamentally more reliable (fewer tests being run means fewer chances for flakiness to derail CI).\u00a0 But the tradeoff here is that tying all of these separate repositories together is much more difficult.\u00a0 Given how important integration is to developing a robot, <em>is this the right tradeoff</em>?\u00a0 Does it make sense to defer all this coordination overhead until some later date?</p><p /><p>The integration could happen within source control via git submodules and some sort of integration repository, but this requires multiple pull requests (PRs) across multiple repositories to make a change.\u00a0 Coordinating interface changes across multiple components could involve changes to 3 or more repositories, and this is extraordinarily cumbersome with git submodules as they don\u2019t track branches easily. \u00a0 This is so painful that developers will often delay necessary refactors or integration changes until the future (where inevitably they are even more expensive).</p><p /><p>Integrating later (fetching pre-built artifacts at build or deployment time) has many of the same downsides as using submodules, but also introduces a lot of additional versioning and artifact management overhead.\u00a0 Each component is versioned and every interface between components needs to be re-integrated over and over and over again.\u00a0 Integration generally becomes much more expensive.</p><p /><p>A single repository can produce a single set of artifacts versioned by a single commit.\u00a0 It becomes trivial to reason about compatibility, as every interface can be tested immediately within the repo.\u00a0 Every interface can be refactored in a single PR.\u00a0 Any changes across modules can be reviewed and merged as a single PR.\u00a0</p><h2 id=\"IntegrationandtheMonorepo-\ud83d\udd27MitigatingtheDownsides\">\ud83d\udd27 Mitigating the Downsides</h2><p>A decision to use a monorepo is a deliberate choice to accept a set of tradeoffs where individual teams may have a bit more friction, but end-to-end integration is faster and easier.\u00a0 The key assumption here is that because programs typically spend most of their time in integration, this more than pays for itself as integration occurs in tiny increments continuously.</p><p /><p>Most of the downsides (larger repo size, tons of \u201csuperfluous\u201d artifacts, longer CI times) can actually be mitigated by better infrastructure.\u00a0 I\u2019m not aware of any such \u201cshort-cuts\u201d for integration as a whole, other than simply doing it frequently and often.\u00a0 <a href=\"https://github.blog/open-source/git/bring-your-monorepo-down-to-size-with-sparse-checkout/\" class=\"external-link\" rel=\"nofollow\"><u>Sparse clones</u></a> can be leveraged to clone only a small portion of the repository.\u00a0 <a href=\"https://github.com/Tinder/bazel-diff\" class=\"external-link\" rel=\"nofollow\"><u>Bazel</u></a> (if used) can query a set of build targets to determine which are affected by a given git diff.\u00a0 Robot software can be updated as deltas to avoid needing to schlepp multi-GB disk images around.\u00a0 Large non-code assets can be stored in some sort of content-addressable bucket in S3 (addressed by hash) if Git LFS becomes too cumbersome.</p><p /><p>Note that the decision to use a monorepo has nothing to do with which modules we choose to have - only that these modules are versioned together in the same repository.\u00a0 In order to keep the monorepo manageable, it will still be important to layout the repo to ensure that sparse clones and selective CI testing are viable.\u00a0 A monorepo will punish you for poor organization.</p><h2 id=\"IntegrationandtheMonorepo-\ud83d\udd12VersionEverything\">\ud83d\udd12 Version <em>Everything</em></h2><p>The scope of what should be versioned in this repo should include as much as possible.\u00a0 Not just the source code or the artifacts built from that code, but the entire root filesystem, all of the various 3rd party dependencies, drivers, kernels and even the bootloaders would ideally be versioned by a single commit.</p><p /><p>When the whole stack - firmware, infrastructure code, dependencies - is under unified version control in a monorepo, the state of the system is explicit and fully reproducible. This clarity allows a large team to share limited hardware efficiently, since you no longer worry about mismatched dependencies or stale builds causing conflicts. Instead of managing scattered, fragile setups across multiple environments, each developer confidently deploys a known-good version, maximizing hardware utilization and minimizing downtime or debugging overhead.</p><p /><p>The confidence that you gain in deploying this way means\u00a0 you can focus on the real work, rather than wasting time on setup and managing dependencies/configuration.\u00a0 It also means that we can trivially trace our collected datasets to a single set of artifacts which produced the data.\u00a0\u00a0</p><h2 id=\"IntegrationandtheMonorepo-\ud83d\udd01DevelopmentFlow\">\ud83d\udd01 Development Flow</h2><ul><li><p><strong>Trunk-based development</strong> on <code>main</code></p></li><li><p><strong>Feature</strong> <strong>branches off main </strong>(<code>feature/short-description</code>)</p></li><li><p><strong>Squash/Rebase on trunk</strong>, no merge commits</p></li><li><p><strong>Release branches</strong> (<code>release/x.y</code>)</p></li><li><p><strong>Hotfixes</strong> should be applied to both release and trunk (this can be automated)</p></li></ul><p>Each commit that lands on trunk or a release branch must be green. Each build can be traced back to a <strong>single SHA</strong> that defines the system state across all layers.</p><p /><p>PRs should be<strong> squashed and rebased</strong>, which ensures that the history of the commits on the trunk reflect tested/gated changes rather than intermediate commits.\u00a0 It's difficult to enforce rules like every commit should build clean without otherwise blowing up CI costs (running CI for every commit in the PR) or trusting developers to run CI locally for every commit, and having a linear history makes bisecting to track down tricky bugs in the future much simpler.</p><h2 id=\"IntegrationandtheMonorepo-\u2699\ufe0fContinuousIntegration\"><strong>\u2699\ufe0f Continuous Integration</strong></h2><h3 id=\"IntegrationandtheMonorepo-\u2705OnEveryPR\"><strong>\u2705 On Every PR</strong></h3><ul><li><p><strong>Lint everything, always</strong> (fast, automatic, enforced)</p></li><li><p><strong>Incremental testing</strong> runs only affected builds/tests</p><ul><li><p>Changed ROS node? Run its integration tests.</p></li><li><p>Changed TF? Run <code>terraform plan</code>.</p></li><li><p>Changed models/weights? Run evals.</p></li><li><p>Changed URDF or CAD?\u00a0 Run sim.</p></li></ul></li><li><p>Goal is to gate PRs by tests impacted by the change.</p></li></ul><h3 id=\"IntegrationandtheMonorepo-\ud83c\udf19NightlyBuilds(midnightUTC/00:00Z)\"><strong>\ud83c\udf19 Nightly Builds (midnight UTC / 00:00Z)</strong></h3><ul><li><p>Tag the latest commit, and kick off a full build (non-incremental) including all tests</p></li><li><p>Potentially include more expensive evals or simulation that are not feasible for gating PRs</p></li><li><p>When appropriate, a nightly may be selected as a release candidate build.</p></li><li><p>It may be worth building the tip of main more frequently than every 24 hours, depending on how large the gap gets between PR test coverage and nightly test coverage.</p></li></ul><p>In order to keep PR test times manageable, we may run a smaller subset of tests.\u00a0 This means that occasionally issues may slip through resulting in a broken nightly.\u00a0 Teams should respond urgently to fix these issues to ensure no one else is blocked on broken builds (and ideally any identified holes in the PR CI process should be patched).</p><p>The idea is to strike a balance where feature branches can be merged quickly into main and integrated (long tests means huge merge queue times and lots of rebasing), and ensuring that our integrated code is tested as thoroughly as possible.\u00a0\u00a0</p><h2 id=\"IntegrationandtheMonorepo-\ud83d\udce6Releasing\"><strong>\ud83d\udce6 </strong>Releasing</h2><p>To create a release, a \u201crelease manager\u201d should tag and branch off a commit on <code>main</code>.\u00a0 The release branch should be <code>release/$version</code> and the tag $version.\u00a0 Any PR against a release branch (as opposed to <code>main</code>) may trigger a different set of release-gating tests, and merging a PR into a release branch should automatically open a PR into main with the same changes (which may need to have conflicts resolved or other modifications before being merged).</p><p /><p>All changes to a release branch should be approved by a release manager.</p><h2 id=\"IntegrationandtheMonorepo-\u2049\ufe0fCommonConcerns\">\u2049\ufe0f Common Concerns</h2><p><strong>&quot;Won\u2019t this slow teams down?&quot;</strong><br/>Only if you don\u2019t count integration as part of your timeline.</p><p><strong>&quot;What if I just want to work on my piece?&quot;</strong><br/>You can. You own your modules. But once it lands on the trunk, it has to <em>work with the rest of the system</em>. That\u2019s not overhead - it\u2019s the entire point.</p><p><strong>&quot;Does this remove team autonomy?&quot;</strong><br/>No. It replaces implicit, fragile team autonomy with <strong>explicit coordination</strong>, tracked by Git and tested by CI.</p><p><strong>&quot;What if we need long-lived experiments?&quot;</strong><br/>Branch away. Pin infra.\u00a0 Comment out all the tests on your branch.\u00a0 But when it's time to ship, it goes through the same path as everything else: trunk \u2192 release \u2192 artifact.</p><p />"
        },
        {
          "id": "1004666903",
          "title": "Trunk-Based Development",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1004666903",
          "last_modified": "2025-07-24T12:28:43.349Z",
          "created_at": "2025-07-24T08:56:50.987Z",
          "body_html": "<p><a href=\"https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1005027354/1+Integration+and+the+Monorepo?atlOrigin=eyJpIjoiZGVlMzg2Yzk4OWNhNGE1OTkxOWYxOTc5OGY5MjA1MDgiLCJwIjoiYyJ9\" rel=\"nofollow\">Our monorepo</a> provides a single commit to version our entire stack from platform to application (and eventually may include cloud infra as well).\u00a0 This drastically simplifies integration, but there are still some challenges that need to be addressed in order to ship code effectively.\u00a0 Having multiple platforms and multiple applications all being developed in one place and needing to be released at different times at different levels of maturity is a major challenge.\u00a0\u00a0</p><p>We\u2019ll try to address this with a few principles:</p><ul><li><p><strong>Never break the build</strong> - every commit on main should be deployable.\u00a0 If your change is dead-on-arrival, <em>you have failed</em>.</p></li><li><p><strong>Branches should be short-lived</strong> - merge pain grows quickly with branch lifetimes.</p></li><li><p><strong>Release late</strong> - do the bulk of the work on main, release as late as possible for stabilization.</p></li><li><p><strong>Commit incrementally</strong> - extensive use of feature flags allows long-running research efforts to be integrated before they are complete, minimizing merge pain.</p></li></ul><h2 id=\"Trunk-BasedDevelopment-\ud83c\udf33TheTrunk\">\ud83c\udf33 The Trunk</h2><p>The trunk (our main branch) is the single source of truth for the state of the system.\u00a0 It captures all dependencies and all integrations across all supported platforms and applications.\u00a0 It is much cheaper to keep all of this constantly updated through small, frequent changes than to attempt to release and track compatibility across a matrix of platform variations, demos, PoCs, etc.\u00a0\u00a0</p><p>When developers want to create new functionality or make changes to the code, it's often necessary to branch off the trunk to provide a \u201csafe space\u201d to make these changes without impacting others.\u00a0 Some more extreme variations of Trunk-based development insist on developers committing everything directly to main (not unlike older non-distributed VCS like perforce or CVS), but the GitHub PR workflow provides a lot of additional benefits around reviews and CI that we should want to keep in place.</p><p>Ideally, every single commit on the trunk should be deployable.\u00a0 It should always be possible to load the latest commit from the main branch onto a robot to see the latest and greatest changes.\u00a0 Of course this requires extensive investment in CI and automated testing, <strong>but this is the goal</strong>.\u00a0 A compromise is that \u201cthe happy path\u201d should always work.\u00a0 What this means is that you should be able to load up a build and perform normal, expected behaviors without any major issues.\u00a0 There may be edge-cases or regressions in some areas that are under-tested, but a developer who merges code which is dead-on-arrival has broken the contract and brings great shame upon themselves.\u00a0 These breaking changes should be reverted immediately and fixed as soon as possible to keep the trunk healthy for everyone.</p><h2 id=\"Trunk-BasedDevelopment-\ud83d\udd25TheHellishnessofLong-LivedBranches\">\ud83d\udd25 The Hellishness of Long-Lived Branches</h2><p>Every branch is a liability, accruing interest over time.\u00a0 When you have a branch, every other developer at the company becomes a liability as they merge changes and update dependencies, increasing the amount of work you need to do to \u201cfinish\u201d your branch and merge back to main.\u00a0 To every other developer, your branch is a ticking time bomb, accumulating changes that they aren\u2019t aware of that may cause issues with their own changes.\u00a0 For these reasons, branches should live for as short a time as possible.\u00a0 Generally speaking, the more \u201ccentral\u201d the changes are (the more of the system impacted), the shorter the branch should exist to reduce merge issues and deferred/accumulated integration costs.</p><p>Another way to think about this is that when you have a branch, you\u2019re the only one responsible for keeping that branch up-to-date.\u00a0 When you merge to main, you effectively have a contract with the org that this addition is to be supported by everyone (no one is allowed to break the build after all).\u00a0 For this reason, developers should be incentivized to merge their branches within hours or days rather than weeks - even if that work is incomplete (which we\u2019ll cover shortly).</p><p>These short branch-cycles improve the velocity, reduce merge-related overhead and serve as effective communication within the team about who is making what changes.\u00a0 Small changes, rapid integration.</p><h2 id=\"Trunk-BasedDevelopment-\ud83d\udee0\ufe0fStabilization:RealityCheck\">\ud83d\udee0\ufe0f Stabilization: Reality Check</h2><p>In an ideal world, trunk commits could instantly deploy everywhere. In reality, a little stabilization might be necessary. \u201cLate branching\u201d from the trunk for releases ensures minimal divergence. Hotfixes for stabilization should always land back into the trunk (and automation is your friend here).\u00a0 Late branching means that once the functionality has been merged into the main trunk, a release branch can be created strictly for stabilization/hotfixes.</p><p>When working to stabilize a release branch, PRs should simply be made against the release branch in git.\u00a0 When that PR is merged to the release branch (where presumably the stabilization is needed first), a second PR should be opened against main with the changes automatically.\u00a0 Depending on the nature of development, it\u2019s possible that the merge to main may have conflicts that didn\u2019t exist on the release branch.\u00a0 This new PR provides the space to resolve those conflicts with the team and get the improvements back to the trunk.</p><p>Work on a release branch should follow the same guidance as work on the trunk - short-lived branches and quick merges.\u00a0 These changes will be reflected on the trunk after-all, so making sure to break things up will ensure things merge more smoothly and keep overhead low.</p><h2 id=\"Trunk-BasedDevelopment-\ud83c\udf9a\ufe0fFeatureFlags:YourSecretWeaponforResearch\">\ud83c\udf9a\ufe0f Feature Flags: Your Secret Weapon for Research</h2><p>Sometimes, especially in research and infrastructure work, there are long-running efforts that can take months or even years to complete.\u00a0 This work should be broken up into reasonable increments and integrated regularly, even if incomplete.\u00a0 Ideally these incremental merges would be partially usable, but at a minimum they should be logically reviewable and testable.</p><p>This incomplete functionality can be behind a feature flag to protect the system from these incomplete changes.\u00a0 If you\u2019re working on a new policy, merge it behind a \u201cuse_fancy_new_policy\u201d flag which defaults to false.\u00a0 At some point in the future you can enable this flag when the feature is complete, and then set it as the new default and remove the configuration.</p><p>In addition to allowing incremental development and integration, these feature flags enable better data-driven development.\u00a0 You can toggle features within a single build and evaluate performance to get a better idea of the impact.\u00a0 This provides much better data than trying to compare two different builds with two different feature sets, as there could be many other confounding variables affecting the metrics.</p><h2 id=\"Trunk-BasedDevelopment-\u2049\ufe0fCommonConcerns\">\u2049\ufe0f Common Concerns</h2><p><strong>&quot;What if my fancy research effort takes 2-3 months?&quot;</strong></p><p>Use feature flags<strong>.</strong> Integrate early, hiding new functionality behind a flag, toggle off by default, and avoid integration nightmares later.</p><p><strong>&quot;What if I\u2019m re-writing our entire perception system?&quot;</strong></p><p>Embrace parallel development.\u00a0 Keep the old system intact and add the new system gradually in parallel behind feature flags.\u00a0 You\u2019ll want to do this anyway so you can properly compare and evaluate both systems within the same version of software to control for other variables.</p><p><strong>&quot;I need to prepare a customer PoC or demo - won\u2019t all these changes be risky?&quot;</strong></p><p>We should be writing tests to protect our core functionality, but obviously this isn\u2019t enough when days or weeks matter.\u00a0 A late release branch allows you to isolate functionality from the trunk-based churn, allowing you to focus on the demo without worrying about new changes (unless you want/need them)</p><p><strong>&quot;What about hotfixes - isn\u2019t this all complicated and messy?&quot;</strong></p><p>As part of stabilization, hotfixes will be made against release branches and with the power of GitHub automation we can automatically open PRs against main with these same fixes so we don\u2019t lose track.</p><p /><p />"
        },
        {
          "id": "1004732467",
          "title": "Move Fast and Merge Things",
          "url": "https://sklvc.atlassian.net/wiki/spaces/ROBOT/pages/1004732467",
          "last_modified": "2025-07-24T12:28:25.037Z",
          "created_at": "2025-07-24T08:54:53.384Z",
          "body_html": "<p>In robotics, speed is everything. But too often, code reviews become a bottleneck, slowing down the team and killing momentum. Here at Humanoid, we've<a href=\"https://sklvc.atlassian.net/wiki/pages/resumedraft.action?draftId=1004666903&amp;draftShareId=d6956c5e-bf9e-460d-a1b2-82f5c69b6556&amp;atlOrigin=eyJpIjoiZTQzYmZlZmY2OGQyNDk5Nzk2M2IyNTliNDg1YzM4YzAiLCJwIjoiYyJ9\" rel=\"nofollow\"><u> embraced trunk-based development</u></a> on <a href=\"https://sklvc.atlassian.net/wiki/pages/resumedraft.action?draftId=1005027354&amp;draftShareId=a5ebe065-af85-4317-b41a-1a7684e9770c&amp;atlOrigin=eyJpIjoiY2QzNDhhNGM5YjI3NGM4NzllYjgxMDgzZDlhMDk1ZGUiLCJwIjoiYyJ9\" rel=\"nofollow\"><u>a monorepo</u></a> precisely to avoid these pitfalls.</p><h2 id=\"MoveFastandMergeThings-\u26a1KeepItShort\"><strong>\u26a1 Keep It Short</strong></h2><p>Branches are like fresh produce: great when fresh, trouble if they linger. The longer a branch exists, the bigger the headaches when it merges. So make branches short-lived. Every branch merged quickly means fewer conflicts, less stale code, and happier developers.</p><p>Part of keeping branch lifetimes short is making sure PRs are reviewed in a timely manner.\u00a0 We need to weigh the benefits of being strict in our reviews with the costs of delaying progress and extending branch lifetimes.</p><h2 id=\"MoveFastandMergeThings-\ud83e\udd16TrustCI\"><strong>\ud83e\udd16 Trust CI</strong></h2><p>Our automated CI pipeline is the first and most thorough reviewer. It checks tests, lints code, verifies builds, and catches the vast majority of potential issues. Trust it. Let automation set you free. Human reviewers aren't there to nitpick code style or enforce trivial rules. Your CI should be ruthless so your reviewers don\u2019t have to be.</p><p>If your style quibbles cannot be covered by formatting or linting rules, they aren\u2019t worth enforcing.</p><h2 id=\"MoveFastandMergeThings-\ud83d\udea7Guardrails,NotGates\"><strong>\ud83d\udea7 Guardrails, Not Gates</strong></h2><p>Human code reviewers act as guardrails, not gates. They protect the repo from genuinely scary problems - huge, breaking changes, accidental disabling of tests, security pitfalls or safety-related issues. Reviews should be quick sanity checks, not perfectionist deep dives. If reviewers start obsessing over every line of code, something's gone wrong (and code is not being shipped).</p><p>That said - if you identify patterns or longer-term problems accumulating, it's worth bringing these to the team.\u00a0 But consider whether or not these concerns should block the immediate changes being made.</p><h2 id=\"MoveFastandMergeThings-\ud83d\udce3CommunicationOverPerfection\"><strong>\ud83d\udce3 Communication Over Perfection</strong></h2><p>Code reviews are also about visibility. Reviewing code forces developers to see what's changing, improving team-wide awareness and helping everyone understand the state of the project. Perfection isn't the goal - awareness is.</p><p>We also probably can't rely only on automated GitHub notifications to summon reviewers.\u00a0 These will be noisy and likely increasingly ignored.\u00a0 A fundamental challenge here is the bystander effect - if everyone can review, who is going to take the action to do so?</p><p>This requires a culture shift where everyone wants to see things reviewed and merged faster.\u00a0 Developers should advertise their ready-to-merge PRs in relevant slack channels, and it should be expected that one or more reviews would be received.\u00a0 Developers should be incentivized to take part in this process because they will benefit when it is their turn to have a PR reviewed.</p><h2 id=\"MoveFastandMergeThings-\ud83e\uddd1\u200d\u2696\ufe0fAIDisclosureandResponsibility\"><strong>\ud83e\uddd1\u200d\u2696\ufe0fAI Disclosure and Responsibility</strong></h2><p>While we obviously encourage AI tooling, it\u2019s important to disclose that your PR was authored with AI tools.\u00a0 In addition, you as the creator of a PR are solely responsible for any AI-generated code.\u00a0 Disclosure is important since the types of mistakes and trickery that an AI coding agent may make can be quite different and surprising, and so reviewers should be made aware up front.</p><h2 id=\"MoveFastandMergeThings-\ud83d\udea8MergeandMoveForward\"><strong>\ud83d\udea8 Merge and Move Forward</strong></h2><p>Don\u2019t hold code hostage in endless review loops. Better to merge fast and fix quickly in small follow-up PRs than strive for perfection before merging. Incremental, rapid iterations keep momentum high, frustration low, and innovation flowing.</p><p>At the end of the day, our philosophy is simple: trust CI, trust your teammates, and keep moving forward. Velocity is your friend, perfection is the enemy, and momentum is everything.</p><p />"
        }
      ]
    }
  },
  "wan": {
    "sites": {
      "lab": {
        "site_desc": null,
        "networks": [],
        "vpn_tunnels": [],
        "devices": []
      },
      "1-triton": {
        "gw_cpu": 4.2,
        "gw_mem": 29.9,
        "wan_latency": 1,
        "wan_availability": 100.0,
        "internet_latency": 1,
        "vpn_status": "error",
        "site_desc": "Default",
        "networks": [
          {
            "name": "hmnd-native",
            "subnet": "192.168.1.0/24",
            "gateway": "192.168.1.1",
            "vlan": null,
            "enabled": true
          },
          {
            "name": "hmnd-infra",
            "subnet": "10.10.60.0/23",
            "gateway": "10.10.60.1",
            "vlan": 60,
            "enabled": true
          },
          {
            "name": "hmnd-humans",
            "subnet": "10.10.40.0/23",
            "gateway": "10.10.40.1",
            "vlan": 40,
            "enabled": true
          },
          {
            "name": "hmnd-iot",
            "subnet": "10.10.70.0/24",
            "gateway": "10.10.70.1",
            "vlan": 70,
            "enabled": true
          },
          {
            "name": "hmnd-strangers",
            "subnet": "10.10.90.0/24",
            "gateway": "10.10.90.1",
            "vlan": 90,
            "enabled": true
          },
          {
            "name": "hmnd-madness",
            "subnet": "10.10.80.0/24",
            "gateway": "10.10.80.1",
            "vlan": 80,
            "enabled": true
          },
          {
            "name": "hmnd-robots",
            "subnet": "10.10.50.0/23",
            "gateway": "10.10.50.1",
            "vlan": 50,
            "enabled": true
          },
          {
            "name": "hmnd-alpha",
            "subnet": "10.10.100.0/24",
            "gateway": "10.10.100.1",
            "vlan": 100,
            "enabled": true
          },
          {
            "name": "hmnd-corp",
            "subnet": "10.10.30.0/23",
            "gateway": "10.10.30.1",
            "vlan": 30,
            "enabled": true
          },
          {
            "name": "hmnd-mgmt",
            "subnet": "10.10.10.0/24",
            "gateway": "10.10.10.1",
            "vlan": 10,
            "enabled": true
          },
          {
            "name": "hmnd-experiments",
            "subnet": "10.10.250.0/24",
            "gateway": "10.10.250.1",
            "vlan": 250,
            "enabled": true
          }
        ],
        "vpn_tunnels": [
          {
            "name": "London Lab",
            "enabled": true,
            "ipsec_peer_addr": null,
            "ipsec_local_ip": null,
            "ipsec_profile": null,
            "ipsec_key_exchange": null,
            "ipsec_ike_version": null,
            "ipsec_esp_dh_group": null,
            "ipsec_dpd_enabled": null,
            "ipsec_dpd_interval": null,
            "remote_subnets": []
          },
          {
            "name": "Deploy 99 | Luke",
            "enabled": true,
            "ipsec_peer_addr": null,
            "ipsec_local_ip": null,
            "ipsec_profile": null,
            "ipsec_key_exchange": null,
            "ipsec_ike_version": null,
            "ipsec_esp_dh_group": null,
            "ipsec_dpd_enabled": null,
            "ipsec_dpd_interval": null,
            "remote_subnets": []
          },
          {
            "name": "hmnd-aws-1",
            "enabled": true,
            "ipsec_peer_addr": null,
            "ipsec_local_ip": "165.65.48.198",
            "ipsec_profile": null,
            "ipsec_key_exchange": "ikev2",
            "ipsec_ike_version": null,
            "ipsec_esp_dh_group": 14,
            "ipsec_dpd_enabled": null,
            "ipsec_dpd_interval": null,
            "remote_subnets": []
          },
          {
            "name": "hmnd-aws-2",
            "enabled": true,
            "ipsec_peer_addr": null,
            "ipsec_local_ip": "165.65.48.198",
            "ipsec_profile": null,
            "ipsec_key_exchange": "ikev2",
            "ipsec_ike_version": null,
            "ipsec_esp_dh_group": 14,
            "ipsec_dpd_enabled": null,
            "ipsec_dpd_interval": null,
            "remote_subnets": []
          }
        ],
        "gw_name": "1 Triton",
        "gw_model": "UDMEA4B",
        "gw_version": "5.1.19.33549",
        "gw_uptime": 2581144,
        "gw_temp_cpu": 39.437,
        "wan_rx_bytes": 6098010567055,
        "wan_tx_bytes": 5716080457382,
        "wan_speed": 10000,
        "wan_rx_24h": 720444974368.7908,
        "wan_tx_24h": 1007517684017.4651,
        "devices": [
          {
            "type": "usw",
            "name": "ECS 48 PoE | 4",
            "model": "USWF069",
            "serial": "8CEDE1C238EF",
            "mac": "8c:ed:e1:c2:38:ef",
            "ip": "10.10.10.10",
            "version": "7.4.1.16850",
            "uptime": 2830784,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 6",
            "model": "USWF069",
            "serial": "8CEDE1C23ADE",
            "mac": "8c:ed:e1:c2:3a:de",
            "ip": "10.10.10.217",
            "version": "7.4.1.16850",
            "uptime": 869641,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "usw",
            "name": "USW Pro Max 16 PoE | 18 (Desk)",
            "model": "USPM16P",
            "serial": "1C6A1B684E64",
            "mac": "1c:6a:1b:68:4e:64",
            "ip": "10.10.10.183",
            "version": "7.4.1.16850",
            "uptime": 785227,
            "state": 1,
            "adopted": true,
            "num_port": 18,
            "poe_power": 180,
            "uplink_mac": "8c:ed:e1:c2:3b:15",
            "uplink_name": "ECS 48 PoE | 15"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 15",
            "model": "USWF069",
            "serial": "8CEDE1C23B15",
            "mac": "8c:ed:e1:c2:3b:15",
            "ip": "10.10.10.128",
            "version": "7.4.1.16850",
            "uptime": 1882325,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:e5:d2",
            "uplink_name": "ECS Aggregation North"
          },
          {
            "type": "uap",
            "name": "E7 | Office (Middle Rear)",
            "model": "UAPA697",
            "serial": "8CEDE100EF2D",
            "mac": "8c:ed:e1:00:ef:2d",
            "ip": "10.10.10.160",
            "version": "8.6.11.18870",
            "uptime": 652521,
            "state": 1,
            "adopted": true,
            "num_sta": 6,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 1,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 149,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 37,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:37:6e",
            "uplink_name": "ECS 48 PoE | 14"
          },
          {
            "type": "usw",
            "name": "UPS Tower",
            "model": "USWDA24",
            "serial": "1C0B8B3C157B",
            "mac": "1c:0b:8b:3c:15:7b",
            "ip": "10.10.10.71",
            "version": "1.5.0.378",
            "uptime": 573879,
            "state": 1,
            "adopted": true,
            "num_port": 1,
            "uplink_mac": "84:78:48:5c:84:e1",
            "uplink_name": "ECS 24 PoE | 16 (Demo DC Lab) "
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 5",
            "model": "USWF069",
            "serial": "8CEDE1C23DE0",
            "mac": "8c:ed:e1:c2:3d:e0",
            "ip": "10.10.10.57",
            "version": "7.4.1.16850",
            "uptime": 1184016,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "udm",
            "name": "1 Triton",
            "model": "UDMEA4B",
            "serial": "A89C6CF4D2B8",
            "mac": "a8:9c:6c:f4:d2:b8",
            "ip": "165.65.48.198",
            "version": "5.1.19.33549",
            "uptime": 2581148,
            "state": 1,
            "adopted": true,
            "temp_cpu": 39.375,
            "uplink_mac": "8c:ed:e1:c2:3c:5f",
            "uplink_name": "ECS 48 PoE | 11 Artum"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-11 Cab",
            "model": "UAPA6BA",
            "serial": "9041B25243B0",
            "mac": "90:41:b2:52:43:b0",
            "ip": "10.10.10.253",
            "version": "8.6.11.18870",
            "uptime": 1035025,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 104,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 41,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3c:5f",
            "uplink_name": "ECS 48 PoE | 11 Artum"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 11 Artum",
            "model": "USWF069",
            "serial": "8CEDE1C23C5F",
            "mac": "8c:ed:e1:c2:3c:5f",
            "ip": "10.10.10.65",
            "version": "7.4.1.16850",
            "uptime": 2225836,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "a8:9c:6c:f4:d2:b8",
            "uplink_name": "1 Triton"
          },
          {
            "type": "uap",
            "name": "E7 | CEO (Right - Desk)",
            "model": "UAPA697",
            "serial": "8CEDE100D41D",
            "mac": "8c:ed:e1:00:d4:1d",
            "ip": "10.10.10.107",
            "version": "8.6.11.18870",
            "uptime": 1035261,
            "state": 1,
            "adopted": true,
            "num_sta": 2,
            "satisfaction": 98,
            "radios": [
              {
                "band": "ng",
                "channel": 1,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 64,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 29,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3c:5f",
            "uplink_name": "ECS 48 PoE | 11 Artum"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | NE SER",
            "model": "UAPA6BA",
            "serial": "9041B2525D38",
            "mac": "90:41:b2:52:5d:38",
            "ip": "10.10.10.58",
            "version": "8.6.11.18870",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": null,
            "radios": [
              {
                "band": "na",
                "channel": 120,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": "auto",
                "ht": "20"
              },
              {
                "band": "ng",
                "channel": 5,
                "ht": "20"
              }
            ],
            "uplink_mac": "84:78:48:5a:39:8c",
            "uplink_name": "ECS 24 PoE | NE | MGMT "
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-4 Cab",
            "model": "UAPA6BA",
            "serial": "9041B25247F4",
            "mac": "90:41:b2:52:47:f4",
            "ip": "10.10.10.22",
            "version": "8.6.11.18870",
            "uptime": 1183289,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 13,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 161,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 77,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:38:ef",
            "uplink_name": "ECS 48 PoE | 4"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-6 Cab",
            "model": "UAPA6BA",
            "serial": "9041B2524458",
            "mac": "90:41:b2:52:44:58",
            "ip": "10.10.10.28",
            "version": "8.6.11.18870",
            "uptime": 771164,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 11,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 64,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 85,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3a:de",
            "uplink_name": "ECS 48 PoE | 6"
          },
          {
            "type": "uap",
            "name": "E7 | Build Lab (front middle)",
            "model": "UAPA697",
            "serial": "8CEDE100CF25",
            "mac": "8c:ed:e1:00:cf:25",
            "ip": "10.10.10.53",
            "version": "8.6.11.18870",
            "uptime": 771186,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 7,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 157,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 57,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3a:de",
            "uplink_name": "ECS 48 PoE | 6"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-2 Cab",
            "model": "UAPA6BA",
            "serial": "9041B2524BFC",
            "mac": "90:41:b2:52:4b:fc",
            "ip": "10.10.10.230",
            "version": "8.6.11.18870",
            "uptime": 235928,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 124,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 49,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:30:66:94:40:92",
            "uplink_name": "USW Pro XG 24 PoE | 2 | Replacement"
          },
          {
            "type": "uap",
            "name": "E7 | Build (Rear Right)",
            "model": "UAPA697",
            "serial": "8CEDE100EDD9",
            "mac": "8c:ed:e1:00:ed:d9",
            "ip": "10.10.10.108",
            "version": "8.6.11.18870",
            "uptime": 1175630,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 7,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 136,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 65,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3e:f3",
            "uplink_name": "ECS 48 PoE | 7"
          },
          {
            "type": "usw",
            "name": "ECS 24 PoE | SW | MGMT | 1",
            "model": "USWF067",
            "serial": "8478485A36D4",
            "mac": "84:78:48:5a:36:d4",
            "ip": "10.10.10.54",
            "version": "7.4.1.16850",
            "uptime": 3006272,
            "state": 1,
            "adopted": true,
            "num_port": 26,
            "poe_power": 1050,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "uap",
            "name": "E7 | Eng Lab (Front)",
            "model": "UAPA697",
            "serial": "8CEDE100D645",
            "mac": "8c:ed:e1:00:d6:45",
            "ip": "10.10.10.123",
            "version": "8.6.11.18870",
            "uptime": 1024921,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 4,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 157,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 61,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3b:83",
            "uplink_name": "ECS 48 PoE | 12"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-15 Cab",
            "model": "UAPA6BA",
            "serial": "9041B2524510",
            "mac": "90:41:b2:52:45:10",
            "ip": "10.10.10.70",
            "version": "8.6.11.18870",
            "uptime": 757201,
            "state": 1,
            "adopted": true,
            "num_sta": 3,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 11,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 136,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 61,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3b:15",
            "uplink_name": "ECS 48 PoE | 15"
          },
          {
            "type": "uap",
            "name": "E7 | Office (Middle Front)",
            "model": "UAPA697",
            "serial": "1C0B8B00463D",
            "mac": "1c:0b:8b:00:46:3d",
            "ip": "10.10.10.243",
            "version": "8.6.11.18870",
            "uptime": 485211,
            "state": 1,
            "adopted": true,
            "num_sta": 10,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 6,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 40,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 89,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:37:6e",
            "uplink_name": "ECS 48 PoE | 14"
          },
          {
            "type": "uap",
            "name": "E7 | Creative",
            "model": "UAPA697",
            "serial": "1C0B8B0047C5",
            "mac": "1c:0b:8b:00:47:c5",
            "ip": "10.10.10.242",
            "version": "8.6.11.18870",
            "uptime": 91181,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 128,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 37,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3e:f3",
            "uplink_name": "ECS 48 PoE | 7"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 8",
            "model": "USWF069",
            "serial": "8CEDE1C23994",
            "mac": "8c:ed:e1:c2:39:94",
            "ip": "10.10.10.31",
            "version": "7.4.1.16850",
            "uptime": 2245898,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "uap",
            "name": "E7 | Eng Lab (Middle Front NL3 )",
            "model": "UAPA697",
            "serial": "8CEDE100F459",
            "mac": "8c:ed:e1:00:f4:59",
            "ip": "10.10.10.16",
            "version": "8.6.11.18870",
            "uptime": 1035244,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 165,
                "ht": 20
              },
              {
                "band": "6e",
                "channel": "auto",
                "ht": 20
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3c:5f",
            "uplink_name": "ECS 48 PoE | 11 Artum"
          },
          {
            "type": "uap",
            "name": "E7 | Eng Lab (Left Front)",
            "model": "UAPA697",
            "serial": "8CEDE100ED1D",
            "mac": "8c:ed:e1:00:ed:1d",
            "ip": "10.10.10.168",
            "version": "8.6.11.18870",
            "uptime": 1116056,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 96,
            "radios": [
              {
                "band": "ng",
                "channel": 1,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 144,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 65,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:39:cb",
            "uplink_name": "ECS 48 PoE | 9"
          },
          {
            "type": "usw",
            "name": "UPS Tower | 16 ",
            "model": "USWDA24",
            "serial": "1C0B8B3C1425",
            "mac": "1c:0b:8b:3c:14:25",
            "ip": "10.10.10.121",
            "version": "1.5.0.378",
            "uptime": 918607,
            "state": 1,
            "adopted": true,
            "num_port": 1,
            "uplink_mac": "84:78:48:5c:84:e1",
            "uplink_name": "ECS 24 PoE | 16 (Demo DC Lab) "
          },
          {
            "type": "uap",
            "name": "E7 | Office (Right Front)",
            "model": "UAPA697",
            "serial": "8CEDE100D40D",
            "mac": "8c:ed:e1:00:d4:0d",
            "ip": "10.10.10.91",
            "version": "8.6.11.18870",
            "uptime": 485238,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 95,
            "radios": [
              {
                "band": "ng",
                "channel": 4,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 108,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 53,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3b:15",
            "uplink_name": "ECS 48 PoE | 15"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 14",
            "model": "USWF069",
            "serial": "8CEDE1C2376E",
            "mac": "8c:ed:e1:c2:37:6e",
            "ip": "10.10.10.18",
            "version": "7.4.1.16850",
            "uptime": 1884407,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:e5:d2",
            "uplink_name": "ECS Aggregation North"
          },
          {
            "type": "usw",
            "name": "UPS Tower",
            "model": "USWDA24",
            "serial": "1C0B8B3C1589",
            "mac": "1c:0b:8b:3c:15:89",
            "ip": "10.10.10.84",
            "version": "1.5.0.378",
            "uptime": 573977,
            "state": 1,
            "adopted": true,
            "num_port": 1,
            "uplink_mac": "84:78:48:5c:84:e1",
            "uplink_name": "ECS 24 PoE | 16 (Demo DC Lab) "
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-12 Cab",
            "model": "UAPA6BA",
            "serial": "9041B2524AC8",
            "mac": "90:41:b2:52:4a:c8",
            "ip": "10.10.10.66",
            "version": "8.6.11.18870",
            "uptime": 1033187,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 8,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 128,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 53,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3b:83",
            "uplink_name": "ECS 48 PoE | 12"
          },
          {
            "type": "uap",
            "name": "E7 Campus | Float",
            "model": "UAPA6B1",
            "serial": "8C3066A2D8C7",
            "mac": "8c:30:66:a2:d8:c7",
            "ip": "192.168.1.209",
            "version": "8.6.11.18870",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": null,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": "auto",
                "ht": 80
              },
              {
                "band": "na",
                "channel": "auto",
                "ht": 80
              }
            ],
            "uplink_mac": "84:78:48:5a:3c:61",
            "uplink_name": "ECS 24 PoE | SW | 1"
          },
          {
            "type": "uap",
            "name": "E7 | Build Lab (Rear Middle)",
            "model": "UAPA697",
            "serial": "8CEDE100E4C5",
            "mac": "8c:ed:e1:00:e4:c5",
            "ip": "10.10.10.76",
            "version": "8.6.11.18870",
            "uptime": 309061,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 10,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 104,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 9,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3a:de",
            "uplink_name": "ECS 48 PoE | 6"
          },
          {
            "type": "uap",
            "name": "E7 | Board Room (left)",
            "model": "UAPA697",
            "serial": "8CEDE100D569",
            "mac": "8c:ed:e1:00:d5:69",
            "ip": "10.10.10.46",
            "version": "8.6.11.18870",
            "uptime": 309048,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 7,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 52,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 65,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3c:5f",
            "uplink_name": "ECS 48 PoE | 11 Artum"
          },
          {
            "type": "uacc",
            "name": "AirWire",
            "model": "UAPEA07",
            "serial": "A89C6CA074C8",
            "mac": "a8:9c:6c:a0:74:c8",
            "ip": "",
            "version": "8.5.21.18681",
            "uptime": 0,
            "state": 2,
            "adopted": true,
            "uplink_mac": null,
            "uplink_name": null
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-10 Cab",
            "model": "UAPA6BA",
            "serial": "9041B2525E74",
            "mac": "90:41:b2:52:5e:74",
            "ip": "10.10.10.229",
            "version": "8.6.11.18870",
            "uptime": 2571106,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 5,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 136,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 81,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3e:4e",
            "uplink_name": "ECS 48 PoE | 10"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-1 Cab",
            "model": "UAPA6BA",
            "serial": "9041B2525070",
            "mac": "90:41:b2:52:50:70",
            "ip": "10.10.10.151",
            "version": "8.6.11.18870",
            "uptime": 220434,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 95,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 100,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 93,
                "ht": "20"
              }
            ],
            "uplink_mac": "1c:0b:8b:08:d7:b3",
            "uplink_name": "USW Pro XG 8 PoE | 1 Replacement"
          },
          {
            "type": "uap",
            "name": "E7 | Eng Lab (Front)",
            "model": "UAPA697",
            "serial": "8CEDE100E575",
            "mac": "8c:ed:e1:00:e5:75",
            "ip": "10.10.10.109",
            "version": "8.6.11.18870",
            "uptime": 485201,
            "state": 1,
            "adopted": true,
            "num_sta": 3,
            "satisfaction": 97,
            "radios": [
              {
                "band": "ng",
                "channel": 12,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 116,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 29,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3e:4e",
            "uplink_name": "ECS 48 PoE | 10"
          },
          {
            "type": "uap",
            "name": "E7 | Kitchen",
            "model": "UAPA697",
            "serial": "1C0B8B0046ED",
            "mac": "1c:0b:8b:00:46:ed",
            "ip": "10.10.10.171",
            "version": "8.6.11.18870",
            "uptime": 219230,
            "state": 1,
            "adopted": true,
            "num_sta": 2,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 153,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 33,
                "ht": "20"
              }
            ],
            "uplink_mac": "90:41:b2:40:8a:0e",
            "uplink_name": "EAV XG 24 PoE | NE SER "
          },
          {
            "type": "uap",
            "name": "E7 | Phone Booth (middle)",
            "model": "UAPA697",
            "serial": "8CEDE100D5FD",
            "mac": "8c:ed:e1:00:d5:fd",
            "ip": "10.10.10.194",
            "version": "8.6.11.18870",
            "uptime": 1181932,
            "state": 1,
            "adopted": true,
            "num_sta": 8,
            "satisfaction": 98,
            "radios": [
              {
                "band": "ng",
                "channel": 3,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 120,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 45,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3a:de",
            "uplink_name": "ECS 48 PoE | 6"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | Meeting Room B",
            "model": "UAPA6BA",
            "serial": "9041B2524B40",
            "mac": "90:41:b2:52:4b:40",
            "ip": "10.10.10.41",
            "version": "8.6.11.18870",
            "uptime": 579806,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 1,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 48,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 45,
                "ht": "20"
              }
            ],
            "uplink_mac": "84:78:48:5a:3c:61",
            "uplink_name": "ECS 24 PoE | SW | Access | 1"
          },
          {
            "type": "usw",
            "name": "EAV XG 24 PoE | SW SER",
            "model": "USWF001",
            "serial": "9041B2408C6E",
            "mac": "90:41:b2:40:8c:6e",
            "ip": "10.10.10.89",
            "version": "7.5.2.16967",
            "uptime": 3005302,
            "state": 1,
            "adopted": true,
            "num_port": 29,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 13",
            "model": "USWF069",
            "serial": "8CEDE1C23C96",
            "mac": "8c:ed:e1:c2:3c:96",
            "ip": "10.10.10.120",
            "version": "7.4.1.16850",
            "uptime": 1124417,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:e5:d2",
            "uplink_name": "ECS Aggregation North"
          },
          {
            "type": "uap",
            "name": "E7 | Build Lab (Right Rear)",
            "model": "UAPA697",
            "serial": "8CEDE100EADD",
            "mac": "8c:ed:e1:00:ea:dd",
            "ip": "10.10.10.25",
            "version": "8.6.11.18870",
            "uptime": 333927,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 2,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 149,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 73,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:39:94",
            "uplink_name": "ECS 48 PoE | 8"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | Meet Room D",
            "model": "UAPA6BA",
            "serial": "9041B2524244",
            "mac": "90:41:b2:52:42:44",
            "ip": "10.10.10.33",
            "version": "8.6.11.18870",
            "uptime": 484789,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 11,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 132,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 81,
                "ht": "20"
              }
            ],
            "uplink_mac": "84:78:48:5a:3c:61",
            "uplink_name": "ECS 24 PoE | SW | Access | 1"
          },
          {
            "type": "uap",
            "name": "E7 Lift Lobby ",
            "model": "UAPA697",
            "serial": "8CEDE100E63D",
            "mac": "8c:ed:e1:00:e6:3d",
            "ip": "10.10.10.163",
            "version": "8.6.11.18870",
            "uptime": 219191,
            "state": 1,
            "adopted": true,
            "num_sta": 2,
            "satisfaction": 99,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 140,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 41,
                "ht": "20"
              }
            ],
            "uplink_mac": "90:41:b2:40:8a:0e",
            "uplink_name": "EAV XG 24 PoE | NE SER "
          },
          {
            "type": "usw",
            "name": "USW Flex 2.5G 8 PoE | 17 (3D Printers)",
            "model": "USWED37",
            "serial": "942A6FFE5357",
            "mac": "94:2a:6f:fe:53:57",
            "ip": "10.10.10.193",
            "version": "2.1.8.971",
            "uptime": 614720,
            "state": 1,
            "adopted": true,
            "num_port": 10,
            "poe_power": 76,
            "uplink_mac": "8c:ed:e1:c2:3b:83",
            "uplink_name": "ECS 48 PoE | 12"
          },
          {
            "type": "uap",
            "name": "E7 | Office (Left Front)",
            "model": "UAPA697",
            "serial": "8CEDE100F039",
            "mac": "8c:ed:e1:00:f0:39",
            "ip": "10.10.10.34",
            "version": "8.6.11.18870",
            "uptime": 253285,
            "state": 1,
            "adopted": true,
            "num_sta": 7,
            "satisfaction": 98,
            "radios": [
              {
                "band": "ng",
                "channel": 6,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 52,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 17,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3c:96",
            "uplink_name": "ECS 48 PoE | 13"
          },
          {
            "type": "uap",
            "name": "E7 | Reception",
            "model": "UAPA697",
            "serial": "8CEDE100BFDD",
            "mac": "8c:ed:e1:00:bf:dd",
            "ip": "10.10.10.189",
            "version": "8.6.11.18870",
            "uptime": 219751,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 116,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 25,
                "ht": "20"
              }
            ],
            "uplink_mac": "1c:0b:8b:08:d7:b3",
            "uplink_name": "USW Pro XG 8 PoE | 1 Replacement"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-5 Cab",
            "model": "UAPA6BA",
            "serial": "9041B25242F0",
            "mac": "90:41:b2:52:42:f0",
            "ip": "10.10.10.206",
            "version": "8.6.11.18870",
            "uptime": 1183836,
            "state": 1,
            "adopted": true,
            "num_sta": 2,
            "satisfaction": 97,
            "radios": [
              {
                "band": "ng",
                "channel": 7,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 100,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 61,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3d:e0",
            "uplink_name": "ECS 48 PoE | 5"
          },
          {
            "type": "usw",
            "name": "USW Flex 2.5G 8 PoE",
            "model": "USWED37",
            "serial": "8C3066CC78AE",
            "mac": "8c:30:66:cc:78:ae",
            "ip": "192.168.1.106",
            "version": "2.1.8.971",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "num_port": 10,
            "uplink_mac": "8c:ed:e1:c2:37:6e",
            "uplink_name": "ECS 48 PoE | 14"
          },
          {
            "type": "uap",
            "name": "E7 | Board Room (Right)",
            "model": "UAPA697",
            "serial": "8CEDE100D46D",
            "mac": "8c:ed:e1:00:d4:6d",
            "ip": "10.10.10.187",
            "version": "8.6.11.18870",
            "uptime": 1035328,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 8,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 153,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 85,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3c:5f",
            "uplink_name": "ECS 48 PoE | 11 Artum"
          },
          {
            "type": "uap",
            "name": "E7 | Demo DC Lab (Left Front)",
            "model": "UAPA697",
            "serial": "8CEDE100D261",
            "mac": "8c:ed:e1:00:d2:61",
            "ip": "10.10.10.200",
            "version": "8.6.11.18870",
            "uptime": 235949,
            "state": 1,
            "adopted": true,
            "num_sta": 6,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 3,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 132,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 25,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:30:66:94:40:92",
            "uplink_name": "USW Pro XG 24 PoE | 2 | Replacement"
          },
          {
            "type": "uap",
            "name": "E7 | NE SER",
            "model": "UAPA697",
            "serial": "8CEDE100E64D",
            "mac": "8c:ed:e1:00:e6:4d",
            "ip": "10.10.10.179",
            "version": "8.6.11.18870",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": null,
            "radios": [
              {
                "band": "6e",
                "channel": "auto",
                "ht": "20"
              },
              {
                "band": "ng",
                "channel": 13,
                "ht": "20"
              },
              {
                "band": "na",
                "channel": 64,
                "ht": "40"
              }
            ],
            "uplink_mac": "84:78:48:5a:39:8c",
            "uplink_name": "ECS 24 PoE | NE | MGMT "
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-9 Cab",
            "model": "UAPA6BA",
            "serial": "9041B2526130",
            "mac": "90:41:b2:52:61:30",
            "ip": "10.10.10.248",
            "version": "8.6.11.18870",
            "uptime": 2082533,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 9,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 56,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 17,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:39:cb",
            "uplink_name": "ECS 48 PoE | 9"
          },
          {
            "type": "uap",
            "name": "E7 | Office (Right Rear)",
            "model": "UAPA697",
            "serial": "8CEDE100E885",
            "mac": "8c:ed:e1:00:e8:85",
            "ip": "10.10.10.210",
            "version": "8.6.11.18870",
            "uptime": 757223,
            "state": 1,
            "adopted": true,
            "num_sta": 2,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 6,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 128,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 73,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3b:15",
            "uplink_name": "ECS 48 PoE | 15"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 7",
            "model": "USWF069",
            "serial": "8CEDE1C23EF3",
            "mac": "8c:ed:e1:c2:3e:f3",
            "ip": "10.10.10.188",
            "version": "7.4.1.16850",
            "uptime": 2314872,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "usw",
            "name": "USW Pro XG 24 PoE | 2 | Replacement",
            "model": "USWED44",
            "serial": "8C3066944092",
            "mac": "8c:30:66:94:40:92",
            "ip": "10.10.10.241",
            "version": "7.4.1.16850",
            "uptime": 236104,
            "state": 1,
            "adopted": true,
            "num_port": 26,
            "poe_power": 720,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "udb",
            "name": "UDB Switch | CDR ",
            "model": "UDBA69F",
            "serial": "8CEDE11C2E20",
            "mac": "8c:ed:e1:1c:2e:20",
            "ip": "10.10.10.88",
            "version": "8.5.21.18681",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "uplink_mac": "8c:ed:e1:c2:39:94",
            "uplink_name": "ECS 48 PoE | 8"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | Testing",
            "model": "UAPA6BA",
            "serial": "9041B252491C",
            "mac": "90:41:b2:52:49:1c",
            "ip": "10.10.10.32",
            "version": "8.6.11.18870",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": null,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 140,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 73,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3a:de",
            "uplink_name": "ECS 48 PoE | 6"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-8 Cab",
            "model": "UAPA6BA",
            "serial": "9041B2526064",
            "mac": "90:41:b2:52:60:64",
            "ip": "10.10.10.190",
            "version": "8.6.11.18870",
            "uptime": 2245342,
            "state": 1,
            "adopted": true,
            "num_sta": 2,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 13,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 48,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 1,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:39:94",
            "uplink_name": "ECS 48 PoE | 8"
          },
          {
            "type": "uap",
            "name": "E7 | Meeting Room A",
            "model": "UAPA697",
            "serial": "1C0B8B004745",
            "mac": "1c:0b:8b:00:47:45",
            "ip": "10.10.10.114",
            "version": "8.6.11.18870",
            "uptime": 606164,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 5,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 60,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 13,
                "ht": "20"
              }
            ],
            "uplink_mac": "84:78:48:5a:3c:61",
            "uplink_name": "ECS 24 PoE | SW | Access | 1"
          },
          {
            "type": "uap",
            "name": "E7 | Demo DC 1 (Left Middle)",
            "model": "UAPA697",
            "serial": "8CEDE100D3C1",
            "mac": "8c:ed:e1:00:d3:c1",
            "ip": "10.10.10.159",
            "version": "8.6.11.18870",
            "uptime": 167056,
            "state": 1,
            "adopted": true,
            "num_sta": 8,
            "satisfaction": 95,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 144,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 53,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:38:ef",
            "uplink_name": "ECS 48 PoE | 4"
          },
          {
            "type": "uap",
            "name": "E7 | Product Deployment",
            "model": "UAPA697",
            "serial": "1C0B8B005065",
            "mac": "1c:0b:8b:00:50:65",
            "ip": "10.10.10.158",
            "version": "8.6.11.18870",
            "uptime": 90196,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "6e",
                "channel": "auto",
                "ht": 20
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3e:f3",
            "uplink_name": "ECS 48 PoE | 7"
          },
          {
            "type": "uap",
            "name": "E7 | Demo DC (Gantry Middle)",
            "model": "UAPA697",
            "serial": "8CEDE100E599",
            "mac": "8c:ed:e1:00:e5:99",
            "ip": "10.10.10.143",
            "version": "8.6.11.18870",
            "uptime": 57114,
            "state": 1,
            "adopted": true,
            "num_sta": 2,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 52,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 85,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:30:66:94:40:92",
            "uplink_name": "USW Pro XG 24 PoE | 2 | Replacement"
          },
          {
            "type": "uap",
            "name": "E7 | Demo DC (Front Middle)",
            "model": "UAPA697",
            "serial": "8CEDE100D541",
            "mac": "8c:ed:e1:00:d5:41",
            "ip": "10.10.10.6",
            "version": "8.6.11.18870",
            "uptime": 1186641,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 12,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 128,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 65,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3d:a9",
            "uplink_name": "ECS 48 PoE | 3"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 3",
            "model": "USWF069",
            "serial": "8CEDE1C23DA9",
            "mac": "8c:ed:e1:c2:3d:a9",
            "ip": "10.10.10.251",
            "version": "7.4.1.16850",
            "uptime": 1190955,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "uap",
            "name": "E7 | Eng Lab (Right Front)",
            "model": "UAPA697",
            "serial": "8CEDE100CB25",
            "mac": "8c:ed:e1:00:cb:25",
            "ip": "10.10.10.103",
            "version": "8.6.11.18870",
            "uptime": 1095892,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 96,
            "radios": [
              {
                "band": "ng",
                "channel": 5,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 108,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 9,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:39:cb",
            "uplink_name": "ECS 48 PoE | 9"
          },
          {
            "type": "uap",
            "name": "E7 Audience | SW Plant Room",
            "model": "UAPA6AB",
            "serial": "847848A09809",
            "mac": "84:78:48:a0:98:09",
            "ip": "10.10.10.231",
            "version": "8.6.11.18870",
            "uptime": 605588,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "na",
                "channel": 124,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "6e",
                "channel": 17,
                "ht": "20"
              }
            ],
            "uplink_mac": "84:78:48:5a:3c:61",
            "uplink_name": "ECS 24 PoE | SW | Access | 1"
          },
          {
            "type": "uap",
            "name": "E7 | Build (Left Front)",
            "model": "UAPA697",
            "serial": "8CEDE100D691",
            "mac": "8c:ed:e1:00:d6:91",
            "ip": "10.10.10.198",
            "version": "8.6.11.18870",
            "uptime": 1174979,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 9,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 60,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 17,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:39:94",
            "uplink_name": "ECS 48 PoE | 8"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-7 Cab",
            "model": "UAPA6BA",
            "serial": "9041B2524260",
            "mac": "90:41:b2:52:42:60",
            "ip": "10.10.10.61",
            "version": "8.6.11.18870",
            "uptime": 484800,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 96,
            "radios": [
              {
                "band": "ng",
                "channel": 3,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 108,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 77,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3e:f3",
            "uplink_name": "ECS 48 PoE | 7"
          },
          {
            "type": "usw",
            "name": "UPS Tower",
            "model": "USWDA24",
            "serial": "1C0B8B3C145E",
            "mac": "1c:0b:8b:3c:14:5e",
            "ip": "192.168.1.150",
            "version": "1.5.0.378",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "num_port": 1,
            "uplink_mac": "8c:30:66:a2:5f:ee",
            "uplink_name": "USW Pro XG 8 PoE | Stores Rack"
          },
          {
            "type": "uap",
            "name": "E7 | CEO (Left Door)",
            "model": "UAPA697",
            "serial": "1C0B8B009445",
            "mac": "1c:0b:8b:00:94:45",
            "ip": "10.10.10.24",
            "version": "8.6.11.18870",
            "uptime": 1035334,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 13,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 120,
                "ht": 20
              },
              {
                "band": "6e",
                "channel": 73,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3c:5f",
            "uplink_name": "ECS 48 PoE | 11 Artum"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 10",
            "model": "USWF069",
            "serial": "8CEDE1C23E4E",
            "mac": "8c:ed:e1:c2:3e:4e",
            "ip": "10.10.10.23",
            "version": "7.4.1.16850",
            "uptime": 2571555,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:e5:d2",
            "uplink_name": "ECS Aggregation North"
          },
          {
            "type": "usw",
            "name": "ECS Aggregation South",
            "model": "USWF066",
            "serial": "942A6F40DC6A",
            "mac": "94:2a:6f:40:dc:6a",
            "ip": "10.10.10.208",
            "version": "3.0.8.852",
            "uptime": 615047,
            "state": 1,
            "adopted": true,
            "num_port": 54,
            "poe_power": 118,
            "uplink_mac": "a8:9c:6c:f4:d2:b8",
            "uplink_name": "1 Triton"
          },
          {
            "type": "umbb",
            "name": "U5G Max Outdoor",
            "model": "UMBBE631",
            "serial": "8C3066D256DC",
            "mac": "8c:30:66:d2:56:dc",
            "ip": "10.10.10.181",
            "version": "7.4.1.19032",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "uplink_mac": "1c:6a:1b:68:4e:64",
            "uplink_name": "USW Pro Max 16 PoE | 18 (Desk)"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-13 Cab",
            "model": "UAPA6BA",
            "serial": "9041B25249C4",
            "mac": "90:41:b2:52:49:c4",
            "ip": "10.10.10.199",
            "version": "8.6.11.18870",
            "uptime": 1124253,
            "state": 1,
            "adopted": true,
            "num_sta": 2,
            "satisfaction": 98,
            "radios": [
              {
                "band": "ng",
                "channel": 11,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 112,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 1,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3c:96",
            "uplink_name": "ECS 48 PoE | 13"
          },
          {
            "type": "usw",
            "name": "USW Pro XG 8 PoE | 1 Replacement",
            "model": "USWED76",
            "serial": "1C0B8B08D7B3",
            "mac": "1c:0b:8b:08:d7:b3",
            "ip": "10.10.10.137",
            "version": "7.4.1.16850",
            "uptime": 221100,
            "state": 1,
            "adopted": true,
            "num_port": 10,
            "poe_power": 150,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | SW SER (check)",
            "model": "UAPA6BA",
            "serial": "9041B2525D7C",
            "mac": "90:41:b2:52:5d:7c",
            "ip": "10.10.10.125",
            "version": "8.6.11.18870",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": null,
            "radios": [
              {
                "band": "na",
                "channel": "auto",
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 77,
                "ht": "20"
              },
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              }
            ],
            "uplink_mac": "90:41:b2:40:8c:6e",
            "uplink_name": "EAV XG 24 PoE | SW SER"
          },
          {
            "type": "usw",
            "name": "ECS 24 PoE | 16 (Demo DC Lab) ",
            "model": "USWF067",
            "serial": "8478485C84E1",
            "mac": "84:78:48:5c:84:e1",
            "ip": "10.10.10.205",
            "version": "7.4.1.16850",
            "uptime": 918553,
            "state": 1,
            "adopted": true,
            "num_port": 26,
            "poe_power": 1050,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-14 Cab",
            "model": "UAPA6BA",
            "serial": "9041B25249C0",
            "mac": "90:41:b2:52:49:c0",
            "ip": "10.10.10.195",
            "version": "8.6.11.18870",
            "uptime": 620422,
            "state": 1,
            "adopted": true,
            "num_sta": 2,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 10,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 124,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 77,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:37:6e",
            "uplink_name": "ECS 48 PoE | 14"
          },
          {
            "type": "uap",
            "name": "E7 | Demo DC 2 (Right Middle)",
            "model": "UAPA697",
            "serial": "8CEDE100D749",
            "mac": "8c:ed:e1:00:d7:49",
            "ip": "10.10.10.239",
            "version": "8.6.11.18870",
            "uptime": 1183024,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 99,
            "radios": [
              {
                "band": "ng",
                "channel": 6,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 116,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 13,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:38:ef",
            "uplink_name": "ECS 48 PoE | 4"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | Meeting Room C",
            "model": "UAPA6BA",
            "serial": "9041B2524A28",
            "mac": "90:41:b2:52:4a:28",
            "ip": "10.10.10.154",
            "version": "8.6.11.18870",
            "uptime": 579952,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 7,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 64,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 61,
                "ht": "20"
              }
            ],
            "uplink_mac": "84:78:48:5a:3c:61",
            "uplink_name": "ECS 24 PoE | SW | Access | 1"
          },
          {
            "type": "uap",
            "name": "E7 | Build 1 (Left Rear)",
            "model": "UAPA697",
            "serial": "8CEDE100D309",
            "mac": "8c:ed:e1:00:d3:09",
            "ip": "10.10.10.224",
            "version": "8.6.11.18870",
            "uptime": 1183813,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 3,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 112,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 81,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3d:e0",
            "uplink_name": "ECS 48 PoE | 5"
          },
          {
            "type": "usw",
            "name": "USW WAN | SW (Primary)",
            "model": "USWED74",
            "serial": "847848A2D420",
            "mac": "84:78:48:a2:d4:20",
            "ip": "10.10.10.119",
            "version": "7.3.109.16640",
            "uptime": 918936,
            "state": 1,
            "adopted": true,
            "num_port": 4,
            "uplink_mac": "84:78:48:5a:36:d4",
            "uplink_name": "ECS 24 PoE | SW | MGMT | 1"
          },
          {
            "type": "usw",
            "name": "USW Pro XG 8 PoE | Stores Rack",
            "model": "USWED76",
            "serial": "8C3066A25FEE",
            "mac": "8c:30:66:a2:5f:ee",
            "ip": "10.10.10.142",
            "version": "7.4.1.16850",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "num_port": 10,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | Meeting Room E",
            "model": "UAPA6BA",
            "serial": "9041B25244E4",
            "mac": "90:41:b2:52:44:e4",
            "ip": "10.10.10.169",
            "version": "8.6.11.18870",
            "uptime": 605689,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": 3,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 124,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 69,
                "ht": "20"
              }
            ],
            "uplink_mac": "84:78:48:5a:3c:61",
            "uplink_name": "ECS 24 PoE | SW | Access | 1"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 1",
            "model": "USWF069",
            "serial": "8C3066C27D78",
            "mac": "8c:30:66:c2:7d:78",
            "ip": "10.10.10.27",
            "version": "7.4.1.16850",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "num_port": 52,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "usw",
            "name": "EAV XG 24 PoE | NE SER ",
            "model": "USWF001",
            "serial": "9041B2408A0E",
            "mac": "90:41:b2:40:8a:0e",
            "ip": "10.10.10.19",
            "version": "7.5.2.16967",
            "uptime": 2579474,
            "state": 1,
            "adopted": true,
            "num_port": 29,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:e5:d2",
            "uplink_name": "ECS Aggregation North"
          },
          {
            "type": "uap",
            "name": "U7 Pro XG Wall | TEC-3 Cab",
            "model": "UAPA6BA",
            "serial": "9041B2524E70",
            "mac": "90:41:b2:52:4e:70",
            "ip": "10.10.10.176",
            "version": "8.6.11.18870",
            "uptime": 1190675,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 97,
            "radios": [
              {
                "band": "ng",
                "channel": 8,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 56,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 73,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3d:a9",
            "uplink_name": "ECS 48 PoE | 3"
          },
          {
            "type": "usw",
            "name": "USW WAN | SW (Secondary)",
            "model": "USWED74",
            "serial": "847848A2D4C0",
            "mac": "84:78:48:a2:d4:c0",
            "ip": "10.10.10.30",
            "version": "7.3.109.16640",
            "uptime": 2082041,
            "state": 1,
            "adopted": true,
            "num_port": 4,
            "uplink_mac": "84:78:48:5a:36:d4",
            "uplink_name": "ECS 24 PoE | SW | MGMT | 1"
          },
          {
            "type": "uap",
            "name": "E7 | Cody Eng",
            "model": "UAPA697",
            "serial": "8CEDE100D675",
            "mac": "8c:ed:e1:00:d6:75",
            "ip": "10.10.10.170",
            "version": "8.6.11.18870",
            "uptime": 757205,
            "state": 1,
            "adopted": true,
            "num_sta": 4,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 7,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 116,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 81,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3b:15",
            "uplink_name": "ECS 48 PoE | 15"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 12",
            "model": "USWF069",
            "serial": "8CEDE1C23B83",
            "mac": "8c:ed:e1:c2:3b:83",
            "ip": "10.10.10.238",
            "version": "7.4.1.16850",
            "uptime": 2576529,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:e5:d2",
            "uplink_name": "ECS Aggregation North"
          },
          {
            "type": "usw",
            "name": "ECS 48 PoE | 9",
            "model": "USWF069",
            "serial": "8CEDE1C239CB",
            "mac": "8c:ed:e1:c2:39:cb",
            "ip": "10.10.10.86",
            "version": "7.4.1.16850",
            "uptime": 2568713,
            "state": 1,
            "adopted": true,
            "num_port": 52,
            "poe_power": 2150,
            "uplink_mac": "94:2a:6f:40:e5:d2",
            "uplink_name": "ECS Aggregation North"
          },
          {
            "type": "uap",
            "name": "E7 | Boris",
            "model": "UAPA697",
            "serial": "1C0B8B00BBAD",
            "mac": "1c:0b:8b:00:bb:ad",
            "ip": "10.10.10.13",
            "version": "8.6.11.18870",
            "uptime": 149877,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 99,
            "radios": [
              {
                "band": "ng",
                "channel": 8,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 64,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 9,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:37:6e",
            "uplink_name": "ECS 48 PoE | 14"
          },
          {
            "type": "uap",
            "name": "E7 | Demo DC (Left Rear)",
            "model": "UAPA697",
            "serial": "8CEDE100D7CD",
            "mac": "8c:ed:e1:00:d7:cd",
            "ip": "10.10.10.122",
            "version": "8.6.11.18870",
            "uptime": 90257,
            "state": 1,
            "adopted": true,
            "num_sta": 0,
            "satisfaction": -1,
            "radios": [
              {
                "band": "ng",
                "channel": "auto",
                "ht": 20
              },
              {
                "band": "na",
                "channel": 40,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 41,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:30:66:94:40:92",
            "uplink_name": "USW Pro XG 24 PoE | 2 | Replacement"
          },
          {
            "type": "uap",
            "name": "E7 | Office ( Left Rear)",
            "model": "UAPA697",
            "serial": "1C0B8B00C1FD",
            "mac": "1c:0b:8b:00:c1:fd",
            "ip": "10.10.10.20",
            "version": "8.6.11.18870",
            "uptime": 485178,
            "state": 1,
            "adopted": true,
            "num_sta": 2,
            "satisfaction": 97,
            "radios": [
              {
                "band": "ng",
                "channel": 9,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 100,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 29,
                "ht": "20"
              }
            ],
            "uplink_mac": "8c:ed:e1:c2:3c:96",
            "uplink_name": "ECS 48 PoE | 13"
          },
          {
            "type": "udb",
            "name": "UDB Switch | Stores",
            "model": "UDBA69F",
            "serial": "8CEDE11C2F18",
            "mac": "8c:ed:e1:1c:2f:18",
            "ip": "10.10.10.192",
            "version": "8.5.21.18681",
            "uptime": 0,
            "state": 0,
            "adopted": true,
            "uplink_mac": "8c:30:66:a2:5f:ee",
            "uplink_name": "USW Pro XG 8 PoE | Stores Rack"
          },
          {
            "type": "usw",
            "name": "ECS Aggregation North",
            "model": "USWF066",
            "serial": "942A6F40E5D2",
            "mac": "94:2a:6f:40:e5:d2",
            "ip": "10.10.10.75",
            "version": "3.0.8.852",
            "uptime": 615247,
            "state": 1,
            "adopted": true,
            "num_port": 54,
            "poe_power": 117,
            "uplink_mac": "a8:9c:6c:f4:d2:b8",
            "uplink_name": "1 Triton"
          },
          {
            "type": "usw",
            "name": "ECS 24 PoE | SW | Access | 1",
            "model": "USWF067",
            "serial": "8478485A3C61",
            "mac": "84:78:48:5a:3c:61",
            "ip": "10.10.10.113",
            "version": "7.4.1.16850",
            "uptime": 608290,
            "state": 1,
            "adopted": true,
            "num_port": 26,
            "poe_power": 1050,
            "uplink_mac": "94:2a:6f:40:dc:6a",
            "uplink_name": "ECS Aggregation South"
          },
          {
            "type": "usw",
            "name": "USP RPS",
            "model": "USPRPS",
            "serial": "1C6A1BECAD6D",
            "mac": "1c:6a:1b:ec:ad:6d",
            "ip": "192.168.1.128",
            "version": "7.2.123.16565",
            "uptime": 672503,
            "state": 1,
            "adopted": true,
            "num_port": 1,
            "uplink_mac": "84:78:48:5a:36:d4",
            "uplink_name": "ECS 24 PoE | SW | MGMT | 1"
          },
          {
            "type": "uap",
            "name": "E7 | SW SER",
            "model": "UAPA697",
            "serial": "8CEDE100D661",
            "mac": "8c:ed:e1:00:d6:61",
            "ip": "10.10.10.150",
            "version": "8.6.11.18870",
            "uptime": 602305,
            "state": 1,
            "adopted": true,
            "num_sta": 1,
            "satisfaction": 100,
            "radios": [
              {
                "band": "ng",
                "channel": 4,
                "ht": 20
              },
              {
                "band": "na",
                "channel": 144,
                "ht": "20"
              },
              {
                "band": "6e",
                "channel": 25,
                "ht": "20"
              }
            ],
            "uplink_mac": "84:78:48:5a:3c:61",
            "uplink_name": "ECS 24 PoE | SW | Access | 1"
          },
          {
            "type": "usw",
            "name": "ECS 24 PoE",
            "model": "USWF067",
            "serial": "8478485A3DBD",
            "mac": "84:78:48:5a:3d:bd",
            "ip": "192.168.1.20",
            "version": "7.4.1.16850",
            "uptime": 262037,
            "state": 2,
            "adopted": false,
            "num_port": 0
          },
          {
            "type": "usw",
            "name": "ECS 24 PoE",
            "model": "USWF067",
            "serial": "8478485A398C",
            "mac": "84:78:48:5a:39:8c",
            "ip": "192.168.1.20",
            "version": "7.4.1.16850",
            "uptime": 262021,
            "state": 2,
            "adopted": false,
            "num_port": 0
          }
        ],
        "inference_servers": []
      },
      "1-triton-efg": {
        "site_desc": null,
        "networks": [],
        "vpn_tunnels": [],
        "devices": []
      },
      "deploy-01": {
        "site_desc": null,
        "networks": [],
        "vpn_tunnels": [],
        "devices": []
      },
      "deploy-02": {
        "site_desc": null,
        "networks": [],
        "vpn_tunnels": [],
        "devices": []
      },
      "deploy-03": {
        "site_desc": null,
        "networks": [],
        "vpn_tunnels": [],
        "devices": []
      },
      "deploy-04": {
        "site_desc": null,
        "networks": [],
        "vpn_tunnels": [],
        "devices": []
      },
      "deploy-05": {
        "site_desc": null,
        "networks": [],
        "vpn_tunnels": [],
        "devices": []
      },
      "deploy-06": {
        "site_desc": null,
        "networks": [],
        "vpn_tunnels": [],
        "devices": []
      },
      "deploy-07": {
        "site_desc": null,
        "networks": [],
        "vpn_tunnels": [],
        "devices": []
      },
      "deploy-08": {
        "site_desc": null,
        "networks": [],
        "vpn_tunnels": [],
        "devices": []
      }
    },
    "wan_latency": null,
    "gw_version": null
  },
  "inference": {
    "updated": "2026-07-25T08:26:56.421751+00:00",
    "clusters": [
      {
        "name": "hmnd-ml-dev-eu-west-2",
        "region": "eu-west-2",
        "source": "aws+k8s",
        "cluster": {
          "status": "ACTIVE",
          "version": "1.33",
          "endpoint": "https://6F95294776BEAD181FAC5C4E01234F75.yl4.eu-west-2.eks.amazonaws.com",
          "platform_version": "eks.41"
        },
        "nodegroups": [
          {
            "name": "hmnd-ml-nodes-dev-eu-west-2",
            "status": "ACTIVE",
            "instance_types": [
              "m5.xlarge",
              "m5.2xlarge",
              "c5.xlarge",
              "c5.2xlarge",
              "m5n.xlarge",
              "m5n.2xlarge",
              "m5.large",
              "c5.large"
            ],
            "desired": 3,
            "min": 2,
            "max": 20,
            "ami_type": "AL2023_x86_64_STANDARD",
            "capacity_type": "ON_DEMAND",
            "labels": {},
            "health_issues": 0
          },
          {
            "name": "hmnd-ml-p5-dev-eu-west-2",
            "status": "ACTIVE",
            "instance_types": [
              "p5.48xlarge"
            ],
            "desired": 6,
            "min": 6,
            "max": 6,
            "ami_type": "AL2023_x86_64_NVIDIA",
            "capacity_type": "ON_DEMAND",
            "labels": {
              "capacity-type": "reserved",
              "gpu-type": "h100",
              "az-placement": "eu-west-2b",
              "networking/efa": "true",
              "instance-family": "p5",
              "node-type": "gpu",
              "lustre-optimized": "true",
              "workload": "p5-reserved"
            },
            "health_issues": 0
          },
          {
            "name": "hmnd-ml-p5-mig-dev-eu-west-2",
            "status": "ACTIVE",
            "instance_types": [
              "p5.48xlarge"
            ],
            "desired": 2,
            "min": 2,
            "max": 2,
            "ami_type": "AL2023_x86_64_NVIDIA",
            "capacity_type": "ON_DEMAND",
            "labels": {
              "capacity-type": "reserved",
              "gpu-type": "h100",
              "az-placement": "eu-west-2b",
              "networking/efa": "true",
              "instance-family": "p5",
              "lustre-optimized": "true",
              "node-type": "gpu",
              "workload": "p5-reserved"
            },
            "health_issues": 0
          }
        ],
        "k8s": {
          "deployments": [
            {
              "name": "bosch-tote-handling-09-03",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:006d95c"
              ],
              "created": "2026-03-13T18:00:29Z",
              "labels": {
                "app": "bosch-tote-handling-09-03",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "bosch-tote-handling-09-03",
                "release": "bosch-tote-handling-09-03"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            },
            {
              "name": "internal-demos-conveyor-18-11-map",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:4ce9e12"
              ],
              "created": "2026-03-26T12:24:19Z",
              "labels": {
                "app": "internal-demos-conveyor-18-11-map",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "internal-demos-conveyor-18-11-map",
                "release": "internal-demos-conveyor-18-11-map"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            },
            {
              "name": "main-2fd2-bosc-tote-09-03",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:2fd2c34"
              ],
              "created": "2026-04-17T09:40:10Z",
              "labels": {
                "app": "main-2fd2-bosc-tote-09-03",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "main-2fd2-bosc-tote-09-03",
                "release": "main-2fd2-bosch-tote-handling-09-03"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            },
            {
              "name": "main-bosc-tote-09-03",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:cb179df"
              ],
              "created": "2026-04-01T14:08:07Z",
              "labels": {
                "app": "main-bosc-tote-09-03",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "main-bosc-tote-09-03",
                "release": "main-bosch-tote-handling-09-03"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            },
            {
              "name": "main-pi0-robo-robostore",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:f5af6cc"
              ],
              "created": "2026-04-02T10:09:38Z",
              "labels": {
                "app": "main-pi0-robo-robostore",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "main-pi0-robo-robostore",
                "release": "main-robostore-2026-03-23"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            },
            {
              "name": "main-scha-mach-13-11-25-18k-map",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:f5af6cc"
              ],
              "created": "2026-04-01T13:59:50Z",
              "labels": {
                "app": "main-scha-mach-13-11-25-18k-map",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "main-scha-mach-13-11-25-18k-map",
                "release": "main-schaeffler-mf-13-11-25-18k-map"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            },
            {
              "name": "r20260302-pi0-symp-symphony-wa-with-termination",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:73290a8"
              ],
              "created": "2026-04-13T13:56:51Z",
              "labels": {
                "app": "r20260302-pi0-symp-symphony-wa-with-termination",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "r20260302-pi0-symp-symphony-wa-with-termination",
                "release": "r20260302-robostore-2026-03-23"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            },
            {
              "name": "r20260318-inte-conv-18-11-map",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:c991543"
              ],
              "created": "2026-04-02T11:25:11Z",
              "labels": {
                "app": "r20260318-inte-conv-18-11-map",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "r20260318-inte-conv-18-11-map",
                "release": "r20260318-internal-demos-conv-18-11-map"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            },
            {
              "name": "r20260318-scha-mach-13-11-25-18k-map",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:c991543"
              ],
              "created": "2026-04-02T11:25:17Z",
              "labels": {
                "app": "r20260318-scha-mach-13-11-25-18k-map",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "r20260318-scha-mach-13-11-25-18k-map",
                "release": "r20260318-schaeffler-mf-13-11-25-18k-map"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            },
            {
              "name": "r20260611-pi0-mach-schaeffler-alpha-rl",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:586bcb5"
              ],
              "created": "2026-06-12T13:25:31Z",
              "labels": {
                "app": "r20260611-pi0-mach-schaeffler-alpha-rl",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "r20260611-pi0-mach-schaeffler-alpha-rl",
                "release": "r20260611-schaeffler-mf-rl-27-may-6200"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            },
            {
              "name": "schaeffler-machine-feeding-13-11-25-18k-map",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:4ce9e12"
              ],
              "created": "2026-03-26T12:12:14Z",
              "labels": {
                "app": "schaeffler-machine-feeding-13-11-25-18k-map",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "schaeffler-machine-feeding-13-11-25-18k-map",
                "release": "schaeffler-machine-feeding-13-11-25-18k-map"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "2",
                "memory_request": "8Gi"
              }
            }
          ],
          "pods": [
            {
              "name": "bosch-tote-handling-09-03-5f8fdfdd7d-ws9dh",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-95-87.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:006d95c"
              ],
              "started": "2026-06-02T12:08:51Z"
            },
            {
              "name": "internal-demos-conveyor-18-11-map-7b587c7b96-9m5t6",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-95-87.eu-west-2.compute.internal",
              "restarts": 3,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:4ce9e12"
              ],
              "started": "2026-05-22T12:37:02Z"
            },
            {
              "name": "main-2fd2-bosc-tote-09-03-7dbfddf89f-s65dk",
              "namespace": "inference",
              "phase": "Failed",
              "node": "ip-10-3-92-36.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": false,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:2fd2c34"
              ],
              "started": "2026-07-13T06:36:23Z"
            },
            {
              "name": "main-2fd2-bosc-tote-09-03-7dbfddf89f-zwrmk",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-92-36.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:2fd2c34"
              ],
              "started": "2026-07-13T07:43:58Z"
            },
            {
              "name": "main-bosc-tote-09-03-6b8c6447db-9rsrx",
              "namespace": "inference",
              "phase": "Failed",
              "node": "ip-10-3-92-36.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": false,
              "images": [],
              "started": "2026-07-13T06:36:24Z"
            },
            {
              "name": "main-bosc-tote-09-03-6b8c6447db-rkfmt",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-92-36.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:cb179df"
              ],
              "started": "2026-07-13T07:44:06Z"
            },
            {
              "name": "main-pi0-robo-robostore-69c8579f8d-xn77c",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-95-87.eu-west-2.compute.internal",
              "restarts": 4,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:f5af6cc"
              ],
              "started": "2026-05-22T12:37:02Z"
            },
            {
              "name": "main-scha-mach-13-11-25-18k-map-9b4fdcd46-62z46",
              "namespace": "inference",
              "phase": "Failed",
              "node": "ip-10-3-92-36.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": false,
              "images": [],
              "started": "2026-07-13T06:36:23Z"
            },
            {
              "name": "main-scha-mach-13-11-25-18k-map-9b4fdcd46-mn8zw",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-92-36.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:f5af6cc"
              ],
              "started": "2026-07-13T07:44:06Z"
            },
            {
              "name": "r20260302-pi0-symp-symphony-wa-with-termination-6474ddf8bc2hbb2",
              "namespace": "inference",
              "phase": "Failed",
              "node": "ip-10-3-92-36.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": false,
              "images": [],
              "started": "2026-07-13T06:36:23Z"
            },
            {
              "name": "r20260302-pi0-symp-symphony-wa-with-termination-6474ddf8bcf4pkh",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-92-36.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:73290a8"
              ],
              "started": "2026-07-13T07:44:06Z"
            },
            {
              "name": "r20260318-inte-conv-18-11-map-58c77f4f66-nbkb8",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-95-87.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:c991543"
              ],
              "started": "2026-07-13T06:36:23Z"
            },
            {
              "name": "r20260318-scha-mach-13-11-25-18k-map-7695ffc97d-cpjn4",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-92-36.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:c991543"
              ],
              "started": "2026-07-13T07:43:58Z"
            },
            {
              "name": "r20260318-scha-mach-13-11-25-18k-map-7695ffc97d-njnxd",
              "namespace": "inference",
              "phase": "Failed",
              "node": "ip-10-3-92-36.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": false,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:c991543"
              ],
              "started": "2026-07-13T06:36:23Z"
            },
            {
              "name": "r20260611-pi0-mach-schaeffler-alpha-rl-648bc8576c-fq8x4",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-95-87.eu-west-2.compute.internal",
              "restarts": 0,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:586bcb5"
              ],
              "started": "2026-06-12T13:25:31Z"
            },
            {
              "name": "schaeffler-machine-feeding-13-11-25-18k-map-664cf66f68-vwv7p",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-10-3-95-87.eu-west-2.compute.internal",
              "restarts": 4,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:4ce9e12"
              ],
              "started": "2026-05-22T12:37:01Z"
            }
          ],
          "ingresses": [
            {
              "hostname": "bosch.tote-handling.09-03.eks-euw2.lan.thehumanoid.ai",
              "client": "bosch",
              "capability": "tote-handling",
              "version": "09-03",
              "cluster_alias": "eks-euw2",
              "name": "bosch-tote-handling-09-03",
              "paths": [
                {
                  "path": "/",
                  "service": "bosch-tote-handling-09-03",
                  "port": 9005
                }
              ],
              "created": "2026-03-13T18:00:29Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 31,
                "status": "SERVING",
                "method": "grpc"
              }
            },
            {
              "hostname": "internal-demos.conveyor.18-11-map.eks-euw2.lan.thehumanoid.ai",
              "client": "internal-demos",
              "capability": "conveyor",
              "version": "18-11-map",
              "cluster_alias": "eks-euw2",
              "name": "internal-demos-conveyor-18-11-map",
              "paths": [
                {
                  "path": "/",
                  "service": "internal-demos-conveyor-18-11-map",
                  "port": 9005
                }
              ],
              "created": "2026-03-26T12:24:19Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 131,
                "status": "OK",
                "method": "https",
                "http_code": "200"
              }
            },
            {
              "hostname": "main-2fd2.bosc.tote.09-03.eks-euw2.lan.thehumanoid.ai",
              "client": "main-2fd2",
              "capability": "bosc",
              "version": "tote",
              "cluster_alias": "09-03",
              "name": "main-2fd2-bosc-tote-09-03",
              "paths": [
                {
                  "path": "/",
                  "service": "main-2fd2-bosc-tote-09-03",
                  "port": 9005
                }
              ],
              "created": "2026-04-17T09:40:10Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 35,
                "status": "SERVING",
                "method": "grpc"
              }
            },
            {
              "hostname": "main.bosc.tote.09-03.eks-euw2.lan.thehumanoid.ai",
              "client": "main",
              "capability": "bosc",
              "version": "tote",
              "cluster_alias": "09-03",
              "name": "main-bosc-tote-09-03",
              "paths": [
                {
                  "path": "/",
                  "service": "main-bosc-tote-09-03",
                  "port": 9005
                }
              ],
              "created": "2026-04-01T14:08:07Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 32,
                "status": "SERVING",
                "method": "grpc"
              }
            },
            {
              "hostname": "main.pi0.robo.robostore.eks-euw2.lan.thehumanoid.ai",
              "client": "main",
              "capability": "pi0",
              "version": "robo",
              "cluster_alias": "robostore",
              "name": "main-pi0-robo-robostore",
              "paths": [
                {
                  "path": "/",
                  "service": "main-pi0-robo-robostore",
                  "port": 9005
                }
              ],
              "created": "2026-04-02T10:09:38Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 232,
                "status": "OK",
                "method": "https",
                "http_code": "200"
              }
            },
            {
              "hostname": "main.scha.mach.13-11-25-18k-map.eks-euw2.lan.thehumanoid.ai",
              "client": "main",
              "capability": "scha",
              "version": "mach",
              "cluster_alias": "13-11-25-18k-map",
              "name": "main-scha-mach-13-11-25-18k-map",
              "paths": [
                {
                  "path": "/",
                  "service": "main-scha-mach-13-11-25-18k-map",
                  "port": 9005
                }
              ],
              "created": "2026-04-01T13:59:50Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 127,
                "status": "OK",
                "method": "https",
                "http_code": "200"
              }
            },
            {
              "hostname": "r20260302.pi0.symp.symphony-wa-with-termination.eks-euw2.lan.thehumanoid.ai",
              "client": "r20260302",
              "capability": "pi0",
              "version": "symp",
              "cluster_alias": "symphony-wa-with-termination",
              "name": "r20260302-pi0-symp-symphony-wa-with-termination",
              "paths": [
                {
                  "path": "/",
                  "service": "r20260302-pi0-symp-symphony-wa-with-termination",
                  "port": 9005
                }
              ],
              "created": "2026-04-13T13:56:51Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 207,
                "status": "OK",
                "method": "https",
                "http_code": "200"
              }
            },
            {
              "hostname": "r20260318.inte.conv.18-11-map.eks-euw2.lan.thehumanoid.ai",
              "client": "r20260318",
              "capability": "inte",
              "version": "conv",
              "cluster_alias": "18-11-map",
              "name": "r20260318-inte-conv-18-11-map",
              "paths": [
                {
                  "path": "/",
                  "service": "r20260318-inte-conv-18-11-map",
                  "port": 9005
                }
              ],
              "created": "2026-04-02T11:25:11Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 133,
                "status": "OK",
                "method": "https",
                "http_code": "200"
              }
            },
            {
              "hostname": "r20260318.scha.mach.13-11-25-18k-map.eks-euw2.lan.thehumanoid.ai",
              "client": "r20260318",
              "capability": "scha",
              "version": "mach",
              "cluster_alias": "13-11-25-18k-map",
              "name": "r20260318-scha-mach-13-11-25-18k-map",
              "paths": [
                {
                  "path": "/",
                  "service": "r20260318-scha-mach-13-11-25-18k-map",
                  "port": 9005
                }
              ],
              "created": "2026-04-02T11:25:17Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 157,
                "status": "OK",
                "method": "https",
                "http_code": "200"
              }
            },
            {
              "hostname": "r20260611.pi0.mach.schaeffler-alpha-rl.eks-euw2.lan.thehumanoid.ai",
              "client": "r20260611",
              "capability": "pi0",
              "version": "mach",
              "cluster_alias": "schaeffler-alpha-rl",
              "name": "r20260611-pi0-mach-schaeffler-alpha-rl",
              "paths": [
                {
                  "path": "/",
                  "service": "r20260611-pi0-mach-schaeffler-alpha-rl",
                  "port": 9005
                }
              ],
              "created": "2026-06-12T13:25:31Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 29,
                "status": "SERVING",
                "method": "grpc"
              }
            },
            {
              "hostname": "schaeffler.machine-feeding.13-11-25-18k-map.eks-euw2.lan.thehumanoid.ai",
              "client": "schaeffler",
              "capability": "machine-feeding",
              "version": "13-11-25-18k-map",
              "cluster_alias": "eks-euw2",
              "name": "schaeffler-machine-feeding-13-11-25-18k-map",
              "paths": [
                {
                  "path": "/",
                  "service": "schaeffler-machine-feeding-13-11-25-18k-map",
                  "port": 9005
                }
              ],
              "created": "2026-03-26T12:12:14Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 292,
                "status": "OK",
                "method": "https",
                "http_code": "200"
              }
            }
          ],
          "services": [
            {
              "name": "bosch-tote-handling-09-03",
              "type": "ClusterIP",
              "cluster_ip": "172.20.214.97",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "internal-demos-conveyor-18-11-map",
              "type": "ClusterIP",
              "cluster_ip": "172.20.161.52",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "main-2fd2-bosc-tote-09-03",
              "type": "ClusterIP",
              "cluster_ip": "172.20.243.179",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "main-bosc-tote-09-03",
              "type": "ClusterIP",
              "cluster_ip": "172.20.47.168",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "main-pi0-robo-robostore",
              "type": "ClusterIP",
              "cluster_ip": "172.20.253.104",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "main-scha-mach-13-11-25-18k-map",
              "type": "ClusterIP",
              "cluster_ip": "172.20.189.3",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "r20260302-pi0-symp-symphony-wa-with-termination",
              "type": "ClusterIP",
              "cluster_ip": "172.20.116.243",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "r20260318-inte-conv-18-11-map",
              "type": "ClusterIP",
              "cluster_ip": "172.20.228.6",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "r20260318-scha-mach-13-11-25-18k-map",
              "type": "ClusterIP",
              "cluster_ip": "172.20.189.27",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "r20260611-pi0-mach-schaeffler-alpha-rl",
              "type": "ClusterIP",
              "cluster_ip": "172.20.32.119",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                },
                {
                  "port": 9213,
                  "target": "metrics",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "schaeffler-machine-feeding-13-11-25-18k-map",
              "type": "ClusterIP",
              "cluster_ip": "172.20.92.103",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            }
          ],
          "nodes": [
            {
              "name": "ip-10-3-102-208.eu-west-2.compute.internal",
              "instance_type": "r7i.8xlarge",
              "zone": "eu-west-2c",
              "ready": true,
              "cpu": "32",
              "memory": "259756456Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "256757160Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-102-31.eu-west-2.compute.internal",
              "instance_type": "r7i.12xlarge",
              "zone": "eu-west-2c",
              "ready": true,
              "cpu": "48",
              "memory": "389808280Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "47810m",
              "allocatable_memory": "386808984Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-103-146.eu-west-2.compute.internal",
              "instance_type": "g6.8xlarge",
              "zone": "eu-west-2c",
              "ready": true,
              "cpu": "32",
              "memory": "127044216Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "124044920Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-103-75.eu-west-2.compute.internal",
              "instance_type": "m6g.4xlarge",
              "zone": "eu-west-2c",
              "ready": true,
              "cpu": "16",
              "memory": "64391308Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "15890m",
              "allocatable_memory": "61392012Ki",
              "os": "linux",
              "arch": "arm64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-105-201.eu-west-2.compute.internal",
              "instance_type": "m5.xlarge",
              "zone": "eu-west-2c",
              "ready": true,
              "cpu": "4",
              "memory": "15992748Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "3800m",
              "allocatable_memory": "13690796Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-nodes-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-106-21.eu-west-2.compute.internal",
              "instance_type": "r7i.8xlarge",
              "zone": "eu-west-2c",
              "ready": true,
              "cpu": "32",
              "memory": "259756464Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "256757168Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-106-97.eu-west-2.compute.internal",
              "instance_type": "g6.8xlarge",
              "zone": "eu-west-2c",
              "ready": true,
              "cpu": "32",
              "memory": "127044224Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "124044928Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-107-175.eu-west-2.compute.internal",
              "instance_type": "m6g.4xlarge",
              "zone": "eu-west-2c",
              "ready": true,
              "cpu": "16",
              "memory": "64391308Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "15890m",
              "allocatable_memory": "61392012Ki",
              "os": "linux",
              "arch": "arm64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-64-123.eu-west-2.compute.internal",
              "instance_type": "g7e.2xlarge",
              "zone": "eu-west-2a",
              "ready": true,
              "cpu": "8",
              "memory": "65293116Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "7910m",
              "allocatable_memory": "62068540Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-64-143.eu-west-2.compute.internal",
              "instance_type": "g7e.2xlarge",
              "zone": "eu-west-2a",
              "ready": true,
              "cpu": "8",
              "memory": "65293120Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "7910m",
              "allocatable_memory": "62068544Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-64-97.eu-west-2.compute.internal",
              "instance_type": "g6.8xlarge",
              "zone": "eu-west-2a",
              "ready": true,
              "cpu": "32",
              "memory": "127044220Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "124044924Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-65-146.eu-west-2.compute.internal",
              "instance_type": "g7e.2xlarge",
              "zone": "eu-west-2a",
              "ready": true,
              "cpu": "8",
              "memory": "65293124Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "7910m",
              "allocatable_memory": "62068548Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-66-140.eu-west-2.compute.internal",
              "instance_type": "g6.8xlarge",
              "zone": "eu-west-2a",
              "ready": true,
              "cpu": "32",
              "memory": "127044220Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "124044924Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-70-69.eu-west-2.compute.internal",
              "instance_type": "m5.xlarge",
              "zone": "eu-west-2a",
              "ready": true,
              "cpu": "4",
              "memory": "16164776Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "3800m",
              "allocatable_memory": "13862824Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-nodes-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-72-29.eu-west-2.compute.internal",
              "instance_type": "r7i.16xlarge",
              "zone": "eu-west-2a",
              "ready": true,
              "cpu": "64",
              "memory": "519860100Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "63770m",
              "allocatable_memory": "511195012Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-73-175.eu-west-2.compute.internal",
              "instance_type": "g7e.2xlarge",
              "zone": "eu-west-2a",
              "ready": true,
              "cpu": "8",
              "memory": "65293156Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "7910m",
              "allocatable_memory": "62068580Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-74-199.eu-west-2.compute.internal",
              "instance_type": "m6g.4xlarge",
              "zone": "eu-west-2a",
              "ready": true,
              "cpu": "16",
              "memory": "64391308Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "15890m",
              "allocatable_memory": "61392012Ki",
              "os": "linux",
              "arch": "arm64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-80-127.eu-west-2.compute.internal",
              "instance_type": "r7i.8xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "32",
              "memory": "259756460Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "256757164Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-80-194.eu-west-2.compute.internal",
              "instance_type": "r7i.8xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "32",
              "memory": "259756572Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "256757276Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-80-81.eu-west-2.compute.internal",
              "instance_type": "m6g.4xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "16",
              "memory": "64391308Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "15890m",
              "allocatable_memory": "61392012Ki",
              "os": "linux",
              "arch": "arm64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-81-145.eu-west-2.compute.internal",
              "instance_type": "p5.48xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "192",
              "memory": "2097112408Ki",
              "gpu": "8",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "188",
              "allocatable_memory": "2082227544Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-p5-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-83-140.eu-west-2.compute.internal",
              "instance_type": "r7i.8xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "32",
              "memory": "259756580Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "256757284Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-83-17.eu-west-2.compute.internal",
              "instance_type": "p5.48xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "192",
              "memory": "2097112420Ki",
              "gpu": "8",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "188",
              "allocatable_memory": "2082227556Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-p5-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-83-49.eu-west-2.compute.internal",
              "instance_type": "p5.48xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "192",
              "memory": "2097112360Ki",
              "gpu": "6",
              "gpu_mig": "6",
              "gpu_product": "",
              "allocatable_cpu": "188",
              "allocatable_memory": "2090616104Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-p5-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-84-128.eu-west-2.compute.internal",
              "instance_type": "g6.8xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "32",
              "memory": "127044216Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "124044920Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-84-253.eu-west-2.compute.internal",
              "instance_type": "g6.8xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "32",
              "memory": "127044088Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "124044792Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-86-106.eu-west-2.compute.internal",
              "instance_type": "g6.8xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "32",
              "memory": "127044088Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "124044792Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-87-48.eu-west-2.compute.internal",
              "instance_type": "p5.48xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "192",
              "memory": "2097112392Ki",
              "gpu": "8",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "188",
              "allocatable_memory": "2082227528Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-p5-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-89-197.eu-west-2.compute.internal",
              "instance_type": "p5.48xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "192",
              "memory": "2097112436Ki",
              "gpu": "8",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "188",
              "allocatable_memory": "2082227572Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-p5-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-90-48.eu-west-2.compute.internal",
              "instance_type": "g6.8xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "32",
              "memory": "127044088Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "124044792Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-91-97.eu-west-2.compute.internal",
              "instance_type": "p5.48xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "192",
              "memory": "2097112408Ki",
              "gpu": "8",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "188",
              "allocatable_memory": "2082227544Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-p5-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-92-103.eu-west-2.compute.internal",
              "instance_type": "m5.xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "4",
              "memory": "15992744Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "3800m",
              "allocatable_memory": "13690792Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-nodes-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-92-124.eu-west-2.compute.internal",
              "instance_type": "r7i.8xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "32",
              "memory": "259756580Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "31850m",
              "allocatable_memory": "256757284Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-3-92-36.eu-west-2.compute.internal",
              "instance_type": "p5.48xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "192",
              "memory": "2097112352Ki",
              "gpu": "4",
              "gpu_mig": "6",
              "gpu_product": "",
              "allocatable_cpu": "188",
              "allocatable_memory": "2090616096Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-p5-mig-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-95-87.eu-west-2.compute.internal",
              "instance_type": "p5.48xlarge",
              "zone": "eu-west-2b",
              "ready": true,
              "cpu": "192",
              "memory": "2097112348Ki",
              "gpu": "4",
              "gpu_mig": "6",
              "gpu_product": "",
              "allocatable_cpu": "188",
              "allocatable_memory": "2082227484Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": "hmnd-ml-p5-mig-dev-eu-west-2"
            },
            {
              "name": "ip-10-3-97-208.eu-west-2.compute.internal",
              "instance_type": "c6i.xlarge",
              "zone": "eu-west-2c",
              "ready": true,
              "cpu": "4",
              "memory": "7964568Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "3920m",
              "allocatable_memory": "6947736Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            }
          ],
          "namespaces": [
            "agent-system",
            "agent-system-staging",
            "agent-system-test",
            "arc-runners",
            "arc-system",
            "bazel-remote",
            "cronjobs",
            "default",
            "dev",
            "efa-testing",
            "hmnd-rl",
            "inference",
            "kamino-dev",
            "kamino-dev-system",
            "kamino-system",
            "karpenter",
            "kube-node-lease",
            "kube-public",
            "kube-system",
            "kyverno",
            "logging",
            "longhorn-system",
            "monitoring",
            "prefect",
            "prefect-ml",
            "prod",
            "ray",
            "ray-system",
            "shared-storage",
            "simulation",
            "stray-dog",
            "vlm-proxy-dev",
            "volcano",
            "volcano-system"
          ]
        }
      },
      {
        "name": "hmnd-eks-cluster",
        "region": "eu-west-2",
        "source": "aws+k8s",
        "cluster": {
          "status": "ACTIVE",
          "version": "1.33",
          "endpoint": "https://A4DC8392E035C92809FE94069A7D7999.gr7.eu-west-2.eks.amazonaws.com",
          "platform_version": "eks.41"
        },
        "nodegroups": [
          {
            "name": "hmnd-eks-cluster-node-group-a",
            "status": "ACTIVE",
            "instance_types": [
              "t3.xlarge",
              "t3.2xlarge",
              "m5.xlarge"
            ],
            "desired": 0,
            "min": 0,
            "max": 1,
            "ami_type": "AL2023_x86_64_STANDARD",
            "capacity_type": "ON_DEMAND",
            "labels": {},
            "health_issues": 0
          },
          {
            "name": "hmnd-eks-cluster-node-group-b",
            "status": "ACTIVE",
            "instance_types": [
              "t3.xlarge",
              "t3.2xlarge",
              "m5.xlarge"
            ],
            "desired": 0,
            "min": 0,
            "max": 1,
            "ami_type": "AL2023_x86_64_STANDARD",
            "capacity_type": "ON_DEMAND",
            "labels": {},
            "health_issues": 0
          },
          {
            "name": "hmnd-eks-cluster-node-group-c",
            "status": "ACTIVE",
            "instance_types": [
              "t3.xlarge",
              "t3.2xlarge",
              "m5.xlarge"
            ],
            "desired": 0,
            "min": 0,
            "max": 1,
            "ami_type": "AL2023_x86_64_STANDARD",
            "capacity_type": "ON_DEMAND",
            "labels": {},
            "health_issues": 0
          }
        ],
        "k8s": {
          "deployments": [],
          "pods": [],
          "ingresses": [],
          "services": [],
          "nodes": [
            {
              "name": "ip-10-253-31-169.eu-west-2.compute.internal",
              "instance_type": "i7ie.3xlarge",
              "zone": "eu-west-2b",
              "ready": false,
              "cpu": "12",
              "memory": "97283312Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "11900m",
              "allocatable_memory": "96266480Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-10-253-38-213.eu-west-2.compute.internal",
              "instance_type": "t2.small",
              "zone": "eu-west-2c",
              "ready": false,
              "cpu": "1",
              "memory": "2002832Ki",
              "gpu": "0",
              "gpu_mig": "0",
              "gpu_product": "",
              "allocatable_cpu": "940m",
              "allocatable_memory": "1515408Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            }
          ],
          "namespaces": [
            "default",
            "humanoid-console",
            "karpenter",
            "kube-node-lease",
            "kube-public",
            "kube-system",
            "monitoring",
            "ops",
            "perception",
            "reasoning",
            "shared-between-teams",
            "simulation",
            "skypilot",
            "skypilot-system",
            "vla"
          ]
        }
      }
    ],
    "onprem_clusters": [
      {
        "name": "h100-01",
        "fqdn": "h100-01.lan.thehumanoid.ai",
        "ip": "10.44.11.101",
        "arch": "amd64",
        "gpu_type": "H100",
        "location": "lab",
        "source": "onprem"
      },
      {
        "name": "h100-02",
        "fqdn": "h100-02.lan.thehumanoid.ai",
        "ip": "10.44.11.201",
        "arch": "amd64",
        "gpu_type": "H100",
        "location": "lab",
        "source": "onprem"
      },
      {
        "name": "spark-01",
        "fqdn": "spark-01.lan.thehumanoid.ai",
        "ip": "10.44.11.12",
        "arch": "arm64",
        "gpu_type": "Spark",
        "location": "lab",
        "source": "onprem"
      },
      {
        "name": "saudi-01",
        "fqdn": "saudi-01.lan.thehumanoid.ai",
        "ip": "158.252.119.42",
        "arch": "amd64",
        "gpu_type": "A10G",
        "location": "me-central-1",
        "source": "onprem+k8s",
        "api_latency_ms": 769,
        "k8s": {
          "deployments": [
            {
              "name": "internal-demos-conveyor-18-11-map",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:latest"
              ],
              "created": "2026-01-23T14:12:04Z",
              "labels": {
                "app": "internal-demos-conveyor-18-11-map",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "internal-demos-conveyor-18-11-map",
                "release": "internal-demos-conveyor-18-11-map"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "4",
                "memory_request": "32Gi"
              }
            },
            {
              "name": "r20260219-inte-conv-18-11-map",
              "namespace": "inference",
              "replicas": 1,
              "ready": 1,
              "available": 1,
              "updated": 1,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:4ce9e12"
              ],
              "created": "2026-04-21T10:59:51Z",
              "labels": {
                "app": "r20260219-inte-conv-18-11-map",
                "app-type": "inference",
                "app.kubernetes.io/managed-by": "Helm",
                "model": "r20260219-inte-conv-18-11-map",
                "release": "r20260219-internal-demos-conv-18-11-map"
              },
              "resources": {
                "gpu_limit": "1",
                "cpu_request": "4",
                "memory_request": "32Gi"
              }
            }
          ],
          "pods": [
            {
              "name": "internal-demos-conveyor-18-11-map-5575469d6b-flwxl",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-172-31-33-154",
              "restarts": 0,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:latest"
              ],
              "started": "2026-02-09T18:52:45Z"
            },
            {
              "name": "r20260219-inte-conv-18-11-map-76d59c7c57-lgtv2",
              "namespace": "inference",
              "phase": "Running",
              "node": "ip-172-31-38-130",
              "restarts": 0,
              "ready": true,
              "images": [
                "767828728064.dkr.ecr.eu-west-2.amazonaws.com/hmnd-training:4ce9e12"
              ],
              "started": "2026-04-21T10:59:51Z"
            }
          ],
          "ingresses": [
            {
              "hostname": "ford.tote-handling.pi0-25-09-29-map.saudi-01.lan.thehumanoid.ai",
              "client": "ford",
              "capability": "tote-handling",
              "version": "pi0-25-09-29-map",
              "cluster_alias": "saudi-01",
              "name": "ford-tote-handling-pi0-25-09-29-map",
              "paths": [
                {
                  "path": "/",
                  "service": "ford-tote-handling-pi0-25-09-29-map",
                  "port": 9005
                }
              ],
              "created": "2026-01-23T09:58:09Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 370,
                "status": "OK",
                "method": "https",
                "http_code": "503"
              }
            },
            {
              "hostname": "internal-demos.conveyor.18-11-map.saudi-01.lan.thehumanoid.ai",
              "client": "internal-demos",
              "capability": "conveyor",
              "version": "18-11-map",
              "cluster_alias": "saudi-01",
              "name": "internal-demos-conveyor-18-11-map",
              "paths": [
                {
                  "path": "/",
                  "service": "internal-demos-conveyor-18-11-map",
                  "port": 9005
                }
              ],
              "created": "2026-01-23T14:12:04Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 480,
                "status": "OK",
                "method": "https",
                "http_code": "200"
              }
            },
            {
              "hostname": "r20260219.inte.conv.18-11-map.saudi-01.lan.thehumanoid.ai",
              "client": "r20260219",
              "capability": "inte",
              "version": "conv",
              "cluster_alias": "18-11-map",
              "name": "r20260219-inte-conv-18-11-map",
              "paths": [
                {
                  "path": "/",
                  "service": "r20260219-inte-conv-18-11-map",
                  "port": 9000
                }
              ],
              "created": "2026-04-21T10:59:51Z",
              "annotations": {
                "kubernetes.io/ingress.class": "nginx",
                "nginx.ingress.kubernetes.io/backend-protocol": "GRPC",
                "nginx.ingress.kubernetes.io/grpc-backend": "true"
              },
              "probe": {
                "latency_ms": 870,
                "status": "OK",
                "method": "https",
                "http_code": "200"
              }
            }
          ],
          "services": [
            {
              "name": "ford-tote-handling-pi0-25-09-29-map",
              "type": "ClusterIP",
              "cluster_ip": "10.106.81.18",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "internal-demos-conveyor-18-11-map",
              "type": "ClusterIP",
              "cluster_ip": "10.102.3.23",
              "ports": [
                {
                  "port": 9005,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            },
            {
              "name": "r20260219-inte-conv-18-11-map",
              "type": "LoadBalancer",
              "cluster_ip": "10.98.118.189",
              "ports": [
                {
                  "port": 9000,
                  "target": "grpc",
                  "protocol": "TCP"
                }
              ]
            }
          ],
          "nodes": [
            {
              "name": "ip-172-31-33-154",
              "instance_type": "",
              "zone": "",
              "ready": true,
              "cpu": "16",
              "memory": "65118216Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "NVIDIA-A10G",
              "allocatable_cpu": "16",
              "allocatable_memory": "56627208Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-172-31-38-130",
              "instance_type": "",
              "zone": "",
              "ready": true,
              "cpu": "16",
              "memory": "65118212Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "NVIDIA-A10G",
              "allocatable_cpu": "16",
              "allocatable_memory": "56627204Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            },
            {
              "name": "ip-172-31-46-251",
              "instance_type": "",
              "zone": "",
              "ready": true,
              "cpu": "16",
              "memory": "65118216Ki",
              "gpu": "1",
              "gpu_mig": "0",
              "gpu_product": "NVIDIA-A10G",
              "allocatable_cpu": "16",
              "allocatable_memory": "56627208Ki",
              "os": "linux",
              "arch": "amd64",
              "node_group": ""
            }
          ],
          "namespaces": [
            "default",
            "inference",
            "kube-flannel",
            "kube-node-lease",
            "kube-public",
            "kube-system",
            "logging",
            "longhorn-system",
            "monitoring"
          ]
        }
      },
      {
        "name": "mumbai-01",
        "fqdn": "mumbai-01.lan.thehumanoid.ai",
        "ip": "3.110.31.221",
        "arch": "amd64",
        "gpu_type": "UNKNOWN",
        "location": "ap-south-1",
        "source": "onprem"
      }
    ]
  },
  "netbox": {
    "updated": "2026-07-25T08:26:57.347389",
    "devices": [
      {
        "name": "hmnd-ab-01",
        "role": "robot",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "Alpha Biped",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/68/"
      },
      {
        "name": "hmnd-ab-02",
        "role": "robot",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "Alpha Biped",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/69/"
      },
      {
        "name": "hmnd-aw-01",
        "role": "robot",
        "site": "hmnd-bos-lab",
        "location": "Robot Womb Boston",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/58/"
      },
      {
        "name": "hmnd-aw-02",
        "role": "robot",
        "site": "hmnd-deploy-04",
        "location": "Bosch PoC",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": "10.44.98.12",
        "dns_name": "aw2.hmnd.lan",
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/54/"
      },
      {
        "name": "hmnd-aw-03",
        "role": "robot",
        "site": "hmnd-deploy-04",
        "location": "Bosch PoC",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/59/"
      },
      {
        "name": "hmnd-aw-04",
        "role": "robot",
        "site": "hmnd-deploy-02",
        "location": "London Lab 6th Floor",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": "10.44.98.14",
        "dns_name": "aw4.hmnd.lan",
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/55/"
      },
      {
        "name": "hmnd-aw-05",
        "role": "robot",
        "site": "hmnd-deploy-03",
        "location": "KSA Showroom",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/60/"
      },
      {
        "name": "hmnd-aw-06",
        "role": "robot",
        "site": "hmnd-deploy-02",
        "location": "London Lab 6th Floor",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/61/"
      },
      {
        "name": "hmnd-aw-07",
        "role": "robot",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/62/"
      },
      {
        "name": "hmnd-aw-08",
        "role": "robot",
        "site": "hmnd-deploy-02",
        "location": "London Lab 6th Floor",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/63/"
      },
      {
        "name": "hmnd-aw-09",
        "role": "robot",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/64/"
      },
      {
        "name": "hmnd-aw-10",
        "role": "robot",
        "site": "hmnd-deploy-02",
        "location": "London Lab 6th Floor",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/65/"
      },
      {
        "name": "hmnd-aw-11",
        "role": "robot",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/66/"
      },
      {
        "name": "hmnd-aw-12",
        "role": "robot",
        "site": "hmnd-deploy-02",
        "location": "London Lab 6th Floor",
        "status": "active",
        "device_type": "Alpha Wheeled",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/67/"
      },
      {
        "name": "hmnd-deploy-01-gw-01",
        "role": "security-appliance",
        "site": "hmnd-deploy-01",
        "location": null,
        "status": "active",
        "device_type": "UniFi Cloud Gateway Fiber",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/10/"
      },
      {
        "name": "hmnd-deploy-01-pi5-01",
        "role": "compute",
        "site": "hmnd-deploy-01",
        "location": null,
        "status": "active",
        "device_type": "Raspberry Pi 5",
        "primary_ip": "10.44.97.101",
        "dns_name": "pi1.hmnd.lan",
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/12/"
      },
      {
        "name": "hmnd-deploy-01-screen-01",
        "role": "screen",
        "site": "hmnd-deploy-01",
        "location": null,
        "status": "active",
        "device_type": "GeekPi Screen",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/13/"
      },
      {
        "name": "hmnd-deploy-01-sw-01",
        "role": "access-switch",
        "site": "hmnd-deploy-01",
        "location": null,
        "status": "active",
        "device_type": "Unifi Switch Pro XG 8 PoE",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/11/"
      },
      {
        "name": "hmnd-deploy-02-ap-01",
        "role": "access-point",
        "site": "hmnd-deploy-02",
        "location": "CES Booth",
        "status": "active",
        "device_type": "E7",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/38/"
      },
      {
        "name": "hmnd-deploy-02-ap-02",
        "role": "access-point",
        "site": "hmnd-deploy-02",
        "location": "CES Booth",
        "status": "active",
        "device_type": "U7 Pro Wall",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/41/"
      },
      {
        "name": "hmnd-deploy-02-ap-03",
        "role": "access-point",
        "site": "hmnd-deploy-02",
        "location": "CES Booth",
        "status": "active",
        "device_type": "E7",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/42/"
      },
      {
        "name": "hmnd-deploy-02-gw-01",
        "role": "security-appliance",
        "site": "hmnd-deploy-02",
        "location": "CES Booth",
        "status": "active",
        "device_type": "UniFi Cloud Gateway Fiber",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/34/"
      },
      {
        "name": "hmnd-deploy-02-inference-01",
        "role": "compute",
        "site": "hmnd-deploy-02",
        "location": "CES Booth",
        "status": "active",
        "device_type": "H100",
        "primary_ip": "10.44.66.10",
        "dns_name": "h100-1.hmnd.lan",
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/43/"
      },
      {
        "name": "hmnd-deploy-02-pi5-01",
        "role": "compute",
        "site": "hmnd-deploy-02",
        "location": "CES Booth",
        "status": "active",
        "device_type": "Raspberry Pi 5",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/37/"
      },
      {
        "name": "hmnd-deploy-02-screen-01",
        "role": "screen",
        "site": "hmnd-deploy-02",
        "location": "CES Booth",
        "status": "active",
        "device_type": "GeekPi Screen",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/36/"
      },
      {
        "name": "hmnd-deploy-02-sw-01",
        "role": "access-switch",
        "site": "hmnd-deploy-02",
        "location": "CES Booth",
        "status": "active",
        "device_type": "Unifi Switch Pro XG 8 PoE",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/35/"
      },
      {
        "name": "hmnd-deploy-04-ap-01",
        "role": "access-point",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "staged",
        "device_type": "E7",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/50/"
      },
      {
        "name": "hmnd-deploy-04-ap-02",
        "role": "access-point",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "staged",
        "device_type": "E7",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/51/"
      },
      {
        "name": "hmnd-deploy-04-ap-03",
        "role": "access-point",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "staged",
        "device_type": "U7 Pro Wall",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/52/"
      },
      {
        "name": "hmnd-deploy-04-cam-01",
        "role": "camera",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "active",
        "device_type": "Unifi G6 Bullet",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/39/"
      },
      {
        "name": "hmnd-deploy-04-cam-02",
        "role": "camera",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "active",
        "device_type": "Unifi G6 Bullet",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/40/"
      },
      {
        "name": "hmnd-deploy-04-gw-01",
        "role": "security-appliance",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "staged",
        "device_type": "UniFi Cloud Gateway Fiber",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/45/"
      },
      {
        "name": "hmnd-deploy-04-inference-01",
        "role": "compute",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "staged",
        "device_type": "RTX5090",
        "primary_ip": "10.44.98.59",
        "dns_name": "5090.hmnd.lan",
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/53/"
      },
      {
        "name": "hmnd-deploy-04-pi5-01",
        "role": "compute",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "staged",
        "device_type": "Raspberry Pi 5",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/47/"
      },
      {
        "name": "hmnd-deploy-04-pi5-02",
        "role": "compute",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "staged",
        "device_type": "Raspberry Pi 5",
        "primary_ip": "10.44.97.102",
        "dns_name": "pi2.hmnd.lan",
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/48/"
      },
      {
        "name": "hmnd-deploy-04-pi5-03",
        "role": "compute",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "staged",
        "device_type": "Raspberry Pi 5",
        "primary_ip": "10.44.97.103",
        "dns_name": "pi3.hmnd.lan",
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/49/"
      },
      {
        "name": "hmnd-deploy-04-screen-01",
        "role": "screen",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "staged",
        "device_type": "GeekPi Screen",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/44/"
      },
      {
        "name": "hmnd-deploy-04-sw-01",
        "role": "access-switch",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "staged",
        "device_type": "Unifi Switch Pro XG 8 PoE",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/46/"
      },
      {
        "name": "hmnd-deploy-04-wan-01",
        "role": "wan-uplink",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "active",
        "device_type": "Customer WAN Uplink",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/57/"
      },
      {
        "name": "hmnd-deploy-04-wan-02",
        "role": "wan-uplink",
        "site": "hmnd-deploy-04",
        "location": "Martur Fompak",
        "status": "active",
        "device_type": "RUTM30",
        "primary_ip": null,
        "dns_name": null,
        "serial": "600585677",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/56/"
      },
      {
        "name": "hmnd-lab-cam-01",
        "role": "camera",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "Unifi G6 Bullet",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/9/"
      },
      {
        "name": "hmnd-lab-gw-01",
        "role": "security-appliance",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "Enterprise Fortress Gateway",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/1/"
      },
      {
        "name": "hmnd-lab-gw-02",
        "role": "security-appliance",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "Enterprise Fortress Gateway",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/4/"
      },
      {
        "name": "hmnd-lab-nas-01",
        "role": "network-attached-storage",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "UNAS Pro",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/5/"
      },
      {
        "name": "hmnd-lab-nvr-01",
        "role": "network-video-recorder",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "UniFi Protect Network Video Recorder Pro",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/6/"
      },
      {
        "name": "hmnd-lab-sw-01",
        "role": "access-switch",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "UniFi Switch Enterprise 48 PoE",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/2/"
      },
      {
        "name": "hmnd-lab-sw-02",
        "role": "access-switch",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "Unifi Switch Pro XG 8 PoE",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/3/"
      },
      {
        "name": "hmnd-lab-wire-01",
        "role": "patch-panel",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "24-Port Blank Keystone Patch Panel",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/7/"
      },
      {
        "name": "hmnd-lab-wire-02",
        "role": "patch-panel",
        "site": "hmnd-lon-lab",
        "location": "London Lab 5th Floor",
        "status": "active",
        "device_type": "24-Port Blank Keystone Patch Panel",
        "primary_ip": null,
        "dns_name": null,
        "serial": "",
        "url": "https://bwgd4658.cloud.netboxapp.com/api/dcim/devices/8/"
      }
    ],
    "sites": [
      {
        "name": "hmnd-bos-lab",
        "slug": "hmnd-bos-lab",
        "description": "hmnd boston hq",
        "region": "Boston",
        "facility": "WeWork 1 Broadway, Cambridge, MA 02142"
      },
      {
        "name": "hmnd-deploy-01",
        "slug": "hmnd-deploy-01",
        "description": "Deployment Network in a Box | GeekPi 10inch 4U",
        "region": "Europe",
        "facility": "Symphony"
      },
      {
        "name": "hmnd-deploy-02",
        "slug": "hmnd-deploy-02",
        "description": "Deployment Network in a Box | GeekPi 10inch 4U",
        "region": "Vegas",
        "facility": "WeWork 5 Merchant Square"
      },
      {
        "name": "hmnd-deploy-03",
        "slug": "hmnd-deploy-03",
        "description": "Deployment Network in a Box | GeekPi 10inch 4U",
        "region": "Europe",
        "facility": "KSA"
      },
      {
        "name": "hmnd-deploy-04",
        "slug": "hmnd-deploy-04",
        "description": "Deployment Network in a Box | GeekPi 10inch 8U",
        "region": "Europe",
        "facility": "Martur Fompak SAP"
      },
      {
        "name": "hmnd-lon-lab",
        "slug": "hmnd-lab-lon",
        "description": "hmnd london hq",
        "region": "London",
        "facility": "WeWork 5 Merchant Square"
      }
    ],
    "ip_addresses": [
      {
        "address": "10.44.10.17",
        "dns_name": "aw7.hmnd.lan",
        "status": "active",
        "assigned_device": "hmnd-deploy-02-ap-01"
      },
      {
        "address": "10.44.10.18",
        "dns_name": "aw8.hmnd.lan",
        "status": "active",
        "assigned_device": null
      },
      {
        "address": "10.44.50.101",
        "dns_name": "h100-01.hmnd.lan",
        "status": "active",
        "assigned_device": null
      },
      {
        "address": "10.44.50.102",
        "dns_name": "h100-02.hmnd.lan",
        "status": "active",
        "assigned_device": null
      },
      {
        "address": "10.44.66.10",
        "dns_name": "h100-1.hmnd.lan",
        "status": "active",
        "assigned_device": "hmnd-deploy-02-inference-01"
      },
      {
        "address": "10.44.66.101",
        "dns_name": "h100-01.hmnd.lan",
        "status": "active",
        "assigned_device": null
      },
      {
        "address": "10.44.66.102",
        "dns_name": "h100-02.hmnd.lan",
        "status": "active",
        "assigned_device": null
      },
      {
        "address": "10.44.82.101",
        "dns_name": "h100-01.hmnd.lan",
        "status": "active",
        "assigned_device": null
      },
      {
        "address": "10.44.82.102",
        "dns_name": "h100-02.hmnd.lan",
        "status": "active",
        "assigned_device": null
      },
      {
        "address": "10.44.97.101",
        "dns_name": "pi1.hmnd.lan",
        "status": "active",
        "assigned_device": "hmnd-deploy-01-pi5-01"
      },
      {
        "address": "10.44.97.102",
        "dns_name": "pi2.hmnd.lan",
        "status": "active",
        "assigned_device": "hmnd-deploy-04-pi5-02"
      },
      {
        "address": "10.44.97.103",
        "dns_name": "pi3.hmnd.lan",
        "status": "active",
        "assigned_device": "hmnd-deploy-04-pi5-03"
      },
      {
        "address": "10.44.98.12",
        "dns_name": "aw2.hmnd.lan",
        "status": "active",
        "assigned_device": "hmnd-aw-02"
      },
      {
        "address": "10.44.98.14",
        "dns_name": "aw4.hmnd.lan",
        "status": "active",
        "assigned_device": "hmnd-aw-04"
      },
      {
        "address": "10.44.98.59",
        "dns_name": "5090.hmnd.lan",
        "status": "active",
        "assigned_device": "hmnd-deploy-04-inference-01"
      },
      {
        "address": "10.44.98.101",
        "dns_name": "h100-01.hmnd.lan",
        "status": "active",
        "assigned_device": null
      },
      {
        "address": "10.44.98.102",
        "dns_name": "h100-02.hmnd.lan",
        "status": "active",
        "assigned_device": null
      }
    ],
    "prefixes": [
      {
        "prefix": "10.44.0.0/20",
        "site": null,
        "vlan": null,
        "vlan_name": null,
        "status": "active",
        "description": "london lab prefix"
      },
      {
        "prefix": "10.44.16.0/20",
        "site": null,
        "vlan": null,
        "vlan_name": null,
        "status": "reserved",
        "description": ""
      },
      {
        "prefix": "10.44.32.0/20",
        "site": null,
        "vlan": null,
        "vlan_name": null,
        "status": "reserved",
        "description": ""
      },
      {
        "prefix": "10.44.48.0/20",
        "site": null,
        "vlan": null,
        "vlan_name": null,
        "status": "active",
        "description": ""
      },
      {
        "prefix": "10.44.50.0/24",
        "site": null,
        "vlan": 3,
        "vlan_name": "hmnd-inference",
        "status": "active",
        "description": "Inference GPU Compute"
      },
      {
        "prefix": "10.44.64.0/20",
        "site": null,
        "vlan": null,
        "vlan_name": null,
        "status": "active",
        "description": ""
      },
      {
        "prefix": "10.44.64.0/24",
        "site": null,
        "vlan": 1,
        "vlan_name": "hmnd-mgmt",
        "status": "active",
        "description": "Net Infra MGMT"
      },
      {
        "prefix": "10.44.65.0/24",
        "site": null,
        "vlan": 2,
        "vlan_name": "hmnd-random",
        "status": "active",
        "description": "Emergent use case - Adapt to context"
      },
      {
        "prefix": "10.44.66.0/24",
        "site": null,
        "vlan": 3,
        "vlan_name": "hmnd-inference",
        "status": "active",
        "description": "Inference GPU Compute"
      },
      {
        "prefix": "10.44.67.0/24",
        "site": null,
        "vlan": 4,
        "vlan_name": "hmnd-human",
        "status": "active",
        "description": "Human Users"
      },
      {
        "prefix": "10.44.68.0/24",
        "site": null,
        "vlan": 5,
        "vlan_name": "hmnd-robot",
        "status": "active",
        "description": "Robot Devices"
      },
      {
        "prefix": "10.44.80.0/20",
        "site": null,
        "vlan": null,
        "vlan_name": null,
        "status": "active",
        "description": ""
      },
      {
        "prefix": "10.44.82.0/24",
        "site": null,
        "vlan": 3,
        "vlan_name": "hmnd-inference",
        "status": "active",
        "description": "Inference GPU Compute"
      },
      {
        "prefix": "10.44.96.0/20",
        "site": null,
        "vlan": null,
        "vlan_name": null,
        "status": "active",
        "description": ""
      },
      {
        "prefix": "10.44.96.0/24",
        "site": null,
        "vlan": 1,
        "vlan_name": "hmnd-mgmt",
        "status": "active",
        "description": "Net Infra MGMT"
      },
      {
        "prefix": "10.44.97.0/24",
        "site": null,
        "vlan": 2,
        "vlan_name": "hmnd-random",
        "status": "active",
        "description": "Emergent use case - Adapt to context"
      },
      {
        "prefix": "10.44.98.0/24",
        "site": null,
        "vlan": 3,
        "vlan_name": "hmnd-inference",
        "status": "active",
        "description": "Inference GPU Compute"
      },
      {
        "prefix": "10.44.99.0/24",
        "site": null,
        "vlan": 4,
        "vlan_name": "hmnd-human",
        "status": "active",
        "description": "Human Users"
      },
      {
        "prefix": "10.44.100.0/24",
        "site": null,
        "vlan": 5,
        "vlan_name": "hmnd-robot",
        "status": "active",
        "description": "Robot Devices"
      },
      {
        "prefix": "10.44.111.0/24",
        "site": null,
        "vlan": 16,
        "vlan_name": "hmnd-ui",
        "status": "active",
        "description": "Unifi One Click Wifi Users"
      }
    ],
    "vlans": [
      {
        "vid": 1,
        "name": "hmnd-mgmt",
        "site": null,
        "status": "active"
      },
      {
        "vid": 2,
        "name": "hmnd-random",
        "site": null,
        "status": "active"
      },
      {
        "vid": 3,
        "name": "hmnd-inference",
        "site": null,
        "status": "active"
      },
      {
        "vid": 4,
        "name": "hmnd-human",
        "site": null,
        "status": "active"
      },
      {
        "vid": 5,
        "name": "hmnd-robot",
        "site": null,
        "status": "active"
      },
      {
        "vid": 16,
        "name": "hmnd-ui",
        "site": null,
        "status": "active"
      }
    ],
    "drift": {
      "gaps": [
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-deploy-01-gw-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-deploy-01",
          "message": "hmnd-deploy-01-gw-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-deploy-01-pi5-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-deploy-01",
          "message": "hmnd-deploy-01-pi5-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-deploy-01-sw-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-deploy-01",
          "message": "hmnd-deploy-01-sw-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-deploy-02-ap-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-deploy-02",
          "message": "hmnd-deploy-02-ap-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-deploy-02-ap-02",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-deploy-02",
          "message": "hmnd-deploy-02-ap-02 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-deploy-02-ap-03",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-deploy-02",
          "message": "hmnd-deploy-02-ap-03 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-deploy-02-gw-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-deploy-02",
          "message": "hmnd-deploy-02-gw-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-deploy-02-inference-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-deploy-02",
          "message": "hmnd-deploy-02-inference-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-deploy-02-pi5-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-deploy-02",
          "message": "hmnd-deploy-02-pi5-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-deploy-02-sw-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-deploy-02",
          "message": "hmnd-deploy-02-sw-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "info",
          "device": "hmnd-deploy-04-ap-01",
          "robot": null,
          "netbox_value": "staged",
          "actual_value": null,
          "site": "hmnd-deploy-04",
          "message": "hmnd-deploy-04-ap-01 (staged) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "info",
          "device": "hmnd-deploy-04-ap-02",
          "robot": null,
          "netbox_value": "staged",
          "actual_value": null,
          "site": "hmnd-deploy-04",
          "message": "hmnd-deploy-04-ap-02 (staged) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "info",
          "device": "hmnd-deploy-04-ap-03",
          "robot": null,
          "netbox_value": "staged",
          "actual_value": null,
          "site": "hmnd-deploy-04",
          "message": "hmnd-deploy-04-ap-03 (staged) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "info",
          "device": "hmnd-deploy-04-gw-01",
          "robot": null,
          "netbox_value": "staged",
          "actual_value": null,
          "site": "hmnd-deploy-04",
          "message": "hmnd-deploy-04-gw-01 (staged) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "info",
          "device": "hmnd-deploy-04-inference-01",
          "robot": null,
          "netbox_value": "staged",
          "actual_value": null,
          "site": "hmnd-deploy-04",
          "message": "hmnd-deploy-04-inference-01 (staged) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "info",
          "device": "hmnd-deploy-04-pi5-01",
          "robot": null,
          "netbox_value": "staged",
          "actual_value": null,
          "site": "hmnd-deploy-04",
          "message": "hmnd-deploy-04-pi5-01 (staged) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "info",
          "device": "hmnd-deploy-04-pi5-02",
          "robot": null,
          "netbox_value": "staged",
          "actual_value": null,
          "site": "hmnd-deploy-04",
          "message": "hmnd-deploy-04-pi5-02 (staged) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "info",
          "device": "hmnd-deploy-04-pi5-03",
          "robot": null,
          "netbox_value": "staged",
          "actual_value": null,
          "site": "hmnd-deploy-04",
          "message": "hmnd-deploy-04-pi5-03 (staged) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "info",
          "device": "hmnd-deploy-04-sw-01",
          "robot": null,
          "netbox_value": "staged",
          "actual_value": null,
          "site": "hmnd-deploy-04",
          "message": "hmnd-deploy-04-sw-01 (staged) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-lab-gw-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-lon-lab",
          "message": "hmnd-lab-gw-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-lab-gw-02",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-lon-lab",
          "message": "hmnd-lab-gw-02 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-lab-nas-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-lon-lab",
          "message": "hmnd-lab-nas-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-lab-nvr-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-lon-lab",
          "message": "hmnd-lab-nvr-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-lab-sw-01",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-lon-lab",
          "message": "hmnd-lab-sw-01 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_unifi",
          "severity": "critical",
          "device": "hmnd-lab-sw-02",
          "robot": null,
          "netbox_value": "active",
          "actual_value": null,
          "site": "hmnd-lon-lab",
          "message": "hmnd-lab-sw-02 (active) in Netbox but not found in Unifi"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "ECS 48 PoE | 9",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "ECS 48 PoE | 9 found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "USW Pro Max 16 PoE | 18 (Desk)",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "USW Pro Max 16 PoE | 18 (Desk) found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "E7 | SW SER",
          "robot": null,
          "netbox_value": null,
          "actual_value": "uap",
          "site": "1-triton",
          "message": "E7 | SW SER found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "UPS Tower",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "UPS Tower found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "1 Triton",
          "robot": null,
          "netbox_value": null,
          "actual_value": "udm",
          "site": "1-triton",
          "message": "1 Triton found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "U7 Pro XG Wall | TEC-3 Cab",
          "robot": null,
          "netbox_value": null,
          "actual_value": "uap",
          "site": "1-triton",
          "message": "U7 Pro XG Wall | TEC-3 Cab found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "ECS 24 PoE",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "ECS 24 PoE found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "E7 Campus | Float",
          "robot": null,
          "netbox_value": null,
          "actual_value": "uap",
          "site": "1-triton",
          "message": "E7 Campus | Float found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "AirWire",
          "robot": null,
          "netbox_value": null,
          "actual_value": "uacc",
          "site": "1-triton",
          "message": "AirWire found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "EAV XG 24 PoE | NE SER ",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "EAV XG 24 PoE | NE SER  found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "E7 Lift Lobby ",
          "robot": null,
          "netbox_value": null,
          "actual_value": "uap",
          "site": "1-triton",
          "message": "E7 Lift Lobby  found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "USW Flex 2.5G 8 PoE",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "USW Flex 2.5G 8 PoE found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "USW Pro XG 24 PoE | 2 | Replacement",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "USW Pro XG 24 PoE | 2 | Replacement found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "UDB Switch | Stores",
          "robot": null,
          "netbox_value": null,
          "actual_value": "udb",
          "site": "1-triton",
          "message": "UDB Switch | Stores found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "E7 Audience | SW Plant Room",
          "robot": null,
          "netbox_value": null,
          "actual_value": "uap",
          "site": "1-triton",
          "message": "E7 Audience | SW Plant Room found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "ECS Aggregation South",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "ECS Aggregation South found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "U5G Max Outdoor",
          "robot": null,
          "netbox_value": null,
          "actual_value": "umbb",
          "site": "1-triton",
          "message": "U5G Max Outdoor found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "USW Pro XG 8 PoE | Stores Rack",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "USW Pro XG 8 PoE | Stores Rack found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "USW WAN | SW (Secondary)",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "USW WAN | SW (Secondary) found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "ECS Aggregation North",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "ECS Aggregation North found in Unifi (1-triton) but not documented in Netbox"
        },
        {
          "type": "missing_in_netbox",
          "severity": "info",
          "device": "USP RPS",
          "robot": null,
          "netbox_value": null,
          "actual_value": "usw",
          "site": "1-triton",
          "message": "USP RPS found in Unifi (1-triton) but not documented in Netbox"
        }
      ],
      "summary": {
        "total_gaps": 46,
        "critical": 16,
        "warnings": 0,
        "info": 30,
        "netbox_devices": 49,
        "unifi_devices": 21,
        "documented_pct": 119
      }
    }
  },
  "fleet_dns": {
    "updated": "2026-07-25T08:26:58.143589+00:00",
    "status": "ok",
    "zone_id": "Z0843494QQHALA69EIET",
    "records_upserted": 11,
    "records": [
      {
        "name": "aw3.robots.hmnd.ai",
        "ip": "10.10.50.103",
        "site": "1-triton (last seen)"
      },
      {
        "name": "ab3.robots.hmnd.ai",
        "ip": "10.10.51.103",
        "site": "1-triton (last seen)"
      },
      {
        "name": "aw12.robots.hmnd.ai",
        "ip": "10.10.50.112",
        "site": "1-triton (last seen)"
      },
      {
        "name": "aw2.robots.hmnd.ai",
        "ip": "10.10.50.102",
        "site": "1-triton (last seen)"
      },
      {
        "name": "aw7.robots.hmnd.ai",
        "ip": "10.10.50.107",
        "site": "1-triton (last seen)"
      },
      {
        "name": "aw6.robots.hmnd.ai",
        "ip": "10.10.50.106",
        "site": "1-triton (last seen)"
      },
      {
        "name": "aw5.robots.hmnd.ai",
        "ip": "10.10.50.105",
        "site": "1-triton (last seen)"
      },
      {
        "name": "aw10.robots.hmnd.ai",
        "ip": "10.10.50.110",
        "site": "1-triton (last seen)"
      },
      {
        "name": "aw9.robots.hmnd.ai",
        "ip": "10.10.50.109",
        "site": "1-triton (last seen)"
      },
      {
        "name": "aw11.robots.hmnd.ai",
        "ip": "10.10.50.111",
        "site": "1-triton (last seen)"
      },
      {
        "name": "ab2.robots.hmnd.ai",
        "ip": "10.10.51.102",
        "site": "1-triton (last seen)"
      }
    ]
  },
  "system_data": {
    "updated": "2026-07-25T08:27:09.849741+00:00",
    "robots": {
      "ab3": {
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "alphabiped03-orin",
          "uptime_seconds": "226",
          "memory_total_mb": "54793",
          "memory_free_mb": "51790",
          "release": null,
          "collected_at": "2026-03-27T14:31:12Z",
          "dns": {
            "servers": {
              "global": "8.8.8.8 1.1.1.1"
            },
            "search_domains": {},
            "dropins": "[Resolve]\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": false,
              "route53": false,
              "private": false,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-03-27T14:32:14+00:00"
        },
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alphabiped03-x86",
          "uptime_seconds": "404",
          "memory_total_mb": "47921",
          "memory_free_mb": "46687",
          "release": null,
          "collected_at": "2026-03-27T15:30:22Z",
          "dns": {
            "servers": {
              "wifi-0": "10.44.10.1"
            },
            "search_domains": {
              "wifi-0": "hmnd.lan"
            },
            "dropins": "no drop-ins",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "c4:03:a8:32:e9:b6",
              "ssid": "Alpha",
              "channel": 36,
              "configured_ssid": "Alpha"
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "DOWN",
              "ip": null,
              "mac": "00:13:95:6a:22:0a"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.113",
              "mac": "c4:03:a8:32:e9:b6"
            }
          ],
          "nm_profiles": [
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 900,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "roadkill",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-03-27T15:32:10+00:00"
        }
      },
      "aw10": {
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "orinalpha10",
          "uptime_seconds": "2878",
          "memory_total_mb": "54793",
          "memory_free_mb": "45991",
          "release": null,
          "collected_at": "2026-04-09T16:01:21Z",
          "dns": {
            "servers": {
              "global": "10.44.10.1"
            },
            "search_domains": {},
            "dropins": "[Resolve]\nDNS=10.44.10.1\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-09T16:02:09+00:00"
        },
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alpha10",
          "uptime_seconds": "2874",
          "memory_total_mb": "47921",
          "memory_free_mb": "44601",
          "release": null,
          "collected_at": "2026-04-09T16:00:26Z",
          "dns": {
            "servers": {
              "wifi-0": "10.44.10.1"
            },
            "search_domains": {
              "wifi-0": "hmnd.lan"
            },
            "dropins": "no drop-ins",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "5c:b2:6d:46:6d:88",
              "ssid": "Alpha",
              "channel": 104,
              "configured_ssid": "Alpha",
              "station": {
                "rx_packets": 321333,
                "tx_packets": 714183,
                "tx_retries": 23215,
                "tx_failed": 0,
                "beacon_loss": 0,
                "rx_drop_misc": 3807,
                "signal_dbm": -35,
                "signal_per_antenna": "[-44, -35]",
                "tx_bitrate": "243.7 MBit/s HE-MCS 10 HE-NSS 2 HE-GI 1 HE-DCM 0",
                "rx_bitrate": "258.0 MBit/s HE-MCS 10 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "connected_seconds": 2893
              }
            },
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "58:6d:67:f7:d1:9f",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "DOWN",
              "ip": null,
              "mac": "00:13:95:6a:22:10"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "58:6d:67:f7:d1:9f"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.20",
              "mac": "5c:b2:6d:46:6d:88"
            }
          ],
          "nm_profiles": [
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 900,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": "internal",
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-09T16:02:08+00:00"
        }
      },
      "ab1": {
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alphabiped01-x86",
          "uptime_seconds": "85924",
          "memory_total_mb": "47921",
          "memory_free_mb": "45538",
          "release": null,
          "collected_at": "2026-04-02T12:30:19Z",
          "dns": {
            "servers": {
              "wifi-0": "10.44.10.1"
            },
            "search_domains": {
              "wifi-0": "hmnd.lan"
            },
            "dropins": "no drop-ins",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "8c:f8:c5:b5:f3:c0",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            },
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "8c:f8:c5:b5:f3:bf",
              "ssid": "Alpha",
              "channel": 85,
              "configured_ssid": "Alpha",
              "station": {
                "rx_packets": 2673194,
                "tx_packets": 2082579,
                "tx_retries": 36245,
                "tx_failed": 0,
                "beacon_loss": 0,
                "rx_drop_misc": 655565,
                "signal_dbm": -47,
                "signal_per_antenna": "[-47, -53]",
                "tx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "rx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "connected_seconds": 85425
              }
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "DOWN",
              "ip": null,
              "mac": "00:13:95:65:f1:5c"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.99",
              "mac": "8c:f8:c5:b5:f3:bf"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "8c:f8:c5:b5:f2:f2"
            }
          ],
          "nm_profiles": [
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 980,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "hmnd-6ghz",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 900,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "wifi",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-02T14:32:49+00:00"
        },
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "alphabiped01-orin",
          "uptime_seconds": "84128",
          "memory_total_mb": "54793",
          "memory_free_mb": "50865",
          "release": null,
          "collected_at": "2026-04-02T12:01:13Z",
          "dns": {
            "servers": {},
            "search_domains": {},
            "dropins": "[Resolve]\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": false,
              "route53": false,
              "private": false,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-02T12:02:19+00:00"
        }
      },
      "aw11": {
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alpha11",
          "uptime_seconds": 21997,
          "memory_total_mb": 47924,
          "memory_free_mb": 42169,
          "release": null,
          "collected_at": "2026-04-10T13:15:40Z",
          "dns": {
            "servers": {
              "eth-shore": "10.44.10.1",
              "wifi-0": "10.44.10.1"
            },
            "search_domains": {
              "eth-shore": "hmnd.lan",
              "wifi-0": "hmnd.lan"
            },
            "dropins": "no drop-ins",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "58:6d:67:f7:d1:37",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            },
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "58:6d:67:f7:d1:36",
              "ssid": "Alpha",
              "channel": 104,
              "configured_ssid": "Alpha",
              "station": {
                "rx_packets": 2409003,
                "tx_packets": 31997,
                "tx_retries": 28,
                "tx_failed": 0,
                "beacon_loss": 0,
                "rx_drop_misc": 23572,
                "signal_dbm": -39,
                "signal_per_antenna": "[-39, -46]",
                "tx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "rx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "connected_seconds": 21987
              }
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "UP",
              "ip": "10.44.10.14",
              "mac": "00:13:95:68:c3:93"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.111",
              "mac": "58:6d:67:f7:d1:36"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "58:6d:67:f7:d0:ff"
            }
          ],
          "nm_profiles": [
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "eth-shore",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 900,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "hmnd-6ghz",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [
              {
                "index": -17,
                "start": "2026-03-30T23:20:14+00:00",
                "end": "2026-03-31T20:49:59+00:00",
                "duration_seconds": 77385,
                "running": false
              },
              {
                "index": -16,
                "start": "2026-03-31T20:55:02+00:00",
                "end": "2026-04-01T13:38:39+00:00",
                "duration_seconds": 60217,
                "running": false
              },
              {
                "index": -15,
                "start": "2026-04-01T13:44:26+00:00",
                "end": "2026-04-01T15:16:33+00:00",
                "duration_seconds": 5527,
                "running": false
              },
              {
                "index": -14,
                "start": "2026-04-01T15:25:29+00:00",
                "end": "2026-04-01T15:43:00+00:00",
                "duration_seconds": 1051,
                "running": false
              },
              {
                "index": -13,
                "start": "2026-04-01T15:45:45+00:00",
                "end": "2026-04-01T17:57:11+00:00",
                "duration_seconds": 7886,
                "running": false
              },
              {
                "index": -12,
                "start": "2026-04-01T17:58:01+00:00",
                "end": "2026-04-01T19:28:44+00:00",
                "duration_seconds": 5443,
                "running": false
              },
              {
                "index": -11,
                "start": "2026-04-01T19:32:03+00:00",
                "end": "2026-04-03T02:00:38+00:00",
                "duration_seconds": 109715,
                "running": false
              },
              {
                "index": -10,
                "start": "2026-04-07T05:43:04+00:00",
                "end": "2026-04-07T07:56:51+00:00",
                "duration_seconds": 8027,
                "running": false
              },
              {
                "index": -9,
                "start": "2026-04-07T07:57:39+00:00",
                "end": "2026-04-09T08:12:22+00:00",
                "duration_seconds": 173683,
                "running": false
              },
              {
                "index": -8,
                "start": "2026-04-09T08:13:53+00:00",
                "end": "2026-04-09T12:34:54+00:00",
                "duration_seconds": 15661,
                "running": false
              },
              {
                "index": -7,
                "start": "2026-04-09T12:36:53+00:00",
                "end": "2026-04-09T12:37:44+00:00",
                "duration_seconds": 51,
                "running": false
              },
              {
                "index": -6,
                "start": "2026-04-09T12:40:38+00:00",
                "end": "2026-04-09T13:41:15+00:00",
                "duration_seconds": 3637,
                "running": false
              },
              {
                "index": -5,
                "start": "2026-04-09T13:42:07+00:00",
                "end": "2026-04-09T13:50:46+00:00",
                "duration_seconds": 519,
                "running": false
              },
              {
                "index": -4,
                "start": "2026-04-09T13:51:36+00:00",
                "end": "2026-04-09T21:05:44+00:00",
                "duration_seconds": 26048,
                "running": false
              },
              {
                "index": -3,
                "start": "2026-04-09T21:08:49+00:00",
                "end": "2026-04-09T21:23:43+00:00",
                "duration_seconds": 894,
                "running": false
              },
              {
                "index": -2,
                "start": "2026-04-09T21:25:02+00:00",
                "end": "2026-04-09T21:35:38+00:00",
                "duration_seconds": 636,
                "running": false
              },
              {
                "index": -1,
                "start": "2026-04-09T21:36:57+00:00",
                "end": "2026-04-10T07:08:08+00:00",
                "duration_seconds": 34271,
                "running": false
              },
              {
                "index": 0,
                "start": "2026-04-10T07:09:11+00:00",
                "end": "2026-04-10T13:15:55+00:00",
                "duration_seconds": 22004,
                "running": false
              }
            ],
            "daily_seconds": {
              "2026-03-30": 2386.0,
              "2026-03-31": 86097.0,
              "2026-04-01": 85103.0,
              "2026-04-02": 86400.0,
              "2026-04-03": 7238.0,
              "2026-04-07": 65768.0,
              "2026-04-08": 86400.0,
              "2026-04-09": 85571.0,
              "2026-04-10": 47692.0
            },
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-10T13:16:49+00:00"
        },
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "orinalpha11",
          "uptime_seconds": 4554,
          "memory_total_mb": 54792,
          "memory_free_mb": 47130,
          "release": null,
          "collected_at": "2026-04-10T13:15:58Z",
          "dns": {
            "servers": {
              "global": "8.8.8.8"
            },
            "search_domains": {},
            "dropins": "[Resolve]\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": false,
              "route53": false,
              "private": false,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [
              {
                "index": 0,
                "start": "2025-08-26T15:23:06+00:00",
                "end": "2026-04-10T13:16:17+00:00",
                "duration_seconds": 19605191,
                "running": false
              }
            ],
            "daily_seconds": {
              "2025-08-26": 31014.0,
              "2025-08-27": 86400.0,
              "2025-08-28": 86400.0,
              "2025-08-29": 86400.0,
              "2025-08-30": 86400.0,
              "2025-08-31": 86400.0,
              "2025-09-01": 86400.0,
              "2025-09-02": 86400.0,
              "2025-09-03": 86400.0,
              "2025-09-04": 86400.0,
              "2025-09-05": 86400.0,
              "2025-09-06": 86400.0,
              "2025-09-07": 86400.0,
              "2025-09-08": 86400.0,
              "2025-09-09": 86400.0,
              "2025-09-10": 86400.0,
              "2025-09-11": 86400.0,
              "2025-09-12": 86400.0,
              "2025-09-13": 86400.0,
              "2025-09-14": 86400.0,
              "2025-09-15": 86400.0,
              "2025-09-16": 86400.0,
              "2025-09-17": 86400.0,
              "2025-09-18": 86400.0,
              "2025-09-19": 86400.0,
              "2025-09-20": 86400.0,
              "2025-09-21": 86400.0,
              "2025-09-22": 86400.0,
              "2025-09-23": 86400.0,
              "2025-09-24": 86400.0,
              "2025-09-25": 86400.0,
              "2025-09-26": 86400.0,
              "2025-09-27": 86400.0,
              "2025-09-28": 86400.0,
              "2025-09-29": 86400.0,
              "2025-09-30": 86400.0,
              "2025-10-01": 86400.0,
              "2025-10-02": 86400.0,
              "2025-10-03": 86400.0,
              "2025-10-04": 86400.0,
              "2025-10-05": 86400.0,
              "2025-10-06": 86400.0,
              "2025-10-07": 86400.0,
              "2025-10-08": 86400.0,
              "2025-10-09": 86400.0,
              "2025-10-10": 86400.0,
              "2025-10-11": 86400.0,
              "2025-10-12": 86400.0,
              "2025-10-13": 86400.0,
              "2025-10-14": 86400.0,
              "2025-10-15": 86400.0,
              "2025-10-16": 86400.0,
              "2025-10-17": 86400.0,
              "2025-10-18": 86400.0,
              "2025-10-19": 86400.0,
              "2025-10-20": 86400.0,
              "2025-10-21": 86400.0,
              "2025-10-22": 86400.0,
              "2025-10-23": 86400.0,
              "2025-10-24": 86400.0,
              "2025-10-25": 86400.0,
              "2025-10-26": 86400.0,
              "2025-10-27": 86400.0,
              "2025-10-28": 86400.0,
              "2025-10-29": 86400.0,
              "2025-10-30": 86400.0,
              "2025-10-31": 86400.0,
              "2025-11-01": 86400.0,
              "2025-11-02": 86400.0,
              "2025-11-03": 86400.0,
              "2025-11-04": 86400.0,
              "2025-11-05": 86400.0,
              "2025-11-06": 86400.0,
              "2025-11-07": 86400.0,
              "2025-11-08": 86400.0,
              "2025-11-09": 86400.0,
              "2025-11-10": 86400.0,
              "2025-11-11": 86400.0,
              "2025-11-12": 86400.0,
              "2025-11-13": 86400.0,
              "2025-11-14": 86400.0,
              "2025-11-15": 86400.0,
              "2025-11-16": 86400.0,
              "2025-11-17": 86400.0,
              "2025-11-18": 86400.0,
              "2025-11-19": 86400.0,
              "2025-11-20": 86400.0,
              "2025-11-21": 86400.0,
              "2025-11-22": 86400.0,
              "2025-11-23": 86400.0,
              "2025-11-24": 86400.0,
              "2025-11-25": 86400.0,
              "2025-11-26": 86400.0,
              "2025-11-27": 86400.0,
              "2025-11-28": 86400.0,
              "2025-11-29": 86400.0,
              "2025-11-30": 86400.0,
              "2025-12-01": 86400.0,
              "2025-12-02": 86400.0,
              "2025-12-03": 86400.0,
              "2025-12-04": 86400.0,
              "2025-12-05": 86400.0,
              "2025-12-06": 86400.0,
              "2025-12-07": 86400.0,
              "2025-12-08": 86400.0,
              "2025-12-09": 86400.0,
              "2025-12-10": 86400.0,
              "2025-12-11": 86400.0,
              "2025-12-12": 86400.0,
              "2025-12-13": 86400.0,
              "2025-12-14": 86400.0,
              "2025-12-15": 86400.0,
              "2025-12-16": 86400.0,
              "2025-12-17": 86400.0,
              "2025-12-18": 86400.0,
              "2025-12-19": 86400.0,
              "2025-12-20": 86400.0,
              "2025-12-21": 86400.0,
              "2025-12-22": 86400.0,
              "2025-12-23": 86400.0,
              "2025-12-24": 86400.0,
              "2025-12-25": 86400.0,
              "2025-12-26": 86400.0,
              "2025-12-27": 86400.0,
              "2025-12-28": 86400.0,
              "2025-12-29": 86400.0,
              "2025-12-30": 86400.0,
              "2025-12-31": 86400.0,
              "2026-01-01": 86400.0,
              "2026-01-02": 86400.0,
              "2026-01-03": 86400.0,
              "2026-01-04": 86400.0,
              "2026-01-05": 86400.0,
              "2026-01-06": 86400.0,
              "2026-01-07": 86400.0,
              "2026-01-08": 86400.0,
              "2026-01-09": 86400.0,
              "2026-01-10": 86400.0,
              "2026-01-11": 86400.0,
              "2026-01-12": 86400.0,
              "2026-01-13": 86400.0,
              "2026-01-14": 86400.0,
              "2026-01-15": 86400.0,
              "2026-01-16": 86400.0,
              "2026-01-17": 86400.0,
              "2026-01-18": 86400.0,
              "2026-01-19": 86400.0,
              "2026-01-20": 86400.0,
              "2026-01-21": 86400.0,
              "2026-01-22": 86400.0,
              "2026-01-23": 86400.0,
              "2026-01-24": 86400.0,
              "2026-01-25": 86400.0,
              "2026-01-26": 86400.0,
              "2026-01-27": 86400.0,
              "2026-01-28": 86400.0,
              "2026-01-29": 86400.0,
              "2026-01-30": 86400.0,
              "2026-01-31": 86400.0,
              "2026-02-01": 86400.0,
              "2026-02-02": 86400.0,
              "2026-02-03": 86400.0,
              "2026-02-04": 86400.0,
              "2026-02-05": 86400.0,
              "2026-02-06": 86400.0,
              "2026-02-07": 86400.0,
              "2026-02-08": 86400.0,
              "2026-02-09": 86400.0,
              "2026-02-10": 86400.0,
              "2026-02-11": 86400.0,
              "2026-02-12": 86400.0,
              "2026-02-13": 86400.0,
              "2026-02-14": 86400.0,
              "2026-02-15": 86400.0,
              "2026-02-16": 86400.0,
              "2026-02-17": 86400.0,
              "2026-02-18": 86400.0,
              "2026-02-19": 86400.0,
              "2026-02-20": 86400.0,
              "2026-02-21": 86400.0,
              "2026-02-22": 86400.0,
              "2026-02-23": 86400.0,
              "2026-02-24": 86400.0,
              "2026-02-25": 86400.0,
              "2026-02-26": 86400.0,
              "2026-02-27": 86400.0,
              "2026-02-28": 86400.0,
              "2026-03-01": 86400.0,
              "2026-03-02": 86400.0,
              "2026-03-03": 86400.0,
              "2026-03-04": 86400.0,
              "2026-03-05": 86400.0,
              "2026-03-06": 86400.0,
              "2026-03-07": 86400.0,
              "2026-03-08": 86400.0,
              "2026-03-09": 86400.0,
              "2026-03-10": 86400.0,
              "2026-03-11": 86400.0,
              "2026-03-12": 86400.0,
              "2026-03-13": 86400.0,
              "2026-03-14": 86400.0,
              "2026-03-15": 86400.0,
              "2026-03-16": 86400.0,
              "2026-03-17": 86400.0,
              "2026-03-18": 86400.0,
              "2026-03-19": 86400.0,
              "2026-03-20": 86400.0,
              "2026-03-21": 86400.0,
              "2026-03-22": 86400.0,
              "2026-03-23": 86400.0,
              "2026-03-24": 86400.0,
              "2026-03-25": 86400.0,
              "2026-03-26": 86400.0,
              "2026-03-27": 86400.0,
              "2026-03-28": 86400.0,
              "2026-03-29": 86400.0,
              "2026-03-30": 86400.0,
              "2026-03-31": 86400.0,
              "2026-04-01": 86400.0,
              "2026-04-02": 86400.0,
              "2026-04-03": 86400.0,
              "2026-04-04": 86400.0,
              "2026-04-05": 86400.0,
              "2026-04-06": 86400.0,
              "2026-04-07": 86400.0,
              "2026-04-08": 86400.0,
              "2026-04-09": 86400.0,
              "2026-04-10": 47777.0
            },
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-10T13:16:49+00:00"
        }
      },
      "aw2": {
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "orinalpha2",
          "uptime_seconds": "10364",
          "memory_total_mb": "54793",
          "memory_free_mb": "47974",
          "release": null,
          "collected_at": "2026-04-09T15:31:24Z",
          "dns": {
            "servers": {
              "global": "192.168.1.1"
            },
            "search_domains": {},
            "dropins": "[Resolve]\nDNS=192.168.1.1\nFallbackDNS=8.8.8.8\n[Resolve]\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": false,
              "route53": false,
              "private": false,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-09T15:32:26+00:00"
        },
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alpha2",
          "uptime_seconds": "10360",
          "memory_total_mb": "31844",
          "memory_free_mb": "28975",
          "release": null,
          "collected_at": "2026-04-09T15:30:23Z",
          "dns": {
            "servers": {
              "wifi-0": "172.31.0.2 8.8.8.8 1.1.1.1 10.44.10.1"
            },
            "search_domains": {
              "wifi-0": "hmnd.lan"
            },
            "dropins": "[Resolve]\nDNSStubListenerExtra=192.168.1.1",
            "zones": {
              "local": false,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "8c:f8:c5:96:2e:cd",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            },
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "8c:f8:c5:96:2e:cc",
              "ssid": "Alpha",
              "channel": 104,
              "configured_ssid": "Alpha",
              "station": {
                "rx_packets": 162955,
                "tx_packets": 39453,
                "tx_retries": 13702,
                "tx_failed": 1,
                "beacon_loss": 0,
                "rx_drop_misc": 12707,
                "signal_dbm": -46,
                "signal_per_antenna": "[-46, -55]",
                "tx_bitrate": "270.8 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 1 HE-DCM 0",
                "rx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "connected_seconds": 6435
              }
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "DOWN",
              "ip": null,
              "mac": "00:13:95:61:a7:cd"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.10",
              "mac": "8c:f8:c5:96:2e:cc"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "8c:f8:c5:b3:81:c5"
            }
          ],
          "nm_profiles": [
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "hmnd-6ghz",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "hmnd-test",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "Roadkill",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-09T15:32:25+00:00"
        }
      },
      "aw12": {
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "orinalpha12",
          "uptime_seconds": 77723,
          "memory_total_mb": 54792,
          "memory_free_mb": 39547,
          "release": null,
          "collected_at": "2026-04-10T12:20:25Z",
          "dns": {
            "servers": {
              "global": "10.44.10.1 192.168.1.1"
            },
            "search_domains": {
              "global": "hmnd.lan lan.thehumanoid.ai robots.hmnd.ai"
            },
            "dropins": "# Managed by Ansible (iac-robots playbook 04)\n# Points DNS at the RTPC stub resolver on the Moxa bridge.\n# 192.168.1.1 is site-independent \u2014 works at any location.\n# The RTPC forwards to whatever upstream DNS it learned from DHCP.\n[Resolve]\nDNS=192.168.1.1\nDomains=hmnd.lan lan.thehumanoid.ai robots.hmnd.ai\nFallbackDNS=8.8.8.8\n[Resolve]\nDNS=192.168.1.1\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [
              {
                "index": 0,
                "start": "2025-08-26T15:23:06+00:00",
                "end": "2026-04-10T12:20:53+00:00",
                "duration_seconds": 19601867,
                "running": false
              }
            ],
            "daily_seconds": {
              "2025-08-26": 31014.0,
              "2025-08-27": 86400.0,
              "2025-08-28": 86400.0,
              "2025-08-29": 86400.0,
              "2025-08-30": 86400.0,
              "2025-08-31": 86400.0,
              "2025-09-01": 86400.0,
              "2025-09-02": 86400.0,
              "2025-09-03": 86400.0,
              "2025-09-04": 86400.0,
              "2025-09-05": 86400.0,
              "2025-09-06": 86400.0,
              "2025-09-07": 86400.0,
              "2025-09-08": 86400.0,
              "2025-09-09": 86400.0,
              "2025-09-10": 86400.0,
              "2025-09-11": 86400.0,
              "2025-09-12": 86400.0,
              "2025-09-13": 86400.0,
              "2025-09-14": 86400.0,
              "2025-09-15": 86400.0,
              "2025-09-16": 86400.0,
              "2025-09-17": 86400.0,
              "2025-09-18": 86400.0,
              "2025-09-19": 86400.0,
              "2025-09-20": 86400.0,
              "2025-09-21": 86400.0,
              "2025-09-22": 86400.0,
              "2025-09-23": 86400.0,
              "2025-09-24": 86400.0,
              "2025-09-25": 86400.0,
              "2025-09-26": 86400.0,
              "2025-09-27": 86400.0,
              "2025-09-28": 86400.0,
              "2025-09-29": 86400.0,
              "2025-09-30": 86400.0,
              "2025-10-01": 86400.0,
              "2025-10-02": 86400.0,
              "2025-10-03": 86400.0,
              "2025-10-04": 86400.0,
              "2025-10-05": 86400.0,
              "2025-10-06": 86400.0,
              "2025-10-07": 86400.0,
              "2025-10-08": 86400.0,
              "2025-10-09": 86400.0,
              "2025-10-10": 86400.0,
              "2025-10-11": 86400.0,
              "2025-10-12": 86400.0,
              "2025-10-13": 86400.0,
              "2025-10-14": 86400.0,
              "2025-10-15": 86400.0,
              "2025-10-16": 86400.0,
              "2025-10-17": 86400.0,
              "2025-10-18": 86400.0,
              "2025-10-19": 86400.0,
              "2025-10-20": 86400.0,
              "2025-10-21": 86400.0,
              "2025-10-22": 86400.0,
              "2025-10-23": 86400.0,
              "2025-10-24": 86400.0,
              "2025-10-25": 86400.0,
              "2025-10-26": 86400.0,
              "2025-10-27": 86400.0,
              "2025-10-28": 86400.0,
              "2025-10-29": 86400.0,
              "2025-10-30": 86400.0,
              "2025-10-31": 86400.0,
              "2025-11-01": 86400.0,
              "2025-11-02": 86400.0,
              "2025-11-03": 86400.0,
              "2025-11-04": 86400.0,
              "2025-11-05": 86400.0,
              "2025-11-06": 86400.0,
              "2025-11-07": 86400.0,
              "2025-11-08": 86400.0,
              "2025-11-09": 86400.0,
              "2025-11-10": 86400.0,
              "2025-11-11": 86400.0,
              "2025-11-12": 86400.0,
              "2025-11-13": 86400.0,
              "2025-11-14": 86400.0,
              "2025-11-15": 86400.0,
              "2025-11-16": 86400.0,
              "2025-11-17": 86400.0,
              "2025-11-18": 86400.0,
              "2025-11-19": 86400.0,
              "2025-11-20": 86400.0,
              "2025-11-21": 86400.0,
              "2025-11-22": 86400.0,
              "2025-11-23": 86400.0,
              "2025-11-24": 86400.0,
              "2025-11-25": 86400.0,
              "2025-11-26": 86400.0,
              "2025-11-27": 86400.0,
              "2025-11-28": 86400.0,
              "2025-11-29": 86400.0,
              "2025-11-30": 86400.0,
              "2025-12-01": 86400.0,
              "2025-12-02": 86400.0,
              "2025-12-03": 86400.0,
              "2025-12-04": 86400.0,
              "2025-12-05": 86400.0,
              "2025-12-06": 86400.0,
              "2025-12-07": 86400.0,
              "2025-12-08": 86400.0,
              "2025-12-09": 86400.0,
              "2025-12-10": 86400.0,
              "2025-12-11": 86400.0,
              "2025-12-12": 86400.0,
              "2025-12-13": 86400.0,
              "2025-12-14": 86400.0,
              "2025-12-15": 86400.0,
              "2025-12-16": 86400.0,
              "2025-12-17": 86400.0,
              "2025-12-18": 86400.0,
              "2025-12-19": 86400.0,
              "2025-12-20": 86400.0,
              "2025-12-21": 86400.0,
              "2025-12-22": 86400.0,
              "2025-12-23": 86400.0,
              "2025-12-24": 86400.0,
              "2025-12-25": 86400.0,
              "2025-12-26": 86400.0,
              "2025-12-27": 86400.0,
              "2025-12-28": 86400.0,
              "2025-12-29": 86400.0,
              "2025-12-30": 86400.0,
              "2025-12-31": 86400.0,
              "2026-01-01": 86400.0,
              "2026-01-02": 86400.0,
              "2026-01-03": 86400.0,
              "2026-01-04": 86400.0,
              "2026-01-05": 86400.0,
              "2026-01-06": 86400.0,
              "2026-01-07": 86400.0,
              "2026-01-08": 86400.0,
              "2026-01-09": 86400.0,
              "2026-01-10": 86400.0,
              "2026-01-11": 86400.0,
              "2026-01-12": 86400.0,
              "2026-01-13": 86400.0,
              "2026-01-14": 86400.0,
              "2026-01-15": 86400.0,
              "2026-01-16": 86400.0,
              "2026-01-17": 86400.0,
              "2026-01-18": 86400.0,
              "2026-01-19": 86400.0,
              "2026-01-20": 86400.0,
              "2026-01-21": 86400.0,
              "2026-01-22": 86400.0,
              "2026-01-23": 86400.0,
              "2026-01-24": 86400.0,
              "2026-01-25": 86400.0,
              "2026-01-26": 86400.0,
              "2026-01-27": 86400.0,
              "2026-01-28": 86400.0,
              "2026-01-29": 86400.0,
              "2026-01-30": 86400.0,
              "2026-01-31": 86400.0,
              "2026-02-01": 86400.0,
              "2026-02-02": 86400.0,
              "2026-02-03": 86400.0,
              "2026-02-04": 86400.0,
              "2026-02-05": 86400.0,
              "2026-02-06": 86400.0,
              "2026-02-07": 86400.0,
              "2026-02-08": 86400.0,
              "2026-02-09": 86400.0,
              "2026-02-10": 86400.0,
              "2026-02-11": 86400.0,
              "2026-02-12": 86400.0,
              "2026-02-13": 86400.0,
              "2026-02-14": 86400.0,
              "2026-02-15": 86400.0,
              "2026-02-16": 86400.0,
              "2026-02-17": 86400.0,
              "2026-02-18": 86400.0,
              "2026-02-19": 86400.0,
              "2026-02-20": 86400.0,
              "2026-02-21": 86400.0,
              "2026-02-22": 86400.0,
              "2026-02-23": 86400.0,
              "2026-02-24": 86400.0,
              "2026-02-25": 86400.0,
              "2026-02-26": 86400.0,
              "2026-02-27": 86400.0,
              "2026-02-28": 86400.0,
              "2026-03-01": 86400.0,
              "2026-03-02": 86400.0,
              "2026-03-03": 86400.0,
              "2026-03-04": 86400.0,
              "2026-03-05": 86400.0,
              "2026-03-06": 86400.0,
              "2026-03-07": 86400.0,
              "2026-03-08": 86400.0,
              "2026-03-09": 86400.0,
              "2026-03-10": 86400.0,
              "2026-03-11": 86400.0,
              "2026-03-12": 86400.0,
              "2026-03-13": 86400.0,
              "2026-03-14": 86400.0,
              "2026-03-15": 86400.0,
              "2026-03-16": 86400.0,
              "2026-03-17": 86400.0,
              "2026-03-18": 86400.0,
              "2026-03-19": 86400.0,
              "2026-03-20": 86400.0,
              "2026-03-21": 86400.0,
              "2026-03-22": 86400.0,
              "2026-03-23": 86400.0,
              "2026-03-24": 86400.0,
              "2026-03-25": 86400.0,
              "2026-03-26": 86400.0,
              "2026-03-27": 86400.0,
              "2026-03-28": 86400.0,
              "2026-03-29": 86400.0,
              "2026-03-30": 86400.0,
              "2026-03-31": 86400.0,
              "2026-04-01": 86400.0,
              "2026-04-02": 86400.0,
              "2026-04-03": 86400.0,
              "2026-04-04": 86400.0,
              "2026-04-05": 86400.0,
              "2026-04-06": 86400.0,
              "2026-04-07": 86400.0,
              "2026-04-08": 86400.0,
              "2026-04-09": 86400.0,
              "2026-04-10": 44453.0
            },
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-10T12:21:23+00:00"
        },
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alpha12",
          "uptime_seconds": 77769,
          "memory_total_mb": 47921,
          "memory_free_mb": 34708,
          "release": null,
          "collected_at": "2026-04-10T12:19:40Z",
          "dns": {
            "servers": {
              "wifi-0": "10.44.10.1"
            },
            "search_domains": {
              "wifi-0": "hmnd.lan"
            },
            "dropins": "# Managed by Ansible (iac-robots playbook 04)\n# Exposes the DNS stub resolver on sw-internal (192.168.1.1)\n# so the Orin and other Moxa devices can use the RTPC as a DNS forwarder.\n# The stub resolver automatically uses whatever upstream DNS the RTPC\n# learned from DHCP \u2014 works at any site without reconfiguration.\n[Resolve]\nDNSStubListenerExtra=192.168.1.1",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "c4:03:a8:32:ee:44",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            },
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "c4:03:a8:32:ee:43",
              "ssid": "Alpha",
              "channel": 157,
              "configured_ssid": "Alpha",
              "station": {
                "rx_packets": 29712955,
                "tx_packets": 60993054,
                "tx_retries": 8651,
                "tx_failed": 0,
                "beacon_loss": 0,
                "rx_drop_misc": 87401,
                "signal_dbm": -44,
                "signal_per_antenna": "[-52, -44]",
                "tx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "rx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "connected_seconds": 77770
              }
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "DOWN",
              "ip": null,
              "mac": "00:13:95:68:c2:fb"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.22",
              "mac": "c4:03:a8:32:ee:43"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "c4:03:a8:32:e6:cd"
            }
          ],
          "nm_profiles": [
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [
              {
                "index": -50,
                "start": "2026-03-24T11:03:18+00:00",
                "end": "2026-03-24T16:15:48+00:00",
                "duration_seconds": 18750,
                "running": false
              },
              {
                "index": -49,
                "start": "2026-03-24T16:16:40+00:00",
                "end": "2026-03-24T17:25:56+00:00",
                "duration_seconds": 4156,
                "running": false
              },
              {
                "index": -48,
                "start": "2026-03-24T19:40:44+00:00",
                "end": "2026-03-24T19:43:50+00:00",
                "duration_seconds": 186,
                "running": false
              },
              {
                "index": -47,
                "start": "2026-03-24T20:52:51+00:00",
                "end": "2026-03-24T20:58:31+00:00",
                "duration_seconds": 340,
                "running": false
              },
              {
                "index": -46,
                "start": "2026-03-24T21:08:33+00:00",
                "end": "2026-03-24T21:10:26+00:00",
                "duration_seconds": 113,
                "running": false
              },
              {
                "index": -45,
                "start": "2026-03-25T08:41:37+00:00",
                "end": "2026-03-25T08:48:07+00:00",
                "duration_seconds": 390,
                "running": false
              },
              {
                "index": -44,
                "start": "2026-03-25T09:16:13+00:00",
                "end": "2026-03-25T09:25:10+00:00",
                "duration_seconds": 537,
                "running": false
              },
              {
                "index": -43,
                "start": "2026-03-25T09:36:45+00:00",
                "end": "2026-03-25T09:38:59+00:00",
                "duration_seconds": 134,
                "running": false
              },
              {
                "index": -42,
                "start": "2026-03-25T09:40:27+00:00",
                "end": "2026-03-25T09:41:48+00:00",
                "duration_seconds": 81,
                "running": false
              },
              {
                "index": -41,
                "start": "2026-03-25T10:07:31+00:00",
                "end": "2026-03-25T10:08:58+00:00",
                "duration_seconds": 87,
                "running": false
              },
              {
                "index": -40,
                "start": "2026-03-25T10:25:04+00:00",
                "end": "2026-03-25T10:46:15+00:00",
                "duration_seconds": 1271,
                "running": false
              },
              {
                "index": -39,
                "start": "2026-03-25T12:22:30+00:00",
                "end": "2026-03-25T12:24:18+00:00",
                "duration_seconds": 108,
                "running": false
              },
              {
                "index": -38,
                "start": "2026-03-25T12:26:24+00:00",
                "end": "2026-03-25T12:27:35+00:00",
                "duration_seconds": 71,
                "running": false
              },
              {
                "index": -37,
                "start": "2026-03-25T12:33:28+00:00",
                "end": "2026-03-25T12:41:07+00:00",
                "duration_seconds": 459,
                "running": false
              },
              {
                "index": -36,
                "start": "2026-03-25T12:43:01+00:00",
                "end": "2026-03-25T16:29:56+00:00",
                "duration_seconds": 13615,
                "running": false
              },
              {
                "index": -35,
                "start": "2026-03-25T17:07:14+00:00",
                "end": "2026-03-25T17:27:21+00:00",
                "duration_seconds": 1207,
                "running": false
              },
              {
                "index": -34,
                "start": "2026-03-25T17:28:55+00:00",
                "end": "2026-03-25T19:41:53+00:00",
                "duration_seconds": 7978,
                "running": false
              },
              {
                "index": -33,
                "start": "2026-03-25T20:45:59+00:00",
                "end": "2026-03-25T23:59:34+00:00",
                "duration_seconds": 11615,
                "running": false
              },
              {
                "index": -32,
                "start": "2026-03-26T00:01:36+00:00",
                "end": "2026-03-26T02:37:59+00:00",
                "duration_seconds": 9383,
                "running": false
              },
              {
                "index": -31,
                "start": "2026-03-26T04:15:45+00:00",
                "end": "2026-03-26T04:42:49+00:00",
                "duration_seconds": 1624,
                "running": false
              },
              {
                "index": -30,
                "start": "2026-03-26T07:01:38+00:00",
                "end": "2026-03-26T13:53:09+00:00",
                "duration_seconds": 24691,
                "running": false
              },
              {
                "index": -29,
                "start": "2026-03-26T13:53:58+00:00",
                "end": "2026-03-26T14:24:25+00:00",
                "duration_seconds": 1827,
                "running": false
              },
              {
                "index": -28,
                "start": "2026-03-26T14:25:15+00:00",
                "end": "2026-03-26T17:43:56+00:00",
                "duration_seconds": 11921,
                "running": false
              },
              {
                "index": -27,
                "start": "2026-03-26T18:02:47+00:00",
                "end": "2026-03-26T18:16:22+00:00",
                "duration_seconds": 815,
                "running": false
              },
              {
                "index": -26,
                "start": "2026-03-27T20:56:59+00:00",
                "end": "2026-03-27T21:08:53+00:00",
                "duration_seconds": 714,
                "running": false
              },
              {
                "index": -25,
                "start": "2026-03-27T21:09:30+00:00",
                "end": "2026-03-27T21:09:30+00:00",
                "duration_seconds": 0,
                "running": false
              },
              {
                "index": -24,
                "start": "2026-03-27T22:51:56+00:00",
                "end": "2026-03-27T22:58:47+00:00",
                "duration_seconds": 411,
                "running": false
              },
              {
                "index": -23,
                "start": "2026-03-28T17:22:53+00:00",
                "end": "2026-03-28T17:49:11+00:00",
                "duration_seconds": 1578,
                "running": false
              },
              {
                "index": -22,
                "start": "2026-03-30T05:45:40+00:00",
                "end": "2026-03-30T07:21:38+00:00",
                "duration_seconds": 5758,
                "running": false
              },
              {
                "index": -21,
                "start": "2026-03-30T09:17:10+00:00",
                "end": "2026-03-30T09:18:46+00:00",
                "duration_seconds": 96,
                "running": false
              },
              {
                "index": -20,
                "start": "2026-03-30T09:21:23+00:00",
                "end": "2026-03-30T09:22:25+00:00",
                "duration_seconds": 62,
                "running": false
              },
              {
                "index": -19,
                "start": "2026-03-30T09:39:31+00:00",
                "end": "2026-03-30T09:42:10+00:00",
                "duration_seconds": 159,
                "running": false
              },
              {
                "index": -18,
                "start": "2026-03-30T14:31:39+00:00",
                "end": "2026-03-30T14:33:14+00:00",
                "duration_seconds": 95,
                "running": false
              },
              {
                "index": -17,
                "start": "2026-03-30T14:34:15+00:00",
                "end": "2026-03-30T14:36:51+00:00",
                "duration_seconds": 156,
                "running": false
              },
              {
                "index": -16,
                "start": "2026-03-30T14:39:27+00:00",
                "end": "2026-03-30T14:46:32+00:00",
                "duration_seconds": 425,
                "running": false
              },
              {
                "index": -15,
                "start": "2026-03-30T14:49:52+00:00",
                "end": "2026-03-30T16:39:49+00:00",
                "duration_seconds": 6597,
                "running": false
              },
              {
                "index": -14,
                "start": "2026-03-31T12:49:50+00:00",
                "end": "2026-03-31T17:41:17+00:00",
                "duration_seconds": 17487,
                "running": false
              },
              {
                "index": -13,
                "start": "2026-04-01T11:27:35+00:00",
                "end": "2026-04-01T19:29:48+00:00",
                "duration_seconds": 28933,
                "running": false
              },
              {
                "index": -12,
                "start": "2026-04-02T08:49:52+00:00",
                "end": "2026-04-02T09:28:56+00:00",
                "duration_seconds": 2344,
                "running": false
              },
              {
                "index": -11,
                "start": "2026-04-02T09:29:40+00:00",
                "end": "2026-04-02T09:31:23+00:00",
                "duration_seconds": 103,
                "running": false
              },
              {
                "index": -10,
                "start": "2026-04-02T09:32:09+00:00",
                "end": "2026-04-02T16:44:48+00:00",
                "duration_seconds": 25959,
                "running": false
              },
              {
                "index": -9,
                "start": "2026-04-02T17:49:20+00:00",
                "end": "2026-04-02T17:50:55+00:00",
                "duration_seconds": 95,
                "running": false
              },
              {
                "index": -8,
                "start": "2026-04-02T17:57:54+00:00",
                "end": "2026-04-02T18:01:15+00:00",
                "duration_seconds": 201,
                "running": false
              },
              {
                "index": -7,
                "start": "2026-04-02T18:03:53+00:00",
                "end": "2026-04-02T18:09:52+00:00",
                "duration_seconds": 359,
                "running": false
              },
              {
                "index": -6,
                "start": "2026-04-02T18:13:38+00:00",
                "end": "2026-04-02T18:16:28+00:00",
                "duration_seconds": 170,
                "running": false
              },
              {
                "index": -5,
                "start": "2026-04-07T09:44:28+00:00",
                "end": "2026-04-07T13:33:02+00:00",
                "duration_seconds": 13714,
                "running": false
              },
              {
                "index": -4,
                "start": "2026-04-07T14:19:17+00:00",
                "end": "2026-04-07T16:43:00+00:00",
                "duration_seconds": 8623,
                "running": false
              },
              {
                "index": -3,
                "start": "2026-04-08T07:51:08+00:00",
                "end": "2026-04-08T17:01:57+00:00",
                "duration_seconds": 33049,
                "running": false
              },
              {
                "index": -2,
                "start": "2026-04-09T08:36:44+00:00",
                "end": "2026-04-09T08:48:15+00:00",
                "duration_seconds": 691,
                "running": false
              },
              {
                "index": -1,
                "start": "2026-04-09T09:11:29+00:00",
                "end": "2026-04-09T14:27:20+00:00",
                "duration_seconds": 18951,
                "running": false
              },
              {
                "index": 0,
                "start": "2026-04-09T14:43:39+00:00",
                "end": "2026-04-10T12:20:06+00:00",
                "duration_seconds": 77787,
                "running": false
              }
            ],
            "daily_seconds": {
              "2026-03-24": 23545.0,
              "2026-03-25": 37553.0,
              "2026-03-26": 50261.0,
              "2026-03-27": 1125.0,
              "2026-03-28": 1578.0,
              "2026-03-30": 13348.0,
              "2026-03-31": 17487.0,
              "2026-04-01": 28933.0,
              "2026-04-02": 29231.0,
              "2026-04-07": 22337.0,
              "2026-04-08": 33049.0,
              "2026-04-09": 53023.0,
              "2026-04-10": 44406.0
            },
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-10T12:21:22+00:00"
        }
      },
      "aw3": {
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "orinalpha3",
          "uptime_seconds": "675",
          "memory_total_mb": "54793",
          "memory_free_mb": "45612",
          "release": null,
          "collected_at": "2026-04-07T14:31:25Z",
          "dns": {
            "servers": {
              "global": "192.168.1.1"
            },
            "search_domains": {
              "global": "hmnd.lan lan.thehumanoid.ai robots.hmnd.ai"
            },
            "dropins": "# Managed by Ansible (iac-robots playbook 04)\n# Points DNS at the RTPC stub resolver on the Moxa bridge.\n# 192.168.1.1 is site-independent \u2014 works at any location.\n# The RTPC forwards to whatever upstream DNS it learned from DHCP.\n[Resolve]\nDNS=192.168.1.1\nDomains=hmnd.lan lan.thehumanoid.ai robots.hmnd.ai\nFallbackDNS=8.8.8.8\n[Resolve]\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-07T14:32:41+00:00"
        },
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alpha3",
          "uptime_seconds": "699",
          "memory_total_mb": "47930",
          "memory_free_mb": "41604",
          "release": null,
          "collected_at": "2026-04-07T14:30:21Z",
          "dns": {
            "servers": {
              "wifi-0": "10.44.10.1"
            },
            "search_domains": {
              "wifi-0": "hmnd.lan"
            },
            "dropins": "[Resolve]\nDNSStubListenerExtra=192.168.2.1\n\n\n\n\n\n\n# Managed by Ansible (iac-robots playbook 04)\n# Exposes the DNS stub resolver on sw-internal (192.168.1.1)\n# so the Orin and other Moxa devices can use the RTPC as a DNS forwarder.\n# The stub resolver automatically uses whatever upstream DNS the RTPC\n# learned from DHCP \u2014 works at any site without reconfiguration.\n[Resolve]\nDNSStubListenerExtra=192.168.1.1",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "8c:f8:c5:b3:81:12",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            },
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "8c:f8:c5:b3:81:11",
              "ssid": "Alpha",
              "channel": 64,
              "configured_ssid": "Alpha",
              "station": {
                "rx_packets": 139751,
                "tx_packets": 492072,
                "tx_retries": 1881,
                "tx_failed": 0,
                "beacon_loss": 0,
                "rx_drop_misc": 2886,
                "signal_dbm": -41,
                "signal_per_antenna": "[-45, -41]",
                "tx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "rx_bitrate": "229.4 MBit/s HE-MCS 9 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "connected_seconds": 722
              }
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "DOWN",
              "ip": null,
              "mac": "00:13:95:65:05:ca"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.13",
              "mac": "8c:f8:c5:b3:81:11"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "8c:f8:c5:96:2d:cd"
            }
          ],
          "nm_profiles": [
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 500,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "hmnd-infra",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": false,
              "priority": 100,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "hmnd-robot",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-07T14:32:40+00:00"
        }
      },
      "aw4": {
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "orinalpha4",
          "uptime_seconds": 164642,
          "memory_total_mb": 54793,
          "memory_free_mb": 40376,
          "release": null,
          "collected_at": "2026-04-10T12:20:20Z",
          "dns": {
            "servers": {
              "global": "10.44.10.1 192.168.1.1"
            },
            "search_domains": {
              "global": "hmnd.lan lan.thehumanoid.ai robots.hmnd.ai"
            },
            "dropins": "# Managed by Ansible (iac-robots playbook 04)\n# Points DNS at the RTPC stub resolver on the Moxa bridge.\n# 192.168.1.1 is site-independent \u2014 works at any location.\n# The RTPC forwards to whatever upstream DNS it learned from DHCP.\n[Resolve]\nDNS=192.168.1.1\nDomains=hmnd.lan lan.thehumanoid.ai robots.hmnd.ai\nFallbackDNS=8.8.8.8\n[Resolve]\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [
              {
                "index": -8,
                "start": "2026-04-02T16:54:04+00:00",
                "end": "2026-04-03T04:01:18+00:00",
                "duration_seconds": 40034,
                "running": false
              },
              {
                "index": -7,
                "start": "2026-04-04T13:22:57+00:00",
                "end": "2026-04-04T17:31:18+00:00",
                "duration_seconds": 14901,
                "running": false
              },
              {
                "index": -6,
                "start": "2026-04-07T05:41:37+00:00",
                "end": "2026-04-07T06:38:05+00:00",
                "duration_seconds": 3388,
                "running": false
              },
              {
                "index": -5,
                "start": "2026-04-07T06:42:39+00:00",
                "end": "2026-04-07T08:46:46+00:00",
                "duration_seconds": 7447,
                "running": false
              },
              {
                "index": -4,
                "start": "2026-04-07T08:56:49+00:00",
                "end": "2026-04-07T08:57:07+00:00",
                "duration_seconds": 18,
                "running": false
              },
              {
                "index": -3,
                "start": "2026-04-07T09:03:14+00:00",
                "end": "2026-04-07T20:35:25+00:00",
                "duration_seconds": 41531,
                "running": false
              },
              {
                "index": -2,
                "start": "2026-04-07T20:44:25+00:00",
                "end": "2026-04-07T20:45:01+00:00",
                "duration_seconds": 36,
                "running": false
              },
              {
                "index": -1,
                "start": "2026-04-07T20:48:44+00:00",
                "end": "2026-04-08T14:32:29+00:00",
                "duration_seconds": 63825,
                "running": false
              },
              {
                "index": 0,
                "start": "2026-04-08T14:36:30+00:00",
                "end": "2026-04-10T12:20:55+00:00",
                "duration_seconds": 164665,
                "running": false
              }
            ],
            "daily_seconds": {
              "2026-04-02": 25556.0,
              "2026-04-03": 14478.0,
              "2026-04-04": 14901.0,
              "2026-04-07": 63896.0,
              "2026-04-08": 86159.0,
              "2026-04-09": 86400.0,
              "2026-04-10": 44455.0
            },
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-10T12:21:20+00:00"
        },
        "rtpc": {
          "kernel": "5.15.183-rt85",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alpha4",
          "uptime_seconds": 164678,
          "memory_total_mb": 47919,
          "memory_free_mb": 40041,
          "release": null,
          "collected_at": "2026-04-10T12:19:28Z",
          "dns": {
            "servers": {
              "wifi-0": "10.44.10.1"
            },
            "search_domains": {
              "wifi-0": "hmnd.lan"
            },
            "dropins": "# Managed by Ansible (iac-robots playbook 04)\n# Exposes the DNS stub resolver on sw-internal (192.168.1.1)\n# so the Orin and other Moxa devices can use the RTPC as a DNS forwarder.\n# The stub resolver automatically uses whatever upstream DNS the RTPC\n# learned from DHCP \u2014 works at any site without reconfiguration.\n[Resolve]\nDNSStubListenerExtra=192.168.1.1",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "90:10:57:98:ab:b7",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            },
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "90:10:57:98:ab:b6",
              "ssid": "Alpha",
              "channel": 104,
              "configured_ssid": "Alpha",
              "station": {
                "rx_packets": 331134685,
                "tx_packets": 173634287,
                "tx_retries": 684013,
                "tx_failed": 132,
                "beacon_loss": 0,
                "rx_drop_misc": 158094,
                "signal_dbm": -35,
                "signal_per_antenna": "[-35, -38]",
                "tx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "rx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "connected_seconds": 164690
              }
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "DOWN",
              "ip": null,
              "mac": "00:13:95:68:c2:f3"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.104",
              "mac": "90:10:57:98:ab:b6"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "90:10:57:97:83:58"
            }
          ],
          "nm_profiles": [
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 900,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "hmnd-6ghz",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [
              {
                "index": -42,
                "start": "2026-03-27T06:01:30+00:00",
                "end": "2026-03-27T11:00:41+00:00",
                "duration_seconds": 17951,
                "running": false
              },
              {
                "index": -41,
                "start": "2026-03-27T11:03:02+00:00",
                "end": "2026-03-27T11:03:59+00:00",
                "duration_seconds": 57,
                "running": false
              },
              {
                "index": -40,
                "start": "2026-03-27T11:04:51+00:00",
                "end": "2026-03-27T18:49:38+00:00",
                "duration_seconds": 27887,
                "running": false
              },
              {
                "index": -39,
                "start": "2026-03-27T19:11:17+00:00",
                "end": "2026-03-27T19:37:40+00:00",
                "duration_seconds": 1583,
                "running": false
              },
              {
                "index": -38,
                "start": "2026-03-27T19:45:09+00:00",
                "end": "2026-03-27T19:53:50+00:00",
                "duration_seconds": 521,
                "running": false
              },
              {
                "index": -37,
                "start": "2026-03-28T17:23:08+00:00",
                "end": "2026-03-28T17:49:34+00:00",
                "duration_seconds": 1586,
                "running": false
              },
              {
                "index": -36,
                "start": "2026-03-30T15:07:54+00:00",
                "end": "2026-03-30T15:40:32+00:00",
                "duration_seconds": 1958,
                "running": false
              },
              {
                "index": -35,
                "start": "2026-03-30T15:41:21+00:00",
                "end": "2026-03-30T16:09:13+00:00",
                "duration_seconds": 1672,
                "running": false
              },
              {
                "index": -34,
                "start": "2026-03-30T16:10:08+00:00",
                "end": "2026-03-30T16:11:32+00:00",
                "duration_seconds": 84,
                "running": false
              },
              {
                "index": -33,
                "start": "2026-03-30T16:12:33+00:00",
                "end": "2026-03-30T16:16:22+00:00",
                "duration_seconds": 229,
                "running": false
              },
              {
                "index": -32,
                "start": "2026-03-30T16:17:26+00:00",
                "end": "2026-03-30T17:14:53+00:00",
                "duration_seconds": 3447,
                "running": false
              },
              {
                "index": -31,
                "start": "2026-03-30T17:34:26+00:00",
                "end": "2026-03-30T18:27:27+00:00",
                "duration_seconds": 3181,
                "running": false
              },
              {
                "index": -30,
                "start": "2026-03-30T18:32:13+00:00",
                "end": "2026-03-30T18:33:36+00:00",
                "duration_seconds": 83,
                "running": false
              },
              {
                "index": -29,
                "start": "2026-03-30T18:34:42+00:00",
                "end": "2026-03-31T12:33:54+00:00",
                "duration_seconds": 64752,
                "running": false
              },
              {
                "index": -28,
                "start": "2026-03-31T12:40:37+00:00",
                "end": "2026-03-31T12:49:09+00:00",
                "duration_seconds": 512,
                "running": false
              },
              {
                "index": -27,
                "start": "2026-03-31T12:51:31+00:00",
                "end": "2026-03-31T12:57:24+00:00",
                "duration_seconds": 353,
                "running": false
              },
              {
                "index": -26,
                "start": "2026-03-31T12:58:23+00:00",
                "end": "2026-03-31T15:33:26+00:00",
                "duration_seconds": 9303,
                "running": false
              },
              {
                "index": -25,
                "start": "2026-03-31T15:41:26+00:00",
                "end": "2026-03-31T15:50:46+00:00",
                "duration_seconds": 560,
                "running": false
              },
              {
                "index": -24,
                "start": "2026-03-31T15:52:31+00:00",
                "end": "2026-03-31T17:45:23+00:00",
                "duration_seconds": 6772,
                "running": false
              },
              {
                "index": -23,
                "start": "2026-03-31T17:48:03+00:00",
                "end": "2026-03-31T17:48:47+00:00",
                "duration_seconds": 44,
                "running": false
              },
              {
                "index": -22,
                "start": "2026-03-31T17:52:45+00:00",
                "end": "2026-03-31T17:53:34+00:00",
                "duration_seconds": 49,
                "running": false
              },
              {
                "index": -21,
                "start": "2026-03-31T17:58:13+00:00",
                "end": "2026-03-31T17:58:57+00:00",
                "duration_seconds": 44,
                "running": false
              },
              {
                "index": -20,
                "start": "2026-03-31T18:09:56+00:00",
                "end": "2026-03-31T19:28:05+00:00",
                "duration_seconds": 4689,
                "running": false
              },
              {
                "index": -19,
                "start": "2026-03-31T20:01:15+00:00",
                "end": "2026-04-01T01:18:37+00:00",
                "duration_seconds": 19042,
                "running": false
              },
              {
                "index": -18,
                "start": "2026-04-01T01:39:43+00:00",
                "end": "2026-04-01T01:41:26+00:00",
                "duration_seconds": 103,
                "running": false
              },
              {
                "index": -17,
                "start": "2026-04-01T01:42:49+00:00",
                "end": "2026-04-01T01:44:24+00:00",
                "duration_seconds": 95,
                "running": false
              },
              {
                "index": -16,
                "start": "2026-04-01T01:48:53+00:00",
                "end": "2026-04-01T04:46:16+00:00",
                "duration_seconds": 10643,
                "running": false
              },
              {
                "index": -15,
                "start": "2026-04-01T04:47:40+00:00",
                "end": "2026-04-01T04:55:05+00:00",
                "duration_seconds": 445,
                "running": false
              },
              {
                "index": -14,
                "start": "2026-04-01T04:58:12+00:00",
                "end": "2026-04-01T05:04:16+00:00",
                "duration_seconds": 364,
                "running": false
              },
              {
                "index": -13,
                "start": "2026-04-01T05:06:43+00:00",
                "end": "2026-04-01T05:06:56+00:00",
                "duration_seconds": 13,
                "running": false
              },
              {
                "index": -12,
                "start": "2026-04-01T05:11:40+00:00",
                "end": "2026-04-01T05:11:58+00:00",
                "duration_seconds": 18,
                "running": false
              },
              {
                "index": -11,
                "start": "2026-04-01T05:14:38+00:00",
                "end": "2026-04-01T17:15:34+00:00",
                "duration_seconds": 43256,
                "running": false
              },
              {
                "index": -10,
                "start": "2026-04-01T17:16:44+00:00",
                "end": "2026-04-01T17:17:30+00:00",
                "duration_seconds": 46,
                "running": false
              },
              {
                "index": -9,
                "start": "2026-04-01T17:18:41+00:00",
                "end": "2026-04-03T04:08:57+00:00",
                "duration_seconds": 125416,
                "running": false
              },
              {
                "index": -8,
                "start": "2026-04-04T13:21:57+00:00",
                "end": "2026-04-04T17:38:11+00:00",
                "duration_seconds": 15374,
                "running": false
              },
              {
                "index": -7,
                "start": "2026-04-07T05:40:37+00:00",
                "end": "2026-04-07T06:38:04+00:00",
                "duration_seconds": 3447,
                "running": false
              },
              {
                "index": -6,
                "start": "2026-04-07T06:40:58+00:00",
                "end": "2026-04-07T08:46:47+00:00",
                "duration_seconds": 7549,
                "running": false
              },
              {
                "index": -5,
                "start": "2026-04-07T08:55:17+00:00",
                "end": "2026-04-07T09:00:30+00:00",
                "duration_seconds": 313,
                "running": false
              },
              {
                "index": -4,
                "start": "2026-04-07T09:01:42+00:00",
                "end": "2026-04-07T20:35:26+00:00",
                "duration_seconds": 41624,
                "running": false
              },
              {
                "index": -3,
                "start": "2026-04-07T20:42:54+00:00",
                "end": "2026-04-07T20:46:02+00:00",
                "duration_seconds": 188,
                "running": false
              },
              {
                "index": -2,
                "start": "2026-04-07T20:47:14+00:00",
                "end": "2026-04-08T14:32:27+00:00",
                "duration_seconds": 63913,
                "running": false
              },
              {
                "index": -1,
                "start": "2026-04-08T14:33:19+00:00",
                "end": "2026-04-08T14:33:32+00:00",
                "duration_seconds": 13,
                "running": false
              },
              {
                "index": 0,
                "start": "2026-04-08T14:34:59+00:00",
                "end": "2026-04-10T12:20:07+00:00",
                "duration_seconds": 164708,
                "running": false
              }
            ],
            "daily_seconds": {
              "2026-03-27": 47999.0,
              "2026-03-28": 1586.0,
              "2026-03-30": 30172.0,
              "2026-03-31": 81885.0,
              "2026-04-01": 83779.0,
              "2026-04-02": 86400.0,
              "2026-04-03": 14937.0,
              "2026-04-04": 15374.0,
              "2026-04-07": 64687.0,
              "2026-04-08": 86261.0,
              "2026-04-09": 86400.0,
              "2026-04-10": 44407.0
            },
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-10T12:21:20+00:00"
        }
      },
      "aw6": {
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "orinalpha6",
          "uptime_seconds": "1637",
          "memory_total_mb": "54793",
          "memory_free_mb": "52668",
          "release": null,
          "collected_at": "2026-04-09T14:31:53Z",
          "dns": {
            "servers": {},
            "search_domains": {},
            "dropins": "[Resolve]\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": false,
              "route53": false,
              "private": false,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-09T14:34:45+00:00"
        },
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alpha6",
          "uptime_seconds": "1638",
          "memory_total_mb": "47921",
          "memory_free_mb": "44490",
          "release": null,
          "collected_at": "2026-04-09T14:30:24Z",
          "dns": {
            "servers": {
              "wifi-0": "10.44.10.1"
            },
            "search_domains": {
              "wifi-0": "hmnd.lan"
            },
            "dropins": "no drop-ins",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "90:10:57:97:84:26",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            },
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "90:10:57:97:84:25",
              "ssid": "Alpha",
              "channel": 157,
              "configured_ssid": "Alpha",
              "station": {
                "rx_packets": 57270,
                "tx_packets": 60396,
                "tx_retries": 62,
                "tx_failed": 0,
                "beacon_loss": 0,
                "rx_drop_misc": 6457,
                "signal_dbm": -45,
                "signal_per_antenna": "[-45, -49]",
                "tx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "rx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "connected_seconds": 1673
              }
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "DOWN",
              "ip": null,
              "mac": "00:13:95:65:f1:60"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.16",
              "mac": "90:10:57:97:84:25"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "90:10:57:97:81:e6"
            }
          ],
          "nm_profiles": [
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 900,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "hmnd-robot-6ghz",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-09T14:34:45+00:00"
        }
      },
      "aw7": {
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alpha7",
          "uptime_seconds": 6009,
          "memory_total_mb": 47921,
          "memory_free_mb": 31145,
          "release": null,
          "collected_at": "2026-04-10T12:19:38Z",
          "dns": {
            "servers": {
              "wifi-0": "10.44.10.1"
            },
            "search_domains": {
              "wifi-0": "hmnd.lan"
            },
            "dropins": "no drop-ins",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "90:10:57:98:aa:27",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            },
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "90:10:57:98:aa:26",
              "ssid": "Alpha",
              "channel": 37,
              "configured_ssid": "Alpha",
              "station": {
                "rx_packets": 1333129,
                "tx_packets": 1907737,
                "tx_retries": 1834,
                "tx_failed": 0,
                "beacon_loss": 0,
                "rx_drop_misc": 19194,
                "signal_dbm": -45,
                "signal_per_antenna": "[-45, -48]",
                "tx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "rx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "connected_seconds": 5805
              }
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "DOWN",
              "ip": null,
              "mac": "00:13:95:69:b6:36"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.17",
              "mac": "90:10:57:98:aa:26"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "90:10:57:98:ab:f2"
            }
          ],
          "nm_profiles": [
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 901,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "hmnd-6ghz",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            },
            {
              "name": "hmnd-robot-6ghz",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [
              {
                "index": -49,
                "start": "2026-03-25T09:54:28+00:00",
                "end": "2026-03-25T11:47:38+00:00",
                "duration_seconds": 6790,
                "running": false
              },
              {
                "index": -48,
                "start": "2026-03-25T11:50:49+00:00",
                "end": "2026-03-25T11:57:31+00:00",
                "duration_seconds": 402,
                "running": false
              },
              {
                "index": -47,
                "start": "2026-03-25T12:00:47+00:00",
                "end": "2026-03-25T12:38:16+00:00",
                "duration_seconds": 2249,
                "running": false
              },
              {
                "index": -46,
                "start": "2026-03-25T13:37:02+00:00",
                "end": "2026-03-25T14:41:31+00:00",
                "duration_seconds": 3869,
                "running": false
              },
              {
                "index": -45,
                "start": "2026-03-25T17:16:34+00:00",
                "end": "2026-03-25T17:49:52+00:00",
                "duration_seconds": 1998,
                "running": false
              },
              {
                "index": -44,
                "start": "2026-03-25T17:51:42+00:00",
                "end": "2026-03-25T17:57:17+00:00",
                "duration_seconds": 335,
                "running": false
              },
              {
                "index": -43,
                "start": "2026-03-25T17:57:59+00:00",
                "end": "2026-03-25T18:45:00+00:00",
                "duration_seconds": 2821,
                "running": false
              },
              {
                "index": -42,
                "start": "2026-03-25T18:45:37+00:00",
                "end": "2026-03-25T18:47:44+00:00",
                "duration_seconds": 127,
                "running": false
              },
              {
                "index": -41,
                "start": "2026-03-25T18:48:32+00:00",
                "end": "2026-03-25T19:14:55+00:00",
                "duration_seconds": 1583,
                "running": false
              },
              {
                "index": -40,
                "start": "2026-03-25T19:15:48+00:00",
                "end": "2026-03-25T19:40:54+00:00",
                "duration_seconds": 1506,
                "running": false
              },
              {
                "index": -39,
                "start": "2026-03-25T19:48:16+00:00",
                "end": "2026-03-25T19:56:18+00:00",
                "duration_seconds": 482,
                "running": false
              },
              {
                "index": -38,
                "start": "2026-03-26T08:32:57+00:00",
                "end": "2026-03-26T10:02:09+00:00",
                "duration_seconds": 5352,
                "running": false
              },
              {
                "index": -37,
                "start": "2026-03-26T10:05:52+00:00",
                "end": "2026-03-26T10:34:30+00:00",
                "duration_seconds": 1718,
                "running": false
              },
              {
                "index": -36,
                "start": "2026-03-26T10:38:42+00:00",
                "end": "2026-03-26T10:42:11+00:00",
                "duration_seconds": 209,
                "running": false
              },
              {
                "index": -35,
                "start": "2026-03-26T10:43:18+00:00",
                "end": "2026-03-26T10:44:41+00:00",
                "duration_seconds": 83,
                "running": false
              },
              {
                "index": -34,
                "start": "2026-03-26T10:45:24+00:00",
                "end": "2026-03-26T11:05:15+00:00",
                "duration_seconds": 1191,
                "running": false
              },
              {
                "index": -33,
                "start": "2026-03-26T12:05:46+00:00",
                "end": "2026-03-26T14:05:51+00:00",
                "duration_seconds": 7205,
                "running": false
              },
              {
                "index": -32,
                "start": "2026-03-27T09:52:43+00:00",
                "end": "2026-03-27T13:34:01+00:00",
                "duration_seconds": 13278,
                "running": false
              },
              {
                "index": -31,
                "start": "2026-03-27T13:42:53+00:00",
                "end": "2026-03-27T14:55:41+00:00",
                "duration_seconds": 4368,
                "running": false
              },
              {
                "index": -30,
                "start": "2026-03-27T15:05:22+00:00",
                "end": "2026-03-27T15:09:42+00:00",
                "duration_seconds": 260,
                "running": false
              },
              {
                "index": -29,
                "start": "2026-03-27T15:10:29+00:00",
                "end": "2026-03-27T15:15:43+00:00",
                "duration_seconds": 314,
                "running": false
              },
              {
                "index": -28,
                "start": "2026-03-27T15:16:56+00:00",
                "end": "2026-03-27T15:19:36+00:00",
                "duration_seconds": 160,
                "running": false
              },
              {
                "index": -27,
                "start": "2026-03-27T15:20:46+00:00",
                "end": "2026-03-27T15:25:19+00:00",
                "duration_seconds": 273,
                "running": false
              },
              {
                "index": -26,
                "start": "2026-03-28T09:30:23+00:00",
                "end": "2026-03-28T13:55:51+00:00",
                "duration_seconds": 15928,
                "running": false
              },
              {
                "index": -25,
                "start": "2026-03-28T14:40:43+00:00",
                "end": "2026-03-28T17:47:18+00:00",
                "duration_seconds": 11195,
                "running": false
              },
              {
                "index": -24,
                "start": "2026-03-30T07:05:15+00:00",
                "end": "2026-03-31T20:38:51+00:00",
                "duration_seconds": 135216,
                "running": false
              },
              {
                "index": -23,
                "start": "2026-04-01T08:33:19+00:00",
                "end": "2026-04-01T13:32:04+00:00",
                "duration_seconds": 17925,
                "running": false
              },
              {
                "index": -22,
                "start": "2026-04-01T13:33:33+00:00",
                "end": "2026-04-01T13:36:53+00:00",
                "duration_seconds": 200,
                "running": false
              },
              {
                "index": -21,
                "start": "2026-04-01T13:38:44+00:00",
                "end": "2026-04-01T16:31:50+00:00",
                "duration_seconds": 10386,
                "running": false
              },
              {
                "index": -20,
                "start": "2026-04-02T08:00:44+00:00",
                "end": "2026-04-02T09:44:03+00:00",
                "duration_seconds": 6199,
                "running": false
              },
              {
                "index": -19,
                "start": "2026-04-02T09:55:31+00:00",
                "end": "2026-04-02T10:03:38+00:00",
                "duration_seconds": 487,
                "running": false
              },
              {
                "index": -18,
                "start": "2026-04-02T10:04:40+00:00",
                "end": "2026-04-02T10:09:02+00:00",
                "duration_seconds": 262,
                "running": false
              },
              {
                "index": -17,
                "start": "2026-04-02T10:09:43+00:00",
                "end": "2026-04-02T10:10:11+00:00",
                "duration_seconds": 28,
                "running": false
              },
              {
                "index": -16,
                "start": "2026-04-02T10:11:00+00:00",
                "end": "2026-04-02T10:19:00+00:00",
                "duration_seconds": 480,
                "running": false
              },
              {
                "index": -15,
                "start": "2026-04-02T12:16:53+00:00",
                "end": "2026-04-02T19:07:58+00:00",
                "duration_seconds": 24665,
                "running": false
              },
              {
                "index": -14,
                "start": "2026-04-02T19:08:55+00:00",
                "end": "2026-04-02T19:19:31+00:00",
                "duration_seconds": 636,
                "running": false
              },
              {
                "index": -13,
                "start": "2026-04-02T19:20:23+00:00",
                "end": "2026-04-02T19:53:53+00:00",
                "duration_seconds": 2010,
                "running": false
              },
              {
                "index": -12,
                "start": "2026-04-02T20:00:20+00:00",
                "end": "2026-04-02T20:05:50+00:00",
                "duration_seconds": 330,
                "running": false
              },
              {
                "index": -11,
                "start": "2026-04-02T20:06:53+00:00",
                "end": "2026-04-02T20:06:53+00:00",
                "duration_seconds": 0,
                "running": false
              },
              {
                "index": -10,
                "start": "2026-04-02T20:08:05+00:00",
                "end": "2026-04-02T20:12:54+00:00",
                "duration_seconds": 289,
                "running": false
              },
              {
                "index": -9,
                "start": "2026-04-02T20:13:53+00:00",
                "end": "2026-04-02T20:16:28+00:00",
                "duration_seconds": 155,
                "running": false
              },
              {
                "index": -8,
                "start": "2026-04-02T20:17:18+00:00",
                "end": "2026-04-02T20:35:43+00:00",
                "duration_seconds": 1105,
                "running": false
              },
              {
                "index": -7,
                "start": "2026-04-02T20:50:48+00:00",
                "end": "2026-04-02T20:55:23+00:00",
                "duration_seconds": 275,
                "running": false
              },
              {
                "index": -6,
                "start": "2026-04-08T08:33:01+00:00",
                "end": "2026-04-08T09:26:49+00:00",
                "duration_seconds": 3228,
                "running": false
              },
              {
                "index": -5,
                "start": "2026-04-08T09:27:52+00:00",
                "end": "2026-04-08T15:56:37+00:00",
                "duration_seconds": 23325,
                "running": false
              },
              {
                "index": -4,
                "start": "2026-04-09T08:32:17+00:00",
                "end": "2026-04-09T12:04:33+00:00",
                "duration_seconds": 12736,
                "running": false
              },
              {
                "index": -3,
                "start": "2026-04-10T08:13:25+00:00",
                "end": "2026-04-10T08:43:08+00:00",
                "duration_seconds": 1783,
                "running": false
              },
              {
                "index": -2,
                "start": "2026-04-10T08:44:02+00:00",
                "end": "2026-04-10T09:15:24+00:00",
                "duration_seconds": 1882,
                "running": false
              },
              {
                "index": -1,
                "start": "2026-04-10T10:08:08+00:00",
                "end": "2026-04-10T10:38:54+00:00",
                "duration_seconds": 1846,
                "running": false
              },
              {
                "index": 0,
                "start": "2026-04-10T10:39:38+00:00",
                "end": "2026-04-10T12:20:06+00:00",
                "duration_seconds": 6028,
                "running": false
              }
            ],
            "daily_seconds": {
              "2026-03-25": 22162.0,
              "2026-03-26": 15758.0,
              "2026-03-27": 18653.0,
              "2026-03-28": 27123.0,
              "2026-03-30": 60885.0,
              "2026-03-31": 74331.0,
              "2026-04-01": 28511.0,
              "2026-04-02": 36921.0,
              "2026-04-08": 26553.0,
              "2026-04-09": 12736.0,
              "2026-04-10": 11539.0
            },
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-10T12:21:20+00:00"
        },
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "orinalpha7",
          "uptime_seconds": 5999,
          "memory_total_mb": 54793,
          "memory_free_mb": 36542,
          "release": null,
          "collected_at": "2026-04-10T12:20:20Z",
          "dns": {
            "servers": {
              "global": "10.44.10.1"
            },
            "search_domains": {},
            "dropins": "[Resolve]\nDNS=10.44.10.1\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [
              {
                "index": 0,
                "start": "2025-08-26T15:23:06+00:00",
                "end": "2026-04-10T12:20:53+00:00",
                "duration_seconds": 19601867,
                "running": false
              }
            ],
            "daily_seconds": {
              "2025-08-26": 31014.0,
              "2025-08-27": 86400.0,
              "2025-08-28": 86400.0,
              "2025-08-29": 86400.0,
              "2025-08-30": 86400.0,
              "2025-08-31": 86400.0,
              "2025-09-01": 86400.0,
              "2025-09-02": 86400.0,
              "2025-09-03": 86400.0,
              "2025-09-04": 86400.0,
              "2025-09-05": 86400.0,
              "2025-09-06": 86400.0,
              "2025-09-07": 86400.0,
              "2025-09-08": 86400.0,
              "2025-09-09": 86400.0,
              "2025-09-10": 86400.0,
              "2025-09-11": 86400.0,
              "2025-09-12": 86400.0,
              "2025-09-13": 86400.0,
              "2025-09-14": 86400.0,
              "2025-09-15": 86400.0,
              "2025-09-16": 86400.0,
              "2025-09-17": 86400.0,
              "2025-09-18": 86400.0,
              "2025-09-19": 86400.0,
              "2025-09-20": 86400.0,
              "2025-09-21": 86400.0,
              "2025-09-22": 86400.0,
              "2025-09-23": 86400.0,
              "2025-09-24": 86400.0,
              "2025-09-25": 86400.0,
              "2025-09-26": 86400.0,
              "2025-09-27": 86400.0,
              "2025-09-28": 86400.0,
              "2025-09-29": 86400.0,
              "2025-09-30": 86400.0,
              "2025-10-01": 86400.0,
              "2025-10-02": 86400.0,
              "2025-10-03": 86400.0,
              "2025-10-04": 86400.0,
              "2025-10-05": 86400.0,
              "2025-10-06": 86400.0,
              "2025-10-07": 86400.0,
              "2025-10-08": 86400.0,
              "2025-10-09": 86400.0,
              "2025-10-10": 86400.0,
              "2025-10-11": 86400.0,
              "2025-10-12": 86400.0,
              "2025-10-13": 86400.0,
              "2025-10-14": 86400.0,
              "2025-10-15": 86400.0,
              "2025-10-16": 86400.0,
              "2025-10-17": 86400.0,
              "2025-10-18": 86400.0,
              "2025-10-19": 86400.0,
              "2025-10-20": 86400.0,
              "2025-10-21": 86400.0,
              "2025-10-22": 86400.0,
              "2025-10-23": 86400.0,
              "2025-10-24": 86400.0,
              "2025-10-25": 86400.0,
              "2025-10-26": 86400.0,
              "2025-10-27": 86400.0,
              "2025-10-28": 86400.0,
              "2025-10-29": 86400.0,
              "2025-10-30": 86400.0,
              "2025-10-31": 86400.0,
              "2025-11-01": 86400.0,
              "2025-11-02": 86400.0,
              "2025-11-03": 86400.0,
              "2025-11-04": 86400.0,
              "2025-11-05": 86400.0,
              "2025-11-06": 86400.0,
              "2025-11-07": 86400.0,
              "2025-11-08": 86400.0,
              "2025-11-09": 86400.0,
              "2025-11-10": 86400.0,
              "2025-11-11": 86400.0,
              "2025-11-12": 86400.0,
              "2025-11-13": 86400.0,
              "2025-11-14": 86400.0,
              "2025-11-15": 86400.0,
              "2025-11-16": 86400.0,
              "2025-11-17": 86400.0,
              "2025-11-18": 86400.0,
              "2025-11-19": 86400.0,
              "2025-11-20": 86400.0,
              "2025-11-21": 86400.0,
              "2025-11-22": 86400.0,
              "2025-11-23": 86400.0,
              "2025-11-24": 86400.0,
              "2025-11-25": 86400.0,
              "2025-11-26": 86400.0,
              "2025-11-27": 86400.0,
              "2025-11-28": 86400.0,
              "2025-11-29": 86400.0,
              "2025-11-30": 86400.0,
              "2025-12-01": 86400.0,
              "2025-12-02": 86400.0,
              "2025-12-03": 86400.0,
              "2025-12-04": 86400.0,
              "2025-12-05": 86400.0,
              "2025-12-06": 86400.0,
              "2025-12-07": 86400.0,
              "2025-12-08": 86400.0,
              "2025-12-09": 86400.0,
              "2025-12-10": 86400.0,
              "2025-12-11": 86400.0,
              "2025-12-12": 86400.0,
              "2025-12-13": 86400.0,
              "2025-12-14": 86400.0,
              "2025-12-15": 86400.0,
              "2025-12-16": 86400.0,
              "2025-12-17": 86400.0,
              "2025-12-18": 86400.0,
              "2025-12-19": 86400.0,
              "2025-12-20": 86400.0,
              "2025-12-21": 86400.0,
              "2025-12-22": 86400.0,
              "2025-12-23": 86400.0,
              "2025-12-24": 86400.0,
              "2025-12-25": 86400.0,
              "2025-12-26": 86400.0,
              "2025-12-27": 86400.0,
              "2025-12-28": 86400.0,
              "2025-12-29": 86400.0,
              "2025-12-30": 86400.0,
              "2025-12-31": 86400.0,
              "2026-01-01": 86400.0,
              "2026-01-02": 86400.0,
              "2026-01-03": 86400.0,
              "2026-01-04": 86400.0,
              "2026-01-05": 86400.0,
              "2026-01-06": 86400.0,
              "2026-01-07": 86400.0,
              "2026-01-08": 86400.0,
              "2026-01-09": 86400.0,
              "2026-01-10": 86400.0,
              "2026-01-11": 86400.0,
              "2026-01-12": 86400.0,
              "2026-01-13": 86400.0,
              "2026-01-14": 86400.0,
              "2026-01-15": 86400.0,
              "2026-01-16": 86400.0,
              "2026-01-17": 86400.0,
              "2026-01-18": 86400.0,
              "2026-01-19": 86400.0,
              "2026-01-20": 86400.0,
              "2026-01-21": 86400.0,
              "2026-01-22": 86400.0,
              "2026-01-23": 86400.0,
              "2026-01-24": 86400.0,
              "2026-01-25": 86400.0,
              "2026-01-26": 86400.0,
              "2026-01-27": 86400.0,
              "2026-01-28": 86400.0,
              "2026-01-29": 86400.0,
              "2026-01-30": 86400.0,
              "2026-01-31": 86400.0,
              "2026-02-01": 86400.0,
              "2026-02-02": 86400.0,
              "2026-02-03": 86400.0,
              "2026-02-04": 86400.0,
              "2026-02-05": 86400.0,
              "2026-02-06": 86400.0,
              "2026-02-07": 86400.0,
              "2026-02-08": 86400.0,
              "2026-02-09": 86400.0,
              "2026-02-10": 86400.0,
              "2026-02-11": 86400.0,
              "2026-02-12": 86400.0,
              "2026-02-13": 86400.0,
              "2026-02-14": 86400.0,
              "2026-02-15": 86400.0,
              "2026-02-16": 86400.0,
              "2026-02-17": 86400.0,
              "2026-02-18": 86400.0,
              "2026-02-19": 86400.0,
              "2026-02-20": 86400.0,
              "2026-02-21": 86400.0,
              "2026-02-22": 86400.0,
              "2026-02-23": 86400.0,
              "2026-02-24": 86400.0,
              "2026-02-25": 86400.0,
              "2026-02-26": 86400.0,
              "2026-02-27": 86400.0,
              "2026-02-28": 86400.0,
              "2026-03-01": 86400.0,
              "2026-03-02": 86400.0,
              "2026-03-03": 86400.0,
              "2026-03-04": 86400.0,
              "2026-03-05": 86400.0,
              "2026-03-06": 86400.0,
              "2026-03-07": 86400.0,
              "2026-03-08": 86400.0,
              "2026-03-09": 86400.0,
              "2026-03-10": 86400.0,
              "2026-03-11": 86400.0,
              "2026-03-12": 86400.0,
              "2026-03-13": 86400.0,
              "2026-03-14": 86400.0,
              "2026-03-15": 86400.0,
              "2026-03-16": 86400.0,
              "2026-03-17": 86400.0,
              "2026-03-18": 86400.0,
              "2026-03-19": 86400.0,
              "2026-03-20": 86400.0,
              "2026-03-21": 86400.0,
              "2026-03-22": 86400.0,
              "2026-03-23": 86400.0,
              "2026-03-24": 86400.0,
              "2026-03-25": 86400.0,
              "2026-03-26": 86400.0,
              "2026-03-27": 86400.0,
              "2026-03-28": 86400.0,
              "2026-03-29": 86400.0,
              "2026-03-30": 86400.0,
              "2026-03-31": 86400.0,
              "2026-04-01": 86400.0,
              "2026-04-02": 86400.0,
              "2026-04-03": 86400.0,
              "2026-04-04": 86400.0,
              "2026-04-05": 86400.0,
              "2026-04-06": 86400.0,
              "2026-04-07": 86400.0,
              "2026-04-08": 86400.0,
              "2026-04-09": 86400.0,
              "2026-04-10": 44453.0
            },
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-10T12:21:21+00:00"
        }
      },
      "aw8": {
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "orinalpha8",
          "uptime_seconds": "13667",
          "memory_total_mb": "54793",
          "memory_free_mb": "46648",
          "release": null,
          "collected_at": "2026-03-24T21:02:10Z",
          "dns": {
            "servers": {},
            "search_domains": {},
            "dropins": "[Resolve]\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": false,
              "route53": false,
              "private": false,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-03-24T21:03:51+00:00"
        },
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alpha8",
          "uptime_seconds": "13654",
          "memory_total_mb": "47921",
          "memory_free_mb": "42279",
          "release": null,
          "collected_at": "2026-03-24T21:00:28Z",
          "dns": {
            "servers": {
              "wifi-0": "10.44.52.1"
            },
            "search_domains": {
              "wifi-0": "hmnd.lan"
            },
            "dropins": "no drop-ins",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "5c:b2:6d:46:6d:57",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            },
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "5c:b2:6d:46:6d:56",
              "ssid": "hmnd-robot-6ghz",
              "channel": 213,
              "configured_ssid": "hmnd-robot-6ghz"
            }
          ],
          "interfaces": [
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.52.108",
              "mac": "5c:b2:6d:46:6d:56"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "58:6d:67:f7:cf:d8"
            }
          ],
          "nm_profiles": [
            {
              "name": "hmnd-robot-6ghz",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "hmnd-robot-6ghz",
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": "sae",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [],
            "daily_seconds": {},
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-03-24T21:03:50+00:00"
        }
      },
      "aw9": {
        "orin": {
          "kernel": "5.15.148-tegra",
          "os": "Ubuntu 22.04",
          "architecture": "aarch64",
          "hostname": "orinalpha9",
          "uptime_seconds": 17006,
          "memory_total_mb": 54793,
          "memory_free_mb": 40292,
          "release": null,
          "collected_at": "2026-04-10T12:20:21Z",
          "dns": {
            "servers": {},
            "search_domains": {},
            "dropins": "[Resolve]\nFallbackDNS=8.8.8.8",
            "zones": {
              "local": false,
              "route53": false,
              "private": false,
              "public": true
            }
          },
          "docker_running": false,
          "can_interfaces_up": 0,
          "model": "Newton + Orin AGXi\u0000",
          "utilization": {
            "boots": [
              {
                "index": 0,
                "start": "2025-08-26T15:23:06+00:00",
                "end": "2026-04-10T12:20:53+00:00",
                "duration_seconds": 19601867,
                "running": false
              }
            ],
            "daily_seconds": {
              "2025-08-26": 31014.0,
              "2025-08-27": 86400.0,
              "2025-08-28": 86400.0,
              "2025-08-29": 86400.0,
              "2025-08-30": 86400.0,
              "2025-08-31": 86400.0,
              "2025-09-01": 86400.0,
              "2025-09-02": 86400.0,
              "2025-09-03": 86400.0,
              "2025-09-04": 86400.0,
              "2025-09-05": 86400.0,
              "2025-09-06": 86400.0,
              "2025-09-07": 86400.0,
              "2025-09-08": 86400.0,
              "2025-09-09": 86400.0,
              "2025-09-10": 86400.0,
              "2025-09-11": 86400.0,
              "2025-09-12": 86400.0,
              "2025-09-13": 86400.0,
              "2025-09-14": 86400.0,
              "2025-09-15": 86400.0,
              "2025-09-16": 86400.0,
              "2025-09-17": 86400.0,
              "2025-09-18": 86400.0,
              "2025-09-19": 86400.0,
              "2025-09-20": 86400.0,
              "2025-09-21": 86400.0,
              "2025-09-22": 86400.0,
              "2025-09-23": 86400.0,
              "2025-09-24": 86400.0,
              "2025-09-25": 86400.0,
              "2025-09-26": 86400.0,
              "2025-09-27": 86400.0,
              "2025-09-28": 86400.0,
              "2025-09-29": 86400.0,
              "2025-09-30": 86400.0,
              "2025-10-01": 86400.0,
              "2025-10-02": 86400.0,
              "2025-10-03": 86400.0,
              "2025-10-04": 86400.0,
              "2025-10-05": 86400.0,
              "2025-10-06": 86400.0,
              "2025-10-07": 86400.0,
              "2025-10-08": 86400.0,
              "2025-10-09": 86400.0,
              "2025-10-10": 86400.0,
              "2025-10-11": 86400.0,
              "2025-10-12": 86400.0,
              "2025-10-13": 86400.0,
              "2025-10-14": 86400.0,
              "2025-10-15": 86400.0,
              "2025-10-16": 86400.0,
              "2025-10-17": 86400.0,
              "2025-10-18": 86400.0,
              "2025-10-19": 86400.0,
              "2025-10-20": 86400.0,
              "2025-10-21": 86400.0,
              "2025-10-22": 86400.0,
              "2025-10-23": 86400.0,
              "2025-10-24": 86400.0,
              "2025-10-25": 86400.0,
              "2025-10-26": 86400.0,
              "2025-10-27": 86400.0,
              "2025-10-28": 86400.0,
              "2025-10-29": 86400.0,
              "2025-10-30": 86400.0,
              "2025-10-31": 86400.0,
              "2025-11-01": 86400.0,
              "2025-11-02": 86400.0,
              "2025-11-03": 86400.0,
              "2025-11-04": 86400.0,
              "2025-11-05": 86400.0,
              "2025-11-06": 86400.0,
              "2025-11-07": 86400.0,
              "2025-11-08": 86400.0,
              "2025-11-09": 86400.0,
              "2025-11-10": 86400.0,
              "2025-11-11": 86400.0,
              "2025-11-12": 86400.0,
              "2025-11-13": 86400.0,
              "2025-11-14": 86400.0,
              "2025-11-15": 86400.0,
              "2025-11-16": 86400.0,
              "2025-11-17": 86400.0,
              "2025-11-18": 86400.0,
              "2025-11-19": 86400.0,
              "2025-11-20": 86400.0,
              "2025-11-21": 86400.0,
              "2025-11-22": 86400.0,
              "2025-11-23": 86400.0,
              "2025-11-24": 86400.0,
              "2025-11-25": 86400.0,
              "2025-11-26": 86400.0,
              "2025-11-27": 86400.0,
              "2025-11-28": 86400.0,
              "2025-11-29": 86400.0,
              "2025-11-30": 86400.0,
              "2025-12-01": 86400.0,
              "2025-12-02": 86400.0,
              "2025-12-03": 86400.0,
              "2025-12-04": 86400.0,
              "2025-12-05": 86400.0,
              "2025-12-06": 86400.0,
              "2025-12-07": 86400.0,
              "2025-12-08": 86400.0,
              "2025-12-09": 86400.0,
              "2025-12-10": 86400.0,
              "2025-12-11": 86400.0,
              "2025-12-12": 86400.0,
              "2025-12-13": 86400.0,
              "2025-12-14": 86400.0,
              "2025-12-15": 86400.0,
              "2025-12-16": 86400.0,
              "2025-12-17": 86400.0,
              "2025-12-18": 86400.0,
              "2025-12-19": 86400.0,
              "2025-12-20": 86400.0,
              "2025-12-21": 86400.0,
              "2025-12-22": 86400.0,
              "2025-12-23": 86400.0,
              "2025-12-24": 86400.0,
              "2025-12-25": 86400.0,
              "2025-12-26": 86400.0,
              "2025-12-27": 86400.0,
              "2025-12-28": 86400.0,
              "2025-12-29": 86400.0,
              "2025-12-30": 86400.0,
              "2025-12-31": 86400.0,
              "2026-01-01": 86400.0,
              "2026-01-02": 86400.0,
              "2026-01-03": 86400.0,
              "2026-01-04": 86400.0,
              "2026-01-05": 86400.0,
              "2026-01-06": 86400.0,
              "2026-01-07": 86400.0,
              "2026-01-08": 86400.0,
              "2026-01-09": 86400.0,
              "2026-01-10": 86400.0,
              "2026-01-11": 86400.0,
              "2026-01-12": 86400.0,
              "2026-01-13": 86400.0,
              "2026-01-14": 86400.0,
              "2026-01-15": 86400.0,
              "2026-01-16": 86400.0,
              "2026-01-17": 86400.0,
              "2026-01-18": 86400.0,
              "2026-01-19": 86400.0,
              "2026-01-20": 86400.0,
              "2026-01-21": 86400.0,
              "2026-01-22": 86400.0,
              "2026-01-23": 86400.0,
              "2026-01-24": 86400.0,
              "2026-01-25": 86400.0,
              "2026-01-26": 86400.0,
              "2026-01-27": 86400.0,
              "2026-01-28": 86400.0,
              "2026-01-29": 86400.0,
              "2026-01-30": 86400.0,
              "2026-01-31": 86400.0,
              "2026-02-01": 86400.0,
              "2026-02-02": 86400.0,
              "2026-02-03": 86400.0,
              "2026-02-04": 86400.0,
              "2026-02-05": 86400.0,
              "2026-02-06": 86400.0,
              "2026-02-07": 86400.0,
              "2026-02-08": 86400.0,
              "2026-02-09": 86400.0,
              "2026-02-10": 86400.0,
              "2026-02-11": 86400.0,
              "2026-02-12": 86400.0,
              "2026-02-13": 86400.0,
              "2026-02-14": 86400.0,
              "2026-02-15": 86400.0,
              "2026-02-16": 86400.0,
              "2026-02-17": 86400.0,
              "2026-02-18": 86400.0,
              "2026-02-19": 86400.0,
              "2026-02-20": 86400.0,
              "2026-02-21": 86400.0,
              "2026-02-22": 86400.0,
              "2026-02-23": 86400.0,
              "2026-02-24": 86400.0,
              "2026-02-25": 86400.0,
              "2026-02-26": 86400.0,
              "2026-02-27": 86400.0,
              "2026-02-28": 86400.0,
              "2026-03-01": 86400.0,
              "2026-03-02": 86400.0,
              "2026-03-03": 86400.0,
              "2026-03-04": 86400.0,
              "2026-03-05": 86400.0,
              "2026-03-06": 86400.0,
              "2026-03-07": 86400.0,
              "2026-03-08": 86400.0,
              "2026-03-09": 86400.0,
              "2026-03-10": 86400.0,
              "2026-03-11": 86400.0,
              "2026-03-12": 86400.0,
              "2026-03-13": 86400.0,
              "2026-03-14": 86400.0,
              "2026-03-15": 86400.0,
              "2026-03-16": 86400.0,
              "2026-03-17": 86400.0,
              "2026-03-18": 86400.0,
              "2026-03-19": 86400.0,
              "2026-03-20": 86400.0,
              "2026-03-21": 86400.0,
              "2026-03-22": 86400.0,
              "2026-03-23": 86400.0,
              "2026-03-24": 86400.0,
              "2026-03-25": 86400.0,
              "2026-03-26": 86400.0,
              "2026-03-27": 86400.0,
              "2026-03-28": 86400.0,
              "2026-03-29": 86400.0,
              "2026-03-30": 86400.0,
              "2026-03-31": 86400.0,
              "2026-04-01": 86400.0,
              "2026-04-02": 86400.0,
              "2026-04-03": 86400.0,
              "2026-04-04": 86400.0,
              "2026-04-05": 86400.0,
              "2026-04-06": 86400.0,
              "2026-04-07": 86400.0,
              "2026-04-08": 86400.0,
              "2026-04-09": 86400.0,
              "2026-04-10": 44453.0
            },
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-10T12:21:21+00:00"
        },
        "rtpc": {
          "kernel": "5.15.197-rt91-hmnd-0",
          "os": "Ubuntu 22.04",
          "architecture": "x86_64",
          "hostname": "alpha9",
          "uptime_seconds": 17017,
          "memory_total_mb": 47921,
          "memory_free_mb": 34538,
          "release": null,
          "collected_at": "2026-04-10T12:19:38Z",
          "dns": {
            "servers": {
              "eth-shore": "10.44.10.1",
              "wifi-0": "10.44.10.1"
            },
            "search_domains": {
              "eth-shore": "hmnd.lan",
              "wifi-0": "hmnd.lan"
            },
            "dropins": "no drop-ins",
            "zones": {
              "local": true,
              "route53": true,
              "private": true,
              "public": true
            }
          },
          "wifi": [
            {
              "name": "wifi-1",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "5c:b2:6d:46:6d:0c",
              "ssid": null,
              "channel": null,
              "configured_ssid": null
            },
            {
              "name": "wifi-0",
              "driver": "iwlwifi",
              "firmware": "89.123cf747.0 ty-a0-gf-a0-89.uc",
              "mac": "5c:b2:6d:46:6d:0b",
              "ssid": "Alpha",
              "channel": 64,
              "configured_ssid": "Alpha",
              "station": {
                "rx_packets": 569143,
                "tx_packets": 2329,
                "tx_retries": 8,
                "tx_failed": 0,
                "beacon_loss": 0,
                "rx_drop_misc": 69023,
                "signal_dbm": -44,
                "signal_per_antenna": "[-46, -44]",
                "tx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "rx_bitrate": "286.7 MBit/s HE-MCS 11 HE-NSS 2 HE-GI 0 HE-DCM 0",
                "connected_seconds": 17010
              }
            }
          ],
          "interfaces": [
            {
              "name": "eth-shore",
              "operstate": "UP",
              "ip": "10.44.10.190",
              "mac": "00:13:95:69:b6:3a"
            },
            {
              "name": "wifi-0",
              "operstate": "UP",
              "ip": "10.44.10.19",
              "mac": "5c:b2:6d:46:6d:0b"
            },
            {
              "name": "wifi-1",
              "operstate": "DOWN",
              "ip": null,
              "mac": "5c:b2:6d:46:6e:6e"
            }
          ],
          "nm_profiles": [
            {
              "name": "eth-shore",
              "type": "ethernet",
              "interface": "eth-shore",
              "ssid": null,
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": null,
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "sw-internal",
              "type": "ethernet",
              "interface": "sw-internal",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "Alpha",
              "type": "wifi",
              "interface": "wifi-0",
              "ssid": "Alpha",
              "autoconnect": true,
              "priority": 0,
              "key_mgmt": "wpa-psk",
              "zone": "external",
              "state": "activated"
            },
            {
              "name": "hmnd0",
              "type": "wireguard",
              "interface": "hmnd0",
              "ssid": null,
              "autoconnect": false,
              "priority": 0,
              "key_mgmt": null,
              "zone": null,
              "state": "activated"
            },
            {
              "name": "hmnd-6ghz",
              "type": "wifi",
              "interface": "",
              "ssid": null,
              "autoconnect": true,
              "priority": 999,
              "key_mgmt": null,
              "zone": null,
              "state": ""
            }
          ],
          "dispatcher_scripts": [
            "10-hmnd-disable-offloads",
            "70-hmnd-qos"
          ],
          "utilization": {
            "boots": [
              {
                "index": -31,
                "start": "2026-03-20T10:11:23+00:00",
                "end": "2026-03-20T14:12:35+00:00",
                "duration_seconds": 14472,
                "running": false
              },
              {
                "index": -30,
                "start": "2026-03-20T14:38:54+00:00",
                "end": "2026-03-20T14:40:00+00:00",
                "duration_seconds": 66,
                "running": false
              },
              {
                "index": -29,
                "start": "2026-03-20T14:41:50+00:00",
                "end": "2026-03-20T15:53:54+00:00",
                "duration_seconds": 4324,
                "running": false
              },
              {
                "index": -28,
                "start": "2026-03-20T15:55:09+00:00",
                "end": "2026-03-20T17:54:59+00:00",
                "duration_seconds": 7190,
                "running": false
              },
              {
                "index": -27,
                "start": "2026-03-23T10:33:33+00:00",
                "end": "2026-03-23T10:35:46+00:00",
                "duration_seconds": 133,
                "running": false
              },
              {
                "index": -26,
                "start": "2026-03-23T10:37:36+00:00",
                "end": "2026-03-23T18:26:52+00:00",
                "duration_seconds": 28156,
                "running": false
              },
              {
                "index": -25,
                "start": "2026-03-24T11:41:10+00:00",
                "end": "2026-03-24T19:24:43+00:00",
                "duration_seconds": 27813,
                "running": false
              },
              {
                "index": -24,
                "start": "2026-03-25T09:42:38+00:00",
                "end": "2026-03-25T17:53:07+00:00",
                "duration_seconds": 29429,
                "running": false
              },
              {
                "index": -23,
                "start": "2026-03-25T17:54:31+00:00",
                "end": "2026-03-25T17:57:07+00:00",
                "duration_seconds": 156,
                "running": false
              },
              {
                "index": -22,
                "start": "2026-03-25T17:57:56+00:00",
                "end": "2026-03-25T18:00:20+00:00",
                "duration_seconds": 144,
                "running": false
              },
              {
                "index": -21,
                "start": "2026-03-25T18:01:11+00:00",
                "end": "2026-03-25T18:02:22+00:00",
                "duration_seconds": 71,
                "running": false
              },
              {
                "index": -20,
                "start": "2026-03-25T18:03:18+00:00",
                "end": "2026-03-25T19:08:51+00:00",
                "duration_seconds": 3933,
                "running": false
              },
              {
                "index": -19,
                "start": "2026-03-26T10:37:52+00:00",
                "end": "2026-03-26T10:39:03+00:00",
                "duration_seconds": 71,
                "running": false
              },
              {
                "index": -18,
                "start": "2026-03-26T10:48:34+00:00",
                "end": "2026-03-26T10:49:36+00:00",
                "duration_seconds": 62,
                "running": false
              },
              {
                "index": -17,
                "start": "2026-03-26T10:50:17+00:00",
                "end": "2026-03-26T10:50:35+00:00",
                "duration_seconds": 18,
                "running": false
              },
              {
                "index": -16,
                "start": "2026-03-26T10:51:19+00:00",
                "end": "2026-03-26T18:27:29+00:00",
                "duration_seconds": 27370,
                "running": false
              },
              {
                "index": -15,
                "start": "2026-03-27T10:19:40+00:00",
                "end": "2026-03-27T18:00:56+00:00",
                "duration_seconds": 27676,
                "running": false
              },
              {
                "index": -14,
                "start": "2026-03-28T17:19:37+00:00",
                "end": "2026-03-28T17:45:41+00:00",
                "duration_seconds": 1564,
                "running": false
              },
              {
                "index": -13,
                "start": "2026-03-30T09:54:40+00:00",
                "end": "2026-03-30T17:49:28+00:00",
                "duration_seconds": 28488,
                "running": false
              },
              {
                "index": -12,
                "start": "2026-03-31T09:09:52+00:00",
                "end": "2026-03-31T10:32:08+00:00",
                "duration_seconds": 4936,
                "running": false
              },
              {
                "index": -11,
                "start": "2026-03-31T10:49:31+00:00",
                "end": "2026-03-31T21:03:13+00:00",
                "duration_seconds": 36822,
                "running": false
              },
              {
                "index": -10,
                "start": "2026-04-01T07:26:37+00:00",
                "end": "2026-04-01T18:40:29+00:00",
                "duration_seconds": 40432,
                "running": false
              },
              {
                "index": -9,
                "start": "2026-04-02T07:57:00+00:00",
                "end": "2026-04-02T18:08:22+00:00",
                "duration_seconds": 36682,
                "running": false
              },
              {
                "index": -8,
                "start": "2026-04-07T06:41:22+00:00",
                "end": "2026-04-07T19:26:33+00:00",
                "duration_seconds": 45911,
                "running": false
              },
              {
                "index": -7,
                "start": "2026-04-08T07:56:33+00:00",
                "end": "2026-04-08T19:25:19+00:00",
                "duration_seconds": 41326,
                "running": false
              },
              {
                "index": -6,
                "start": "2026-04-09T05:52:45+00:00",
                "end": "2026-04-09T06:06:36+00:00",
                "duration_seconds": 831,
                "running": false
              },
              {
                "index": -5,
                "start": "2026-04-09T06:09:26+00:00",
                "end": "2026-04-09T09:33:56+00:00",
                "duration_seconds": 12270,
                "running": false
              },
              {
                "index": -4,
                "start": "2026-04-09T09:34:56+00:00",
                "end": "2026-04-09T09:35:52+00:00",
                "duration_seconds": 56,
                "running": false
              },
              {
                "index": -3,
                "start": "2026-04-09T09:38:12+00:00",
                "end": "2026-04-09T13:25:48+00:00",
                "duration_seconds": 13656,
                "running": false
              },
              {
                "index": -2,
                "start": "2026-04-09T13:26:34+00:00",
                "end": "2026-04-09T14:47:10+00:00",
                "duration_seconds": 4836,
                "running": false
              },
              {
                "index": -1,
                "start": "2026-04-09T15:09:09+00:00",
                "end": "2026-04-10T06:24:44+00:00",
                "duration_seconds": 54935,
                "running": false
              },
              {
                "index": 0,
                "start": "2026-04-10T07:36:10+00:00",
                "end": "2026-04-10T12:20:07+00:00",
                "duration_seconds": 17037,
                "running": false
              }
            ],
            "daily_seconds": {
              "2026-03-20": 26052.0,
              "2026-03-23": 28289.0,
              "2026-03-24": 27813.0,
              "2026-03-25": 33733.0,
              "2026-03-26": 27521.0,
              "2026-03-27": 27676.0,
              "2026-03-28": 1564.0,
              "2026-03-30": 28488.0,
              "2026-03-31": 41758.0,
              "2026-04-01": 40432.0,
              "2026-04-02": 36682.0,
              "2026-04-07": 45911.0,
              "2026-04-08": 41326.0,
              "2026-04-09": 63500.0,
              "2026-04-10": 40121.0
            },
            "total_boots_7d": 0,
            "total_on_seconds_7d": 0,
            "utilization_7d_pct": 0.0
          },
          "_source_mtime": "2026-04-10T12:21:21+00:00"
        }
      }
    },
    "source_mtime": "2026-04-10T13:16:49+00:00"
  },
  "console": {
    "updated": "2026-07-25T08:27:34Z",
    "available": true,
    "statusCode": 200,
    "robots": [
      {
        "id": 41,
        "name": "UMI 2",
        "shortName": "umi-2",
        "status": "active",
        "isSimulation": false,
        "model": "UMI",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 39,
        "name": "Egocentric 2",
        "shortName": "egocentric2",
        "status": "active",
        "isSimulation": false,
        "model": "Egocentric",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 42,
        "name": "Biped 3",
        "shortName": "biped3",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Biped)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 33,
        "name": "Quest 0",
        "shortName": "quest0",
        "status": "active",
        "isSimulation": false,
        "model": "Egocentric",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 43,
        "name": "Quest 1",
        "shortName": "quest1",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 44,
        "name": "Quest 2",
        "shortName": "quest2",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 45,
        "name": "Quest 3",
        "shortName": "quest3",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 46,
        "name": "Quest 4",
        "shortName": "quest4",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 47,
        "name": "Quest 5",
        "shortName": "quest5",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 48,
        "name": "Quest 6",
        "shortName": "quest6",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 1,
        "name": "H1",
        "shortName": "h1",
        "status": "active",
        "isSimulation": false,
        "model": null,
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 2,
        "name": "Adam",
        "shortName": "adam",
        "status": "inactive",
        "isSimulation": false,
        "model": null,
        "location": null,
        "deactivationDate": "2025-09-04T13:13:49.315757",
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 49,
        "name": "Quest 7",
        "shortName": "quest7",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 50,
        "name": "Quest 8",
        "shortName": "quest8",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 51,
        "name": "Quest 9",
        "shortName": "quest9",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 52,
        "name": "Quest 10",
        "shortName": "quest10",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 53,
        "name": "Quest 11",
        "shortName": "quest11",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 54,
        "name": "Quest 12",
        "shortName": "quest12",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 55,
        "name": "Quest 13",
        "shortName": "quest13",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 56,
        "name": "Quest 14",
        "shortName": "quest14",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 57,
        "name": "Quest 15",
        "shortName": "quest15",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 58,
        "name": "Quest 16",
        "shortName": "quest16",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 7,
        "name": "Dev",
        "shortName": "dev",
        "status": "inactive",
        "isSimulation": false,
        "model": null,
        "location": null,
        "deactivationDate": "2025-09-23T09:44:11.495060",
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 4,
        "name": "H1 (Sim)",
        "shortName": "h1-isaac",
        "status": "active",
        "isSimulation": true,
        "model": null,
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 18,
        "name": "Alpha 1 (Sim)",
        "shortName": "alpha-1-sim",
        "status": "active",
        "isSimulation": true,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 59,
        "name": "Quest 17",
        "shortName": "quest17",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 21,
        "name": "Alpha 2",
        "shortName": "alpha2",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 22,
        "name": "Alpha 5",
        "shortName": "alpha5",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 60,
        "name": "Quest 18",
        "shortName": "quest18",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 61,
        "name": "Quest 19",
        "shortName": "quest19",
        "status": "active",
        "isSimulation": false,
        "model": "Quest",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 20,
        "name": "Test 1",
        "shortName": "test-1",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 62,
        "name": "Alpha Biped 4",
        "shortName": "alpha_biped4",
        "status": "active",
        "isSimulation": false,
        "model": null,
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 24,
        "name": "Alpha 7",
        "shortName": "alpha7",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 63,
        "name": "Alpha Biped 2",
        "shortName": "alpha_biped2",
        "status": "active",
        "isSimulation": false,
        "model": null,
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 25,
        "name": "Alpha 6",
        "shortName": "alpha6",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 19,
        "name": "Alpha 3",
        "shortName": "alpha3",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 17,
        "name": "Alpha 1",
        "shortName": "alpha1",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 26,
        "name": "Alpha 8",
        "shortName": "alpha8",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 27,
        "name": "Alpha Biped 1",
        "shortName": "alphabiped01-orin",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Biped)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 28,
        "name": "XDOF UMI 1",
        "shortName": "xdof-umi-1",
        "status": "active",
        "isSimulation": false,
        "model": "UMI",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 5,
        "name": "rainbow-r2",
        "shortName": "rby2",
        "status": "active",
        "isSimulation": false,
        "model": "(Rainbow) RB-Y1",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 32,
        "name": "Alpha 11",
        "shortName": "alpha11",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 34,
        "name": "Alpha 12",
        "shortName": "alpha12",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 38,
        "name": "Alpha 9",
        "shortName": "alpha9",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 31,
        "name": "Alpha 10",
        "shortName": "alpha10",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 23,
        "name": "Alpha 4",
        "shortName": "alpha4",
        "status": "active",
        "isSimulation": false,
        "model": "Alpha (Wheelbase)",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 30,
        "name": "UMI 1",
        "shortName": "umi-1",
        "status": "active",
        "isSimulation": false,
        "model": "UMI",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 29,
        "name": "xdof-umi-20250523",
        "shortName": "xdof-umi-20250523",
        "status": "active",
        "isSimulation": false,
        "model": "UMI",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 8,
        "name": "rainbow-r3",
        "shortName": "rby3",
        "status": "active",
        "isSimulation": false,
        "model": "(Rainbow) RB-Y1",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 9,
        "name": "rainbow-r1",
        "shortName": "rby1",
        "status": "active",
        "isSimulation": false,
        "model": "(Rainbow) RB-Y1",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 12,
        "name": "rainbow-r4",
        "shortName": "rby4",
        "status": "active",
        "isSimulation": false,
        "model": "(Rainbow) RB-Y1",
        "location": "Lab",
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 13,
        "name": "rainbow-r5",
        "shortName": "rby5",
        "status": "active",
        "isSimulation": false,
        "model": "(Rainbow) RB-Y1",
        "location": "Lab",
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 11,
        "name": "rainbow-r6",
        "shortName": "rby6",
        "status": "active",
        "isSimulation": false,
        "model": "(Rainbow) RB-Y1",
        "location": "Lab",
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 14,
        "name": "rainbow-r7",
        "shortName": "rby7",
        "status": "active",
        "isSimulation": false,
        "model": "(Rainbow) RB-Y1",
        "location": "Lab",
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 16,
        "name": "Rainbow (Sim)",
        "shortName": "rby1-isaac",
        "status": "active",
        "isSimulation": true,
        "model": "(Rainbow) RB-Y1",
        "location": "isaac-sim",
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      },
      {
        "id": 37,
        "name": "Egocentric 1",
        "shortName": "egocentric1",
        "status": "active",
        "isSimulation": false,
        "model": "Egocentric",
        "location": null,
        "deactivationDate": null,
        "recordingCount": 0,
        "episodeCount": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingGood": 0,
        "operators": {}
      }
    ],
    "recentRecordings": [],
    "recentEpisodes": [
      {
        "id": 913439,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_49_40/",
        "createdAt": "2026-07-25T08:23:32.429378",
        "uploadStatus": "Converted",
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": "not_found",
        "project": null,
        "item": null
      },
      {
        "id": 913438,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_49_19/",
        "createdAt": "2026-07-25T08:23:32.077049",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913437,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_48_48/",
        "createdAt": "2026-07-25T08:23:31.781863",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913436,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_48_17/",
        "createdAt": "2026-07-25T08:23:31.442947",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913435,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_47_47/",
        "createdAt": "2026-07-25T08:23:31.092453",
        "uploadStatus": "Converted",
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": "not_found",
        "project": null,
        "item": null
      },
      {
        "id": 913434,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_47_22/",
        "createdAt": "2026-07-25T08:23:30.795991",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913433,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_46_56/",
        "createdAt": "2026-07-25T08:23:30.443619",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913432,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_46_33/",
        "createdAt": "2026-07-25T08:23:30.094819",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913431,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_46_00/",
        "createdAt": "2026-07-25T08:23:29.793361",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913430,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_45_30/",
        "createdAt": "2026-07-25T08:23:29.439415",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913429,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_44_54/",
        "createdAt": "2026-07-25T08:23:29.087731",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913428,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_44_49/",
        "createdAt": "2026-07-25T08:23:28.794198",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913427,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_44_16/",
        "createdAt": "2026-07-25T08:23:28.451951",
        "uploadStatus": "Converted",
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": "not_found",
        "project": null,
        "item": null
      },
      {
        "id": 913426,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_43_45/",
        "createdAt": "2026-07-25T08:23:28.101429",
        "uploadStatus": "Converted",
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": "not_found",
        "project": null,
        "item": null
      },
      {
        "id": 913425,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_43_19/",
        "createdAt": "2026-07-25T08:23:27.805067",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913424,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_42_42/",
        "createdAt": "2026-07-25T08:23:27.458173",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913423,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_42_14/",
        "createdAt": "2026-07-25T08:23:27.106892",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913422,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha8/record-pkg-id=9011/2026_07_25-07_41_32/",
        "createdAt": "2026-07-25T08:23:26.808115",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913421,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha4/record-pkg-id=9011/2026_07_24-09_46_53/",
        "createdAt": "2026-07-25T08:23:26.457835",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      },
      {
        "id": 913420,
        "recordingId": 9011,
        "robotName": "Alpha 4",
        "taskTitle": "QGF distillation",
        "operator": "Sergei Fedotov",
        "s3Url": "s3://hm-rainbow-mount/alpha4/record-pkg-id=9011/2026_07_24-09_46_27/",
        "createdAt": "2026-07-25T08:23:26.105258",
        "uploadStatus": null,
        "pickQuality": null,
        "controlMode": null,
        "pedalAction": null,
        "project": null,
        "item": null
      }
    ],
    "evaluationSessions": [
      {
        "id": 19,
        "title": "Machine feeding joint pi0.5 model",
        "description": "",
        "robotName": "rainbow-r5",
        "modelId": 13,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 12,
        "createdAt": "2025-10-01T10:48:35.950648",
        "comment": "",
        "trials": [
          {
            "id": 147,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-11_25_40/20251001_112540.mp4",
            "comment": "",
            "createdAt": "2025-10-01T11:26:12.323244"
          },
          {
            "id": 148,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-11_39_56/20251001_113956.mp4",
            "comment": "",
            "createdAt": "2025-10-01T11:41:14.429190"
          },
          {
            "id": 149,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-11_42_49/20251001_114249.mp4",
            "comment": "",
            "createdAt": "2025-10-01T11:46:13.940381"
          },
          {
            "id": 150,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-12_05_03/20251001_120503.mp4",
            "comment": "",
            "createdAt": "2025-10-01T12:06:18.034990"
          },
          {
            "id": 151,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-12_06_30/20251001_120630.mp4",
            "comment": "",
            "createdAt": "2025-10-01T12:11:18.566627"
          },
          {
            "id": 152,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-12_16_15/20251001_121615.mp4",
            "comment": "",
            "createdAt": "2025-10-01T12:16:19.867108"
          },
          {
            "id": 153,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-12_19_00/20251001_121900.mp4",
            "comment": "",
            "createdAt": "2025-10-01T12:21:19.655204"
          },
          {
            "id": 154,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-12_17_03/20251001_121703.mp4",
            "comment": "",
            "createdAt": "2025-10-01T12:21:20.884304"
          },
          {
            "id": 155,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-12_31_45/20251001_123145.mp4",
            "comment": "",
            "createdAt": "2025-10-01T17:55:40.556708"
          },
          {
            "id": 156,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-18_00_24/20251001_180024.mp4",
            "comment": "",
            "createdAt": "2025-10-01T18:00:45.260729"
          },
          {
            "id": 157,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-18_02_12/20251001_180212.mp4",
            "comment": "",
            "createdAt": "2025-10-01T18:05:44.921730"
          },
          {
            "id": 158,
            "videoLink": "s3://hm-rainbow-mount/rby5/session-id=19/2025_10_01-18_12_31/20251001_181231.mp4",
            "comment": "",
            "createdAt": "2025-10-01T18:15:48.874933"
          }
        ]
      },
      {
        "id": 18,
        "title": "test",
        "description": "test",
        "robotName": "Adam",
        "modelId": 1,
        "modelName": "",
        "evaluator": "Anastacia Koncz",
        "numTrials": 0,
        "createdAt": "2025-08-15T11:15:39.513476",
        "comment": "test",
        "trials": []
      },
      {
        "id": 17,
        "title": "Calibration check ",
        "description": "Checking if calibration has worked on R4",
        "robotName": "rainbow-r4",
        "modelId": 9,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 0,
        "createdAt": "2025-06-17T15:49:45.588009",
        "comment": "",
        "trials": []
      },
      {
        "id": 16,
        "title": "After 8  test for Calibration",
        "description": "Testing using Alfa 8 base positions",
        "robotName": "rainbow-r3",
        "modelId": 11,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 11,
        "createdAt": "2025-06-17T14:53:16.591907",
        "comment": "",
        "trials": [
          {
            "id": 136,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-14_54_00/20250617_145400.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:54:49.905366"
          },
          {
            "id": 137,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-14_55_44/20250617_145544.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:59:52.580251"
          },
          {
            "id": 138,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-14_58_57/20250617_145857.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:59:54.042936"
          },
          {
            "id": 139,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-14_57_00/20250617_145700.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:59:54.078920"
          },
          {
            "id": 140,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-15_04_29/20250617_150429.mp4",
            "comment": "",
            "createdAt": "2025-06-17T15:04:51.766335"
          },
          {
            "id": 141,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-14_59_53/20250617_145953.mp4",
            "comment": "",
            "createdAt": "2025-06-17T15:04:55.177510"
          },
          {
            "id": 142,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-15_02_12/20250617_150212.mp4",
            "comment": "",
            "createdAt": "2025-06-17T15:04:55.741057"
          },
          {
            "id": 143,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-15_00_59/20250617_150059.mp4",
            "comment": "",
            "createdAt": "2025-06-17T15:05:00.990219"
          },
          {
            "id": 144,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-15_03_20/20250617_150320.mp4",
            "comment": "",
            "createdAt": "2025-06-17T15:05:01.769933"
          },
          {
            "id": 145,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-15_06_29/20250617_150629.mp4",
            "comment": "",
            "createdAt": "2025-06-17T15:09:52.458076"
          },
          {
            "id": 146,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=16/2025_06_17-15_05_37/20250617_150537.mp4",
            "comment": "",
            "createdAt": "2025-06-17T15:09:54.944052"
          }
        ]
      },
      {
        "id": 15,
        "title": "Quavers  test for Calibration",
        "description": "10 Picks for testing ",
        "robotName": "rainbow-r3",
        "modelId": 10,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 10,
        "createdAt": "2025-06-17T14:39:20.845237",
        "comment": "",
        "trials": [
          {
            "id": 126,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=15/2025_06_17-14_39_42/20250617_143942.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:40:00.677642"
          },
          {
            "id": 127,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=15/2025_06_17-14_40_25/20250617_144025.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:44:49.904151"
          },
          {
            "id": 128,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=15/2025_06_17-14_41_01/20250617_144101.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:44:54.148725"
          },
          {
            "id": 129,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=15/2025_06_17-14_42_23/20250617_144223.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:44:54.917811"
          },
          {
            "id": 130,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=15/2025_06_17-14_41_54/20250617_144154.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:44:54.957773"
          },
          {
            "id": 131,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=15/2025_06_17-14_43_06/20250617_144306.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:45:02.645140"
          },
          {
            "id": 132,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=15/2025_06_17-14_43_35/20250617_144335.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:45:03.537990"
          },
          {
            "id": 133,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=15/2025_06_17-14_44_16/20250617_144416.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:45:06.076231"
          },
          {
            "id": 134,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=15/2025_06_17-14_44_46/20250617_144446.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:45:06.879725"
          },
          {
            "id": 135,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=15/2025_06_17-14_45_17/20250617_144517.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:49:50.661709"
          }
        ]
      },
      {
        "id": 14,
        "title": "Crumpets test for Calibration",
        "description": "",
        "robotName": "rainbow-r3",
        "modelId": 9,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 14,
        "createdAt": "2025-06-17T14:14:02.495402",
        "comment": "Actually Jack Running ",
        "trials": [
          {
            "id": 112,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_16_55/20250617_141655.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:19:44.750612"
          },
          {
            "id": 113,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_15_53/20250617_141553.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:19:44.770938"
          },
          {
            "id": 114,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_24_08/20250617_142408.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:24:46.008096"
          },
          {
            "id": 115,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_20_27/20250617_142027.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:24:46.924700"
          },
          {
            "id": 116,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_22_16/20250617_142216.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:24:47.682270"
          },
          {
            "id": 117,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_28_52/20250617_142852.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:29:50.396566"
          },
          {
            "id": 118,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_27_09/20250617_142709.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:29:50.564045"
          },
          {
            "id": 119,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_27_40/20250617_142740.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:29:53.784205"
          },
          {
            "id": 120,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_29_30/20250617_142930.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:29:54.010849"
          },
          {
            "id": 121,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_28_22/20250617_142822.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:29:56.615276"
          },
          {
            "id": 122,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_26_28/20250617_142628.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:29:59.953662"
          },
          {
            "id": 123,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_24_59/20250617_142459.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:30:02.386922"
          },
          {
            "id": 124,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_25_44/20250617_142544.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:30:02.589025"
          },
          {
            "id": 125,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=14/2025_06_17-14_30_03/20250617_143003.mp4",
            "comment": "",
            "createdAt": "2025-06-17T14:34:47.171728"
          }
        ]
      },
      {
        "id": 13,
        "title": "Testing quavers",
        "description": "",
        "robotName": "rainbow-r2",
        "modelId": 8,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 0,
        "createdAt": "2025-05-19T15:27:00.915273",
        "comment": "",
        "trials": []
      },
      {
        "id": 12,
        "title": "Quavers",
        "description": "",
        "robotName": "rainbow-r2",
        "modelId": 8,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 0,
        "createdAt": "2025-05-19T15:25:33.153170",
        "comment": "",
        "trials": []
      },
      {
        "id": 11,
        "title": "Quavers on R2",
        "description": "",
        "robotName": "rainbow-r2",
        "modelId": 8,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 0,
        "createdAt": "2025-05-19T15:25:02.803864",
        "comment": "",
        "trials": []
      },
      {
        "id": 10,
        "title": "Crumpets with recoveries",
        "description": "Evaluate whether adding recoveries to the crumpet dataset leads to better behavior",
        "robotName": "rainbow-r3",
        "modelId": 5,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 21,
        "createdAt": "2025-05-12T17:38:16.761466",
        "comment": "",
        "trials": [
          {
            "id": 26,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/20250512_174055.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:06.013737"
          },
          {
            "id": 27,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/20250512_174138.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:06.207897"
          },
          {
            "id": 28,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/20250512_174219.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:06.399085"
          },
          {
            "id": 29,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/20250512_174311.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:06.581359"
          },
          {
            "id": 30,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/20250512_174342.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:06.767381"
          },
          {
            "id": 64,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_40_28/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:17.399279"
          },
          {
            "id": 65,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_39_26/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:17.435117"
          },
          {
            "id": 66,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_41_38/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:17.765644"
          },
          {
            "id": 67,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_40_55/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:17.776915"
          },
          {
            "id": 68,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_42_19/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:18.358176"
          },
          {
            "id": 69,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_43_11/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:18.382103"
          },
          {
            "id": 25,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/20250512_174028.mp4",
            "comment": "The video was deleted and moved. ",
            "createdAt": "2025-05-13T16:49:05.824099"
          },
          {
            "id": 74,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_43_42/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:19.105587"
          },
          {
            "id": 104,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_40_55/evaluation_head.mp4",
            "comment": "Added manually via portal",
            "createdAt": "2025-05-13T19:38:25.095050"
          },
          {
            "id": 105,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_40_55/evaluation_head.mp4",
            "comment": "added manually",
            "createdAt": "2025-05-13T19:39:36.108102"
          },
          {
            "id": 106,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_40_55/evaluation_head.mp4",
            "comment": "added manually",
            "createdAt": "2025-05-13T19:41:42.970321"
          },
          {
            "id": 107,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_40_55/evaluation_head.mp4",
            "comment": "manual",
            "createdAt": "2025-05-13T19:43:38.169637"
          },
          {
            "id": 108,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_40_55/evaluation_head.mp4",
            "comment": "rest api created",
            "createdAt": "2025-05-13T19:48:15.012413"
          },
          {
            "id": 109,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/2025_05_12-17_40_55/evaluation_head.mp4",
            "comment": "rest api created",
            "createdAt": "2025-05-13T19:49:00.072077"
          },
          {
            "id": 110,
            "videoLink": "s3://hm-rainbow-mount/rby3/evaluation_session_id=2/20250507_090447.mp4",
            "comment": "created manually for testing. The video is not from this eval. ",
            "createdAt": "2025-05-13T20:05:24.131848"
          },
          {
            "id": 8,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=10/20250512_173926.mp4",
            "comment": "The video was deleted and moved. ",
            "createdAt": "2025-05-12T17:55:57.755970"
          }
        ]
      },
      {
        "id": 9,
        "title": "Quality street million model",
        "description": "",
        "robotName": "rainbow-r3",
        "modelId": 7,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 16,
        "createdAt": "2025-05-12T17:28:57.735596",
        "comment": "",
        "trials": [
          {
            "id": 56,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/20250512_172942.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:11.615968"
          },
          {
            "id": 57,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/20250512_173021.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:11.808316"
          },
          {
            "id": 58,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/20250512_173048.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:11.996690"
          },
          {
            "id": 59,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/20250512_173154.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:12.192215"
          },
          {
            "id": 60,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/20250512_173235.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:12.392561"
          },
          {
            "id": 61,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/20250512_173320.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:12.591853"
          },
          {
            "id": 62,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/20250512_173426.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:12.773149"
          },
          {
            "id": 63,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/20250512_173502.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:12.960146"
          },
          {
            "id": 95,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/2025_05_12-17_30_21/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:23.785364"
          },
          {
            "id": 96,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/2025_05_12-17_29_42/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:23.802959"
          },
          {
            "id": 98,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/2025_05_12-17_31_54/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:24.754857"
          },
          {
            "id": 99,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/2025_05_12-17_30_48/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:24.779063"
          },
          {
            "id": 100,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/2025_05_12-17_32_35/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:24.801720"
          },
          {
            "id": 101,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/2025_05_12-17_33_20/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:25.161835"
          },
          {
            "id": 102,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/2025_05_12-17_34_26/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:25.375613"
          },
          {
            "id": 103,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=9/2025_05_12-17_35_02/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:25.399112"
          }
        ]
      },
      {
        "id": 8,
        "title": "After eight slow",
        "description": "",
        "robotName": "rainbow-r3",
        "modelId": 3,
        "modelName": "",
        "evaluator": "Diogo Almeida",
        "numTrials": 34,
        "createdAt": "2025-05-12T17:06:46.848120",
        "comment": "",
        "trials": [
          {
            "id": 39,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_170856.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:08.439245"
          },
          {
            "id": 40,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_171032.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:08.617615"
          },
          {
            "id": 41,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_171125.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:08.808420"
          },
          {
            "id": 42,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_171215.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:09.005489"
          },
          {
            "id": 43,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_171335.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:09.190138"
          },
          {
            "id": 44,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_171413.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:09.379944"
          },
          {
            "id": 45,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_171528.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:09.568643"
          },
          {
            "id": 46,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_171655.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:09.765192"
          },
          {
            "id": 47,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_171733.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:09.946138"
          },
          {
            "id": 48,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_171900.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:10.132396"
          },
          {
            "id": 49,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_171942.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:10.312037"
          },
          {
            "id": 50,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_172026.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:10.500841"
          },
          {
            "id": 51,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_172153.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:10.691083"
          },
          {
            "id": 52,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_172230.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:10.874803"
          },
          {
            "id": 53,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_172329.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:11.060869"
          },
          {
            "id": 54,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_172409.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:11.245338"
          },
          {
            "id": 55,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/20250512_172744.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:11.432216"
          },
          {
            "id": 75,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_10_32/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:19.571631"
          },
          {
            "id": 82,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_12_15/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:20.376919"
          },
          {
            "id": 84,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_15_28/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:21.274083"
          },
          {
            "id": 85,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_14_13/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:21.286263"
          },
          {
            "id": 88,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_19_42/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:21.770645"
          },
          {
            "id": 91,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_22_30/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:22.886795"
          },
          {
            "id": 93,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_21_53/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:22.907431"
          },
          {
            "id": 94,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_27_44/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:23.776187"
          },
          {
            "id": 80,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_08_56/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:20.157685"
          },
          {
            "id": 81,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_11_25/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:20.179864"
          },
          {
            "id": 83,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_13_35/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:20.387708"
          },
          {
            "id": 86,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_16_55/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:21.295107"
          },
          {
            "id": 87,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_17_33/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:21.305199"
          },
          {
            "id": 89,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_19_00/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:21.781884"
          },
          {
            "id": 90,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_20_26/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:21.976005"
          },
          {
            "id": 92,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_23_29/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:22.897769"
          },
          {
            "id": 97,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=8/2025_05_12-17_24_09/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:23.813617"
          }
        ]
      },
      {
        "id": 7,
        "title": "After eight fast",
        "description": "Fast policy; image transforms; admittance controller fixes",
        "robotName": "rainbow-r3",
        "modelId": 1,
        "modelName": "",
        "evaluator": "Artem Shutak",
        "numTrials": 16,
        "createdAt": "2025-05-12T13:06:10.148062",
        "comment": "",
        "trials": [
          {
            "id": 31,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/20250512_131323.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:06.946121"
          },
          {
            "id": 32,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/20250512_131620.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:07.125978"
          },
          {
            "id": 33,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/20250512_131747.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:07.309428"
          },
          {
            "id": 34,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/20250512_131839.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:07.493933"
          },
          {
            "id": 35,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/20250512_131929.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:07.684980"
          },
          {
            "id": 36,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/20250512_132030.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:07.873477"
          },
          {
            "id": 37,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/20250512_132203.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:08.056300"
          },
          {
            "id": 38,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/20250512_132303.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:49:08.240949"
          },
          {
            "id": 70,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/2025_05_12-13_18_39/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:18.573073"
          },
          {
            "id": 71,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/2025_05_12-13_16_20/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:18.585408"
          },
          {
            "id": 72,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/2025_05_12-13_17_47/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:18.623436"
          },
          {
            "id": 73,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/2025_05_12-13_13_23/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:18.632346"
          },
          {
            "id": 78,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/2025_05_12-13_22_03/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:19.604058"
          },
          {
            "id": 76,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/2025_05_12-13_19_29/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:19.581390"
          },
          {
            "id": 77,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/2025_05_12-13_20_30/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:19.595161"
          },
          {
            "id": 79,
            "videoLink": "s3://hm-rainbow-mount/rby3/session-id=7/2025_05_12-13_23_03/evaluation_head.mp4",
            "comment": "",
            "createdAt": "2025-05-13T19:20:19.634749"
          }
        ]
      },
      {
        "id": 6,
        "title": "Test evaluatoin",
        "description": "sdfsdf",
        "robotName": "Dev",
        "modelId": 2,
        "modelName": "",
        "evaluator": "Artem Shutak",
        "numTrials": 1,
        "createdAt": "2025-05-09T15:01:34.678375",
        "comment": "testy test",
        "trials": [
          {
            "id": 111,
            "videoLink": "s3://hm-rainbow-mount/rby3/evaluation_session_id=2/20250507_090447.mp4",
            "comment": "pupupuuu",
            "createdAt": "2025-05-13T20:06:02.348484"
          }
        ]
      },
      {
        "id": 4,
        "title": "Test Session",
        "description": "",
        "robotName": "H1",
        "modelId": 1,
        "modelName": "",
        "evaluator": "Artem Shutak",
        "numTrials": 0,
        "createdAt": "2025-05-07T19:58:29.001508",
        "comment": "",
        "trials": []
      },
      {
        "id": 3,
        "title": "Test Session",
        "description": "",
        "robotName": "H1",
        "modelId": 1,
        "modelName": "",
        "evaluator": "Artem Shutak",
        "numTrials": 0,
        "createdAt": "2025-05-07T19:58:22.039435",
        "comment": "",
        "trials": []
      },
      {
        "id": 1,
        "title": "Test evaluation",
        "description": "Some description of the test",
        "robotName": "Dev",
        "modelId": 1,
        "modelName": "",
        "evaluator": "Artem Shutak",
        "numTrials": 3,
        "createdAt": "2025-05-01T22:15:15.623386",
        "comment": "Tratatatata",
        "trials": [
          {
            "id": 6,
            "videoLink": "s3://hm-rainbow-mount/rby3/evaluation_session_id=2/20250507_090707.mp4",
            "comment": "new one\nanother one",
            "createdAt": "2025-05-12T08:52:23.639843"
          },
          {
            "id": 7,
            "videoLink": "s3://hm-rainbow-mount/rby3/evaluation_session_id=2/2025_05_07-09_07_07/test_vid.mp4",
            "comment": "",
            "createdAt": "2025-05-12T17:05:14.311387"
          },
          {
            "id": 9,
            "videoLink": "s3://hm-rainbow-mount/rby3/evaluation_session_id=2/20250507_090707.mp4",
            "comment": "",
            "createdAt": "2025-05-13T16:15:39.082521"
          }
        ]
      }
    ],
    "mlModels": [],
    "users": [
      {
        "id": 3,
        "name": "Sergei Fedotov",
        "email": "sfed@skl.vc"
      },
      {
        "id": 1,
        "name": "Artem Shutak",
        "email": "ashu@skl.vc"
      },
      {
        "id": 4,
        "name": "Diogo Almeida",
        "email": "dalm@skl.vc"
      },
      {
        "id": 5,
        "name": "Arjun Liddar",
        "email": "alid@skl.vc"
      },
      {
        "id": 6,
        "name": "Amadeea Sara Filip",
        "email": "asfi@skl.vc"
      },
      {
        "id": 7,
        "name": "Mhara Koutsoudi",
        "email": "mkou@skl.vc"
      },
      {
        "id": 8,
        "name": "Anastacia Koncz",
        "email": "anak@skl.vc"
      },
      {
        "id": 9,
        "name": "Casey Atienza",
        "email": "kcva@skl.vc"
      },
      {
        "id": 10,
        "name": "Daniel Ponsford",
        "email": "danp@skl.vc"
      },
      {
        "id": 11,
        "name": "Warsame Sheikhdon",
        "email": "wash@skl.vc"
      },
      {
        "id": 14,
        "name": "Viktoria Glypti",
        "email": "veig@skl.vc"
      },
      {
        "id": 16,
        "name": "Grace Johnson",
        "email": "graj@thehumanoid.ai"
      },
      {
        "id": 17,
        "name": "Jamie Uy",
        "email": "jamu@thehumanoid.ai"
      },
      {
        "id": 18,
        "name": "Jaimin Pithwa",
        "email": "jaip@thehumanoid.ai"
      },
      {
        "id": 19,
        "name": "Claudio Coppola",
        "email": "ccop@thehumanoid.ai"
      },
      {
        "id": 20,
        "name": "Brian Delhaisse",
        "email": "bdel@skl.vc"
      },
      {
        "id": 21,
        "name": "Ezeddin Al Hakim",
        "email": "ezah@skl.vc"
      },
      {
        "id": 22,
        "name": "Jake Longley",
        "email": "jakl@thehumanoid.ai"
      },
      {
        "id": 23,
        "name": "Team Red",
        "email": "alid@skl.vc"
      },
      {
        "id": 24,
        "name": "Team Green",
        "email": "alid@skl.vc"
      },
      {
        "id": 25,
        "name": "Team Blue",
        "email": "alid@skl.vc"
      },
      {
        "id": 26,
        "name": "Polina Shorenko",
        "email": "pols@skl.vc"
      },
      {
        "id": 27,
        "name": "Krova Farik",
        "email": "kfar@skl.vc"
      },
      {
        "id": 28,
        "name": "XDOF",
        "email": "xdof-operator@thehumanoid.ai"
      },
      {
        "id": 29,
        "name": "Mohamed Hisham",
        "email": "mhis@thehumanoid.ai"
      },
      {
        "id": 30,
        "name": "Dilip Naidu Govind",
        "email": "dina@thehumanoid.ai"
      },
      {
        "id": 31,
        "name": "Hamza Shekhdon",
        "email": "hash@thehumanoid.ai"
      },
      {
        "id": 32,
        "name": "Alexandra Vorrea",
        "email": "alvo@thehumanoid.ai"
      },
      {
        "id": 33,
        "name": "Saleh Zaiba",
        "email": "saza@thehumanoid.ai"
      },
      {
        "id": 35,
        "name": "Tobias Jacob",
        "email": "tjac@thehumanoid.ai"
      },
      {
        "id": 36,
        "name": "Bao Tran",
        "email": "batr@thehumanoid.ai"
      },
      {
        "id": 34,
        "name": "Barbara Charles",
        "email": "bach@thehumanoid.ai"
      },
      {
        "id": 37,
        "name": "Rodrigo Zenha",
        "email": "rzen@skl.vc"
      },
      {
        "id": 38,
        "name": "Dmitrii Ovsiannikov",
        "email": "dovs@skl.vc"
      },
      {
        "id": 39,
        "name": "Yoo-Jin Jung",
        "email": "yjj@skl.vc"
      },
      {
        "id": 40,
        "name": "Federica Leo",
        "email": "federica.leo@thehumanoid.ai"
      },
      {
        "id": 41,
        "name": "Shihabuddeen Waqar",
        "email": "shihab.waqar@thehumanoid.ai"
      },
      {
        "id": 42,
        "name": "Rajat Sharma",
        "email": "rash@thehumanoid.ai"
      },
      {
        "id": 43,
        "name": "Noor K Mahdy",
        "email": "noor.mahdy@thehumanoid.ai"
      },
      {
        "id": 44,
        "name": "Karim Shaban",
        "email": "ksha@skl.vc"
      },
      {
        "id": 45,
        "name": "Aiden Pocha",
        "email": "aiden.pocha@hmnd.ai"
      },
      {
        "id": 15,
        "name": "Dan Mason",
        "email": "dmas@thehumanoid.ai"
      },
      {
        "id": 46,
        "name": "Richard Weight",
        "email": "riwe@thehumanoid.ai"
      },
      {
        "id": 47,
        "name": "Nia Oloyede",
        "email": "nolo@thehumanoid.ai"
      },
      {
        "id": 48,
        "name": "Saurabh Kumar",
        "email": "saurabh.kumar@thehumanoid.ai"
      },
      {
        "id": 49,
        "name": "Matteo Presutto",
        "email": "mapr@thehumanoid.ai"
      },
      {
        "id": 50,
        "name": "Jacob Moss",
        "email": "jamo@thehumanoid.ai"
      },
      {
        "id": 51,
        "name": "Edward Holder",
        "email": "edward.holder@thehumanoid.ai"
      },
      {
        "id": 52,
        "name": "Zayd Liloul",
        "email": "zali@thehumanoid.ai"
      },
      {
        "id": 53,
        "name": "Malorie Iovino",
        "email": "malorie.iovino@thehumanoid.ai"
      },
      {
        "id": 54,
        "name": "Saeid Samadi",
        "email": "ssam@skl.vc"
      },
      {
        "id": 55,
        "name": "Omkar Ninawe",
        "email": "onin@skl.vc"
      },
      {
        "id": 56,
        "name": "Joe Jeffcock",
        "email": "joe.jeffcock@thehumanoid.ai"
      },
      {
        "id": 57,
        "name": "Fanqi Xu",
        "email": "fanqi.xu@thehumanoid.ai"
      },
      {
        "id": 58,
        "name": "Fanqi",
        "email": "fanqi.xu@thehumanoid.ai"
      },
      {
        "id": 59,
        "name": "Aisha Marenah",
        "email": "aisha.marenah@thehumanoid.ai"
      },
      {
        "id": 60,
        "name": "Adrian Petrescu",
        "email": "adpe@thehumanoid.ai"
      },
      {
        "id": 61,
        "name": "Jin Rhee",
        "email": "jin.rhee@thehumanoid.ai"
      },
      {
        "id": 62,
        "name": "Raphael Shuaibu",
        "email": "raphael.shuaibu@thehumanoid.ai"
      }
    ],
    "projects": [
      {
        "id": 6,
        "name": "Alpha Ring Picking",
        "description": "Metadata Template for Ring picking with alpha",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Item",
          "prompt",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "Task Stage",
          "Gripper Type"
        ],
        "requiredKeys": [
          "Item",
          "prompt",
          "Pick Quality",
          "Task Stage",
          "Gripper Type"
        ]
      },
      {
        "id": 27,
        "name": "Amazon",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Control Mode",
          "is_onsite",
          "Project",
          "Box type",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "Task Stage",
          "Amazon Recovery Type",
          "Certified"
        ],
        "requiredKeys": [
          "Control Mode",
          "is_onsite",
          "Project",
          "Pick Quality",
          "Task Stage",
          "Amazon Recovery Type",
          "Certified"
        ]
      },
      {
        "id": 29,
        "name": "Beta feasibility study",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Project",
          "Tote",
          "Task Stage",
          "Tote pick type"
        ],
        "requiredKeys": [
          "Project",
          "Tote",
          "Task Stage",
          "Tote pick type"
        ]
      },
      {
        "id": 13,
        "name": "Bosch",
        "description": "PoC",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Item",
          "is_onsite",
          "Pick Quality",
          "Comment",
          "Re-reviewed",
          "Bosch_Stage",
          "Technical Issue"
        ],
        "requiredKeys": [
          "Item",
          "Pick Quality",
          "Bosch_Stage"
        ]
      },
      {
        "id": 5,
        "name": "Bussing",
        "description": "Template with the new bussing task annotations",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Item",
          "Arm",
          "prompt",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "Item 2"
        ],
        "requiredKeys": [
          "Item",
          "Arm",
          "prompt",
          "Pick Quality"
        ]
      },
      {
        "id": 31,
        "name": "Capability Factory - Ring on stick",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Item",
          "Project",
          "Pick Quality",
          "Task Stage"
        ],
        "requiredKeys": [
          "Item",
          "Project",
          "Pick Quality",
          "Task Stage"
        ]
      },
      {
        "id": 21,
        "name": "Ceva",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "is_onsite",
          "Project",
          "Ceva Task Stage",
          "Payload",
          "Pick Quality",
          "Technical Issue",
          "Gripper Type"
        ],
        "requiredKeys": [
          "Project",
          "Ceva Task Stage",
          "Payload",
          "Pick Quality",
          "Gripper Type"
        ]
      },
      {
        "id": 10,
        "name": "Common",
        "description": "The template where we have one required field: pick_quality. We can use it where the whole package is homogeneous and doesn't need episode-level labelling",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Pick Quality",
          "Comment",
          "Technical Issue"
        ],
        "requiredKeys": [
          "Pick Quality"
        ]
      },
      {
        "id": 16,
        "name": "FT Tests",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Item",
          "Project",
          "Control Mode",
          "is_onsite",
          "FT Tests Task Stage",
          "Item 2",
          "Pick Quality",
          "Comment"
        ],
        "requiredKeys": [
          "Item",
          "Project",
          "Control Mode",
          "is_onsite",
          "FT Tests Task Stage",
          "Item 2",
          "Pick Quality"
        ]
      },
      {
        "id": 23,
        "name": "Household Biped",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Recovery Type",
          "Household Biped Project",
          "Household Items",
          "Pick Quality",
          "Comment",
          "Re-reviewed",
          "Technical Issue",
          "Arm",
          "Household totes",
          "Terminal",
          "Certified"
        ],
        "requiredKeys": [
          "Household Biped Project",
          "Household Items",
          "Pick Quality",
          "Arm",
          "Household totes",
          "Terminal",
          "Certified"
        ]
      },
      {
        "id": 20,
        "name": "Household Egocentric",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Item",
          "Arm",
          "Household Egocentric Stage",
          "Household Items",
          "Robot height",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "Terminal"
        ],
        "requiredKeys": [
          "Item",
          "Arm",
          "Household Egocentric Stage",
          "Robot height",
          "Pick Quality",
          "Terminal"
        ]
      },
      {
        "id": 12,
        "name": "Martur Fompak",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Item",
          "Technical Issue",
          "Action Type",
          "Martur Task Stage",
          "Pick Quality",
          "Comment",
          "Re-reviewed",
          "prompt"
        ],
        "requiredKeys": [
          "Item",
          "Martur Task Stage",
          "Pick Quality",
          "prompt"
        ]
      },
      {
        "id": 7,
        "name": "Picking and Placing tote",
        "description": "Picking and Placing tote",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Re-reviewed",
          "prompt",
          "Item",
          "Pick Quality",
          "Arm",
          "Comment",
          "Technical Issue",
          "Task Stage with Tote",
          "Action Type"
        ],
        "requiredKeys": [
          "prompt",
          "Item",
          "Pick Quality",
          "Arm",
          "Task Stage with Tote"
        ]
      },
      {
        "id": 28,
        "name": "Ring Picking 2026",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Bin size",
          "is_onsite",
          "Project",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "Task Stage",
          "Ring Picking Pick Recovery Type",
          "Ring Type",
          "Gripper Type",
          "Bin depth",
          "Torso turn direction",
          "Certified",
          "Robot Rotation"
        ],
        "requiredKeys": [
          "Bin size",
          "is_onsite",
          "Project",
          "Pick Quality",
          "Task Stage",
          "Ring Picking Pick Recovery Type",
          "Ring Type",
          "Gripper Type",
          "Bin depth",
          "Certified"
        ]
      },
      {
        "id": 14,
        "name": "Robostore",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Project",
          "Control Mode",
          "is_onsite",
          "Robostore Task Stage",
          "Robostore Right Item",
          "Robostore Left Item",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "is_robostore_wait_handover"
        ],
        "requiredKeys": [
          "Project",
          "Control Mode",
          "is_onsite",
          "Robostore Task Stage",
          "Robostore Right Item",
          "Robostore Left Item",
          "Pick Quality"
        ]
      },
      {
        "id": 17,
        "name": "Robostore Bussing",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Project",
          "Control Mode",
          "is_onsite",
          "prompt",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "Robostore Bussing Task Stage",
          "Action Type"
        ],
        "requiredKeys": [
          "Project",
          "Control Mode",
          "is_onsite",
          "prompt",
          "Pick Quality",
          "Robostore Bussing Task Stage"
        ]
      },
      {
        "id": 9,
        "name": "Robot Skills",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Pre-training tasks",
          "prompt",
          "Item",
          "Pick Quality",
          "Arm",
          "Comment",
          "Technical Issue"
        ],
        "requiredKeys": [
          "Pre-training tasks",
          "prompt",
          "Item",
          "Pick Quality",
          "Arm"
        ]
      },
      {
        "id": 30,
        "name": "Schaeffler Pilot",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Tote",
          "Pick Quality",
          "Comment",
          "Task Stage"
        ],
        "requiredKeys": [
          "Tote",
          "Pick Quality",
          "Task Stage"
        ]
      },
      {
        "id": 11,
        "name": "Symphony Biped",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Symphony Biped Task Stage",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "Action Type"
        ],
        "requiredKeys": [
          "Symphony Biped Task Stage",
          "Pick Quality"
        ]
      },
      {
        "id": 8,
        "name": "Symphony Bussing",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Item 2",
          "prompt",
          "Item",
          "Pick Quality",
          "Arm",
          "Comment",
          "Technical Issue",
          "Bussing_Symphony",
          "Action Type"
        ],
        "requiredKeys": [
          "prompt",
          "Item",
          "Pick Quality",
          "Arm",
          "Bussing_Symphony"
        ]
      },
      {
        "id": 18,
        "name": "Symphony II",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Symphony II Task Stage",
          "Project",
          "Tote",
          "Symphony II Item",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "With new UMI mount"
        ],
        "requiredKeys": [
          "Symphony II Task Stage",
          "Project",
          "Tote",
          "Symphony II Item",
          "Pick Quality"
        ]
      },
      {
        "id": 24,
        "name": "Symphony II Objects",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Recovery Type",
          "Environment",
          "Symphony II Task Stage",
          "Project",
          "Tote",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "Symphony II right item",
          "Symphony II left item",
          "dev_branch",
          "Terminal",
          "Gripper Type"
        ],
        "requiredKeys": [
          "Environment",
          "Symphony II Task Stage",
          "Project",
          "Tote",
          "Pick Quality",
          "Symphony II right item",
          "Symphony II left item",
          "Gripper Type"
        ]
      },
      {
        "id": 19,
        "name": "System 1.5 [Memory]",
        "description": "A memory layer for the VLA",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Project",
          "Pick Quality"
        ],
        "requiredKeys": [
          "Project",
          "Pick Quality"
        ]
      },
      {
        "id": 26,
        "name": "Test",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Task Stage"
        ],
        "requiredKeys": [
          "Task Stage"
        ]
      },
      {
        "id": 15,
        "name": "UMI",
        "description": "",
        "recordings": 0,
        "totalEpisodes": 0,
        "labelingComplete": 0,
        "labelingRequired": 0,
        "labelingNotRequired": 0,
        "labelingGood": 0,
        "metadataKeys": [
          "Item",
          "Item 2",
          "prompt",
          "Project",
          "UMI task stages",
          "Pick Quality",
          "Comment",
          "Technical Issue",
          "Arm",
          "Gripper Type"
        ],
        "requiredKeys": [
          "Item",
          "UMI task stages",
          "Pick Quality",
          "Gripper Type"
        ]
      }
    ],
    "episodeStats": {
      "total": 375577,
      "uploadStatus": {
        "Converted": 1969,
        "MissingMetadataFile": 2,
        "MissingMetadata": 2,
        "NoVideoTopics": 1
      },
      "pickQuality": {
        "Good quality": 215,
        "Mistake": 194,
        "Bad quality": 67
      },
      "controlMode": {
        "teleop": 313
      },
      "pedalAction": {
        "saved": 840,
        "not_found": 647,
        "rejected": 487
      },
      "sampled": 2000
    },
    "stats": {
      "totalRecordings": 9052,
      "totalEpisodes": 0,
      "byRobot": {},
      "byTemplate": {},
      "byOperator": {},
      "byOperatorDetail": {},
      "episodesByRobot": {},
      "labeling": {
        "complete": 0,
        "required": 0,
        "notRequired": 0,
        "good": 0
      }
    }
  },
  "changes": {
    "compared_to": "2026-07-25T08:22:22.990558+00:00",
    "computed_at": "2026-07-25T08:27:34.029096+00:00",
    "summary": {
      "added": 0,
      "removed": 0,
      "changed": 35
    },
    "sections": {
      "console": {
        "robots": {
          "added": [],
          "removed": [],
          "changed": [
            {
              "name": "Quest 7",
              "field": "recordingCount",
              "from": 1,
              "to": 0
            },
            {
              "name": "Quest 7",
              "field": "episodeCount",
              "from": 49,
              "to": 0
            },
            {
              "name": "Alpha 12",
              "field": "recordingCount",
              "from": 57,
              "to": 0
            },
            {
              "name": "Alpha 12",
              "field": "episodeCount",
              "from": 1851,
              "to": 0
            },
            {
              "name": "Alpha 10",
              "field": "recordingCount",
              "from": 11,
              "to": 0
            },
            {
              "name": "Alpha 10",
              "field": "episodeCount",
              "from": 22,
              "to": 0
            },
            {
              "name": "UMI 1",
              "field": "recordingCount",
              "from": 37,
              "to": 0
            },
            {
              "name": "UMI 1",
              "field": "episodeCount",
              "from": 1323,
              "to": 0
            },
            {
              "name": "UMI 2",
              "field": "recordingCount",
              "from": 4,
              "to": 0
            },
            {
              "name": "UMI 2",
              "field": "episodeCount",
              "from": 149,
              "to": 0
            },
            {
              "name": "Biped 3",
              "field": "recordingCount",
              "from": 102,
              "to": 0
            },
            {
              "name": "Biped 3",
              "field": "episodeCount",
              "from": 2592,
              "to": 0
            },
            {
              "name": "Alpha 4",
              "field": "recordingCount",
              "from": 1,
              "to": 0
            },
            {
              "name": "Alpha 4",
              "field": "episodeCount",
              "from": 662,
              "to": 0
            },
            {
              "name": "Alpha 2",
              "field": "recordingCount",
              "from": 18,
              "to": 0
            },
            {
              "name": "Alpha 2",
              "field": "episodeCount",
              "from": 62,
              "to": 0
            },
            {
              "name": "Egocentric 1",
              "field": "recordingCount",
              "from": 2,
              "to": 0
            },
            {
              "name": "Egocentric 1",
              "field": "episodeCount",
              "from": 11,
              "to": 0
            },
            {
              "name": "Alpha 7",
              "field": "recordingCount",
              "from": 13,
              "to": 0
            },
            {
              "name": "Alpha 7",
              "field": "episodeCount",
              "from": 492,
              "to": 0
            },
            {
              "name": "Quest 5",
              "field": "recordingCount",
              "from": 1,
              "to": 0
            },
            {
              "name": "Alpha 1 (Sim)",
              "field": "recordingCount",
              "from": 4,
              "to": 0
            },
            {
              "name": "Alpha 1 (Sim)",
              "field": "episodeCount",
              "from": 234,
              "to": 0
            },
            {
              "name": "Alpha 11",
              "field": "recordingCount",
              "from": 40,
              "to": 0
            },
            {
              "name": "Alpha 11",
              "field": "episodeCount",
              "from": 2753,
              "to": 0
            },
            {
              "name": "Alpha 3",
              "field": "recordingCount",
              "from": 53,
              "to": 0
            },
            {
              "name": "Alpha 3",
              "field": "episodeCount",
              "from": 1531,
              "to": 0
            },
            {
              "name": "Alpha 5",
              "field": "recordingCount",
              "from": 91,
              "to": 0
            },
            {
              "name": "Alpha 5",
              "field": "episodeCount",
              "from": 3826,
              "to": 0
            },
            {
              "name": "Alpha 6",
              "field": "recordingCount",
              "from": 56,
              "to": 0
            },
            {
              "name": "Alpha 6",
              "field": "episodeCount",
              "from": 1617,
              "to": 0
            },
            {
              "name": "Alpha 9",
              "field": "recordingCount",
              "from": 1,
              "to": 0
            },
            {
              "name": "Alpha 9",
              "field": "episodeCount",
              "from": 1,
              "to": 0
            },
            {
              "name": "Egocentric 2",
              "field": "recordingCount",
              "from": 8,
              "to": 0
            },
            {
              "name": "Egocentric 2",
              "field": "episodeCount",
              "from": 110,
              "to": 0
            }
          ]
        }
      }
    }
  }
}