{
  "schema_version": 1,
  "channel": "homelab-runtime",
  "command_id": "CLUSTER-REFERENCE-MODE-SEMANTICS-153",
  "status": "OK",
  "rc": 0,
  "host": "pve01",
  "mode": "read-only",
  "component": "cluster-audit",
  "started_at_utc": "2026-07-22T07:56:06Z",
  "finished_at_utc": "2026-07-22T07:56:06Z",
  "reference_register_checked": true,
  "reference_sha256": "5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e",
  "error_register_checked": true,
  "error_register_sha256": "08b3a769b8e38eaa1acec915352fb328180d70caa7ff6cd9d1ec0da426262752",
  "command_sha256": "8dc27e444049919a8436dfda6dbbf1e6f925075388cb73ecf483b2944f0dcf2e",
  "duplicate_failed_command_blocked": false,
  "block_reason": null,
  "execution_started": true,
  "changes_made": false,
  "sanitized": true,
  "secrets_included": false,
  "private_addresses_included": false,
  "raw_evidence_retained_locally": true,
  "raw_evidence_sha256": "5a67f7767c4daff72ce91f626619b8d4251dbd9378ec9d757183506a3e9345d0",
  "sanitized_output_sha256": "1d71af6fb931c9d83bc82e594516212e45cd585f292d30486e0939ba5708acd0",
  "output_truncated_in_json": false,
  "full_sanitized_output_url": "https://git.gram1.ru/.well-known/homelab-runtime/latest.txt",
  "output": "PREVIOUS_RESULT=VERIFIED\nPREVIOUS_IMMUTABLE_COMMIT=fa3878ea8aeec87002c4c8f179fb88e25184e924\n=== RUNNER_HELP ===\nUsage:\n  homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]\n\nMODE:\n  read-only\n  verify\n  change\n  transport-test\n\nEnvironment:\n  HOMELAB_ALLOW_REPEAT=1   Allow exact repeat of a previously failed command.\n  HOMELAB_TIMEOUT=SECONDS  Optional command timeout.\n=== MODE_VALIDATION_AND_EFFECTS ===\n1-#!/usr/bin/env bash\n2-set -Eeuo pipefail\n3-umask 077\n4-\n5-usage() {\n6-    cat >&2 <<'USAGE'\n7-Usage:\n8-  homelab-chat-run COMMAND_ID MODE COMPONENT -- command [arguments...]\n9-\n10-MODE:\n11:  read-only\n12:  verify\n13:  change\n14:  transport-test\n15-\n16-Environment:\n17-  HOMELAB_ALLOW_REPEAT=1   Allow exact repeat of a previously failed command.\n18-  HOMELAB_TIMEOUT=SECONDS  Optional command timeout.\n19-USAGE\n20-    exit 64\n21-}\n22-\n23-[ \"$#\" -ge 5 ] || usage\n24-\n25-COMMAND_ID=\"$1\"\n26-MODE=\"$2\"\n27-COMPONENT=\"$3\"\n28-shift 3\n29-\n30-[ \"${1:-}\" = '--' ] || usage\n31-shift\n32-[ \"$#\" -ge 1 ] || usage\n33-\n34-case \"$COMMAND_ID\" in\n35-    ''|*[!A-Za-z0-9._-]*)\n36-        echo 'RESULT=FAIL'\n37-        echo 'REASON=INVALID_COMMAND_ID'\n38-        exit 65\n39-        ;;\n40-esac\n41-\n42-case \"$COMPONENT\" in\n43-    ''|*[!A-Za-z0-9._-]*)\n44-        echo 'RESULT=FAIL'\n45-        echo 'REASON=INVALID_COMPONENT'\n46-        exit 66\n47-        ;;\n48-esac\n49-\n50:case \"$MODE\" in\n51:    read-only|verify|change|transport-test)\n52-        ;;\n53-    *)\n54-        echo 'RESULT=FAIL'\n55:        echo 'REASON=INVALID_MODE'\n56-        exit 67\n57-        ;;\n58-esac\n59-\n60-for TOOL in \\\n61-    awk \\\n62-    curl \\\n63-    flock \\\n64-    python3 \\\n65-    scp \\\n66-    sha256sum \\\n67-    ssh\n68-do\n69-    command -v \"$TOOL\" >/dev/null 2>&1 || {\n70-        echo 'RESULT=FAIL'\n71-        echo \"REASON=REQUIRED_TOOL_MISSING:$TOOL\"\n72-        exit 68\n73-    }\n74-done\n75-\n76-REFERENCE=/etc/pve/31_HOMELAB_REFERENCE.md\n77-ERROR_REGISTER=/etc/pve/HOMELAB_ASSISTANT_ERROR_REGISTER.md\n78-\n79-[ -r \"$REFERENCE\" ] || {\n80-    echo 'RESULT=FAIL'\n81-    echo 'REASON=REFERENCE_NOT_READABLE'\n82-    exit 69\n83-}\n84-\n85-[ -r \"$ERROR_REGISTER\" ] || {\n86-    echo 'RESULT=FAIL'\n87-    echo 'REASON=ERROR_REGISTER_NOT_READABLE'\n88-    exit 70\n89-}\n90-\n91-STATE_DIR=/var/lib/homelab-chat-run\n92-RAW_DIR=\"$STATE_DIR/raw\"\n93-PUBLIC_DIR=\"$STATE_DIR/public\"\n94-LEDGER=\"$STATE_DIR/state/command-ledger.tsv\"\n95-LOCK=\"$STATE_DIR/state/runner.lock\"\n--\n131-\n132-PREVIOUS_FAILED_RC=\"$(\n133-    awk -F '\\t' -v hash=\"$COMMAND_SHA256\" '\n134-        $3 == hash && $4 != \"0\" {\n135-            value=$4\n136-        }\n137-\n138-        END {\n139-            print value\n140-        }\n141-    ' \"$LEDGER\"\n142-)\"\n143-\n144-RUN_STARTED=true\n145-REPEAT_BLOCKED=false\n146:BLOCK_REASON=''\n147:CHANGES_MADE=false\n148-\n149:case \"$MODE\" in\n150:    change)\n151:        CHANGES_MADE=true\n152-        ;;\n153-esac\n154-\n155-if [ -n \"$PREVIOUS_FAILED_RC\" ] &&\n156-   [ \"${HOMELAB_ALLOW_REPEAT:-0}\" != 1 ]; then\n157-\n158-    RUN_STARTED=false\n159-    REPEAT_BLOCKED=true\n160:    BLOCK_REASON='EXACT_FAILED_COMMAND_REPEAT'\n161-    RC=73\n162-    STATUS='BLOCKED'\n163-\n164-    {\n165-        echo 'COMMAND_EXECUTION_BLOCKED=yes'\n166-        echo 'REASON=EXACT_FAILED_COMMAND_REPEAT'\n167-        echo \"PREVIOUS_RC=$PREVIOUS_FAILED_RC\"\n168-        echo \"COMMAND_SHA256=$COMMAND_SHA256\"\n169-        echo\n170-        echo 'Set HOMELAB_ALLOW_REPEAT=1 only after reviewing the previous failure.'\n171-    } >\"$RAW_FILE\"\n172-else\n173-    set +e\n174-\n175-    if [ -n \"${HOMELAB_TIMEOUT:-}\" ]; then\n176-        case \"$HOMELAB_TIMEOUT\" in\n177-            *[!0-9]*|'')\n178-                echo 'RESULT=FAIL'\n179-                echo 'REASON=INVALID_HOMELAB_TIMEOUT'\n180-                exit 74\n181-                ;;\n182-        esac\n183-\n184-        timeout \\\n185-            --foreground \\\n186-            --preserve-status \\\n187-            \"$HOMELAB_TIMEOUT\" \\\n188-            \"$@\" >\"$RAW_FILE\" 2>&1\n189-        RC=$?\n190-    else\n191-        \"$@\" >\"$RAW_FILE\" 2>&1\n192-        RC=$?\n193-    fi\n194-\n195-    set -e\n196-\n197-    if [ \"$RC\" -eq 0 ]; then\n198-        STATUS='OK'\n199-    else\n200-        STATUS='FAIL'\n--\n317-    \"$COMMAND_ID\" \\\n318-    \"$STATUS\" \\\n319-    \"$RC\" \\\n320-    \"$HOST_SHORT\" \\\n321-    \"$MODE\" \\\n322-    \"$COMPONENT\" \\\n323-    \"$STARTED_AT\" \\\n324-    \"$FINISHED_AT\" \\\n325-    \"$REFERENCE_SHA256\" \\\n326-    \"$ERROR_REGISTER_SHA256\" \\\n327-    \"$COMMAND_SHA256\" \\\n328-    \"$RAW_SHA256\" \\\n329-    \"$SANITIZED_SHA256\" \\\n330-    \"$RUN_STARTED\" \\\n331-    \"$REPEAT_BLOCKED\" \\\n332:    \"$BLOCK_REASON\" \\\n333:    \"$CHANGES_MADE\" <<'PY'\n334-import json\n335-import sys\n336-from pathlib import Path\n337-\n338-(\n339-    json_path,\n340-    output_path,\n341-    command_id,\n342-    status,\n343-    rc,\n344-    host,\n345-    mode,\n346-    component,\n347-    started,\n348-    finished,\n349-    reference_sha,\n350-    error_sha,\n351-    command_sha,\n352-    raw_sha,\n353-    sanitized_sha,\n354-    run_started,\n355-    repeat_blocked,\n356:    block_reason,\n357:    changes_made,\n358-) = sys.argv[1:]\n359-\n360-output = Path(output_path).read_text(\n361-    encoding=\"utf-8\",\n362-    errors=\"replace\",\n363-)\n364-\n365-encoded = output.encode(\"utf-8\")\n366-json_limit = 300_000\n367-output_truncated = len(encoded) > json_limit\n368-\n369-if output_truncated:\n370-    output_preview = encoded[:json_limit].decode(\n371-        \"utf-8\",\n372-        errors=\"ignore\",\n373-    )\n374-else:\n375-    output_preview = output\n376-\n377-document = {\n378-    \"schema_version\": 1,\n379-    \"channel\": \"homelab-runtime\",\n380-    \"command_id\": command_id,\n381-    \"status\": status,\n382-    \"rc\": int(rc),\n383-    \"host\": host,\n384-    \"mode\": mode,\n385-    \"component\": component,\n386-    \"started_at_utc\": started,\n387-    \"finished_at_utc\": finished,\n388-    \"reference_register_checked\": True,\n389-    \"reference_sha256\": reference_sha,\n390-    \"error_register_checked\": True,\n391-    \"error_register_sha256\": error_sha,\n392-    \"command_sha256\": command_sha,\n393-    \"duplicate_failed_command_blocked\": repeat_blocked == \"true\",\n394:    \"block_reason\": block_reason or None,\n395:    \"execution_started\": run_started == \"true\",\n396:    \"changes_made\": changes_made == \"true\",\n397-    \"sanitized\": True,\n398-    \"secrets_included\": False,\n399-    \"private_addresses_included\": False,\n400-    \"raw_evidence_retained_locally\": True,\n401-    \"raw_evidence_sha256\": raw_sha,\n402-    \"sanitized_output_sha256\": sanitized_sha,\n403-    \"output_truncated_in_json\": output_truncated,\n404-    \"full_sanitized_output_url\": (\n405-        \"https://git.gram1.ru/.well-known/\"\n406-        \"homelab-runtime/latest.txt\"\n407-    ),\n408-    \"output\": output_preview,\n409-}\n410-\n411-Path(json_path).write_text(\n412-    json.dumps(\n413-        document,\n414-        ensure_ascii=False,\n415-        indent=2,\n416-    )\n417-    + \"\\n\",\n418-    encoding=\"utf-8\",\n419-)\n420-PY\n421-\n422-{\n423-    echo 'CHAT_OUTPUT_BEGIN'\n424-    echo \"COMMAND_ID=$COMMAND_ID\"\n425-    echo \"STATUS=$STATUS\"\n426-    echo \"RC=$RC\"\n427-    echo \"HOST=$HOST_SHORT\"\n428-    echo \"MODE=$MODE\"\n429-    echo \"COMPONENT=$COMPONENT\"\n430-    echo 'REFERENCE_REGISTER_CHECK=OK'\n431-    echo \"REFERENCE_SHA256=$REFERENCE_SHA256\"\n432-    echo 'ERROR_REGISTER_CHECK=OK'\n433-    echo \"ERROR_REGISTER_SHA256=$ERROR_REGISTER_SHA256\"\n434-    echo \"COMMAND_SHA256=$COMMAND_SHA256\"\n435-    echo \"DUPLICATE_FAILED_COMMAND_BLOCKED=$REPEAT_BLOCKED\"\n436:    echo \"EXECUTION_STARTED=$RUN_STARTED\"\n437:    echo \"CHANGES_MADE=$CHANGES_MADE\"\n438-    echo 'SANITIZED=yes'\n439-    echo 'SECRETS_INCLUDED=no'\n440-    echo 'PRIVATE_ADDRESSES_INCLUDED=no'\n441-    echo \"RAW_EVIDENCE_SHA256=$RAW_SHA256\"\n442-    echo \"SANITIZED_OUTPUT_SHA256=$SANITIZED_SHA256\"\n443-    echo 'OUTPUT_BEGIN'\n444-    cat \"$SANITIZED_FILE\"\n445-    echo\n446-    echo 'OUTPUT_END'\n447-    echo 'CHAT_OUTPUT_END'\n448-} >\"$TXT_FILE\"\n449-\n450-chmod 0600 \\\n451-    \"$RAW_FILE\" \\\n452-    \"$SANITIZED_FILE\" \\\n453-    \"$JSON_FILE\" \\\n454-    \"$TXT_FILE\"\n455-\n456-TARGET=debian@[PRIVATE_IP]\n457-REMOTE_PREFIX=\"/tmp/homelab-runtime-${COMMAND_ID}-$$\"\n458-\n459-SSH_OPTS=(\n460-    -o BatchMode=yes\n461-    -o ConnectTimeout=10\n462-    -o ConnectionAttempts=1\n463-    -o StrictHostKeyChecking=yes\n464-    -o UserKnownHostsFile=[SENSITIVE_PATH]\n465-)\n466-\n467-scp \\\n468-    -q \\\n469-    \"${SSH_OPTS[@]}\" \\\n470-    \"$JSON_FILE\" \\\n471-    \"${TARGET}:${REMOTE_PREFIX}.json\"\n472-\n473-scp \\\n474-    -q \\\n475-    \"${SSH_OPTS[@]}\" \\\n476-    \"$TXT_FILE\" \\\n477-    \"${TARGET}:${REMOTE_PREFIX}.txt\"\n=== MODE_REFERENCES ===\n11:  read-only\n12:  verify\n13:  change\n14:  transport-test\n51:    read-only|verify|change|transport-test)\n150:    change)\n357:    changes_made,\n396:    \"changes_made\": changes_made == \"true\",\nCLUSTER_REFERENCE_MODE_SEMANTICS=COMPLETE\n"
}
