diff --git a/fixtures/hardware/README.md b/fixtures/hardware/README.md new file mode 100644 index 00000000..930c8bf2 --- /dev/null +++ b/fixtures/hardware/README.md @@ -0,0 +1,27 @@ +# Hardware Fixtures + +Last updated: 2026-05-13 + +This folder contains local-alpha hardware projections that can be consumed by dashboard, workbench, or control-plane code without depending on live FlowRouter hardware. + +## Fixtures + +- `flowrouter_local_alpha_seed42.json`: deterministic FlowRouter-to-FlowChain operator signal projection generated from `hardware/fixtures/flowrouter_sample_seed42.json`. + +## Shape + +The fixture is a `flowmemory.hardware_operator_signals.local_alpha.v0` document. It includes: + +- `signalEnvelopes`: one envelope for heartbeat, receipt relay, verifier digest relay, offline alert/challenge input, and NFC memory cartridge metadata. +- `hardwareSignals`: direct workbench/control-plane signal records for the same five envelopes. +- `hardwareNodes`, `workReceipts`, `verifierReports`, `artifactCommitments`, `memoryCells`, `challenges`, `finalityReceipts`, and `alerts`: control-plane-friendly local fixture collections. +- `workbenchRecords`: ready-to-render records grouped by workbench section keys, including `hardwareSignals`. +- `boundary`: explicit local-only, advisory, optional-hardware limitations. + +## Validation + +```powershell +python hardware/simulator/flowrouter_sim.py --validate-operator-file fixtures/hardware/flowrouter_local_alpha_seed42.json +``` + +These fixtures are local-only and advisory. They do not prove hardware trustlessness, production field deployment, or receipt/verifier finality. diff --git a/fixtures/hardware/flowrouter_local_alpha_seed42.json b/fixtures/hardware/flowrouter_local_alpha_seed42.json new file mode 100644 index 00000000..6ac960cd --- /dev/null +++ b/fixtures/hardware/flowrouter_local_alpha_seed42.json @@ -0,0 +1,1411 @@ +{ + "alerts": [ + { + "id": "hw-alert-f187cbc304cb", + "incidentId": "hw-alert-f187cbc304cb", + "linkedObjectIds": [ + "fr-e1e7878a2aa8", + "receipt:hardware:1e92f586a767", + "challenge:hardware:5f54ef32073d" + ], + "localOnly": true, + "openedAt": "2026-05-13T17:01:30Z", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "recommendedAction": "check-upstream-and-power", + "severity": "warning", + "sourcePacketType": "emergency_offline_signal", + "status": "unresolved", + "summary": "Upstream unavailable; LAN dashboard and local cache still reachable.", + "title": "UPSTREAM_LOSS" + } + ], + "artifactCommitments": [ + { + "artifactId": "artifact:hardware:dffc8c3e46ff", + "availabilityStatus": "metadata-only", + "cartridgeId": "cart-0cfd3cfcb210", + "commitment": "0x7bb78aa4de0935712809a8e46e13b832ba5a761416731e51aeb02d753bbca5b0", + "containsSecrets": false, + "expiresAt": "2026-06-13T17:00:00Z", + "label": "field-test-cache-alpha", + "localOnly": true, + "rootfieldId": "rootfield:hardware:flowrouter-local-alpha", + "sourcePacketType": "nfc_memory_cartridge_metadata", + "status": "observed", + "trustLevel": "untrusted-pointer", + "uriHint": "flowmemory://cache/4549dba629bc" + } + ], + "boundary": { + "advisory": true, + "claimLimitations": [ + "Hardware-originated references are hints until reconciled by normal indexer, receipt, and verifier paths.", + "LoRa and Meshtastic packets carry compact control signals, not artifacts, model data, media, or raw memory.", + "NFC cartridge metadata is an untrusted pointer until checked against expected commitments.", + "Emergency offline signals are operator alerts or challenge inputs only; they do not execute remote actions." + ], + "hardwareRequiredForPrivateTestnet": false, + "localOnly": true, + "normalNetworkReconciliationRequired": true + }, + "chainId": "flowmemory-local-alpha", + "challenges": [ + { + "challengeId": "challenge:hardware:5f54ef32073d", + "doesNotExecuteRemoteAction": true, + "localOnly": true, + "openedAt": "2026-05-13T17:01:30Z", + "openedBy": "hardware-node:fr-e1e7878a2aa8", + "reason": "offline-alert-candidate", + "receiptId": "receipt:hardware:1e92f586a767", + "recommendedAction": "check-upstream-and-power", + "reportId": "report:hardware:bd367723d169", + "sourcePacketType": "emergency_offline_signal", + "status": "pending", + "summary": "Upstream unavailable; LAN dashboard and local cache still reachable.", + "targetId": "receipt:hardware:1e92f586a767", + "ttlSeconds": 900 + } + ], + "compatibility": { + "controlPlaneStateKeys": [ + "hardwareSignals", + "hardwareNodes", + "workReceipts", + "verifierReports", + "artifactCommitments", + "memoryCells", + "challenges", + "finalityReceipts", + "alerts" + ], + "jsonRpcBoundary": "Read-only fixture data; no submit, wallet, live indexing, or production settlement method is implied.", + "workbenchSectionKeys": [ + "receipts", + "verifierReports", + "artifacts", + "memoryCells", + "challenges", + "hardwareSignals", + "provenance" + ] + }, + "environment": "local-devnet-fixture", + "finalityReceipts": [ + { + "finalityReceiptId": "finality:hardware:e28633303a6b", + "finalityStatus": "local-pending", + "localOnly": true, + "objectId": "receipt:hardware:1e92f586a767", + "receiptId": "receipt:hardware:1e92f586a767", + "rootfieldId": "rootfield:hardware:flowrouter-local-alpha", + "settlement": "local-fixture", + "sourcePacketType": "compact_receipt_relay", + "status": "pending" + } + ], + "generatedAt": "2026-05-13T17:01:40Z", + "hardwareNodes": [ + { + "cacheState": "healthy", + "callsign": "FlowRouter local-alpha fixture", + "firmware": "flowrouter.poc.v0", + "flowcoreState": "online", + "id": "fr-e1e7878a2aa8", + "lastHeartbeatAt": "2026-05-13T17:00:10Z", + "linkedWorkLaneId": "CHECKPOINT_STORAGE", + "localOnly": true, + "locationHint": "local lab fixture", + "nodeId": "fr-e1e7878a2aa8", + "powerState": "mains", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "role": "router", + "sidecarState": "ready", + "sourcePacketType": "heartbeat", + "status": "verified", + "transport": "local-wifi+meshtastic-sidecar-sim", + "warnings": [] + } + ], + "hardwareSignals": [ + { + "envelopeId": "hw-env-69eab6533abb", + "id": "hw-sig-cd45a2ab8b1d", + "linkedObjectIds": [ + "fr-e1e7878a2aa8" + ], + "localOnly": true, + "loraEligible": false, + "nodeId": "fr-e1e7878a2aa8", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "rawEnvelope": { + "envelopeId": "hw-env-69eab6533abb", + "localOnly": true, + "loraEligible": false, + "objectRefs": [ + { + "collection": "hardwareNodes", + "objectId": "fr-e1e7878a2aa8" + } + ], + "observedAt": "2026-05-13T17:00:10Z", + "payloadBytesEstimate": 0, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-cd45a2ab8b1d", + "signalType": "heartbeat", + "sourcePacketId": "heartbeat:1042", + "sourcePacketType": "heartbeat", + "status": "observed" + }, + "receivedAt": "2026-05-13T17:00:10Z", + "signalId": "hw-sig-cd45a2ab8b1d", + "signalType": "heartbeat", + "sourcePacketType": "heartbeat", + "status": "observed", + "summary": "FlowRouter heartbeat and coarse node state.", + "transport": "local-simulator" + }, + { + "envelopeId": "hw-env-88c288e8803c", + "id": "hw-sig-5dd1dbdec22d", + "linkedObjectIds": [ + "receipt:hardware:1e92f586a767" + ], + "localOnly": true, + "loraEligible": true, + "nodeId": "fr-e1e7878a2aa8", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "rawEnvelope": { + "envelopeId": "hw-env-88c288e8803c", + "localOnly": true, + "loraEligible": true, + "objectRefs": [ + { + "collection": "workReceipts", + "objectId": "receipt:hardware:1e92f586a767" + } + ], + "observedAt": "2026-05-13T17:00:40Z", + "payloadBytesEstimate": 96, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-5dd1dbdec22d", + "signalType": "receipt_relay", + "sourcePacketId": "compact_receipt_relay:1045", + "sourcePacketType": "compact_receipt_relay", + "status": "unresolved" + }, + "receivedAt": "2026-05-13T17:00:40Z", + "signalId": "hw-sig-5dd1dbdec22d", + "signalType": "receipt_relay", + "sourcePacketType": "compact_receipt_relay", + "status": "unresolved", + "summary": "Compact WorkReceipt digest relay awaiting normal reconciliation.", + "transport": "meshtastic-control-sim" + }, + { + "envelopeId": "hw-env-3c18d09ea961", + "id": "hw-sig-d7087f4f3257", + "linkedObjectIds": [ + "report:hardware:bd367723d169" + ], + "localOnly": true, + "loraEligible": true, + "nodeId": "fr-e1e7878a2aa8", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "rawEnvelope": { + "envelopeId": "hw-env-3c18d09ea961", + "localOnly": true, + "loraEligible": true, + "objectRefs": [ + { + "collection": "verifierReports", + "objectId": "report:hardware:bd367723d169" + } + ], + "observedAt": "2026-05-13T17:00:30Z", + "payloadBytesEstimate": 128, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-d7087f4f3257", + "signalType": "verifier_digest_relay", + "sourcePacketId": "verifier_report_digest_relay:1044", + "sourcePacketType": "verifier_report_digest_relay", + "status": "unresolved" + }, + "receivedAt": "2026-05-13T17:00:30Z", + "signalId": "hw-sig-d7087f4f3257", + "signalType": "verifier_digest_relay", + "sourcePacketType": "verifier_report_digest_relay", + "status": "unresolved", + "summary": "Compact VerifierReport digest relay awaiting the full report.", + "transport": "meshtastic-control-sim" + }, + { + "envelopeId": "hw-env-2d165bbf5812", + "id": "hw-sig-2474b9971f93", + "linkedObjectIds": [ + "hw-alert-f187cbc304cb", + "challenge:hardware:5f54ef32073d" + ], + "localOnly": true, + "loraEligible": false, + "nodeId": "fr-e1e7878a2aa8", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "rawEnvelope": { + "envelopeId": "hw-env-2d165bbf5812", + "localOnly": true, + "loraEligible": false, + "objectRefs": [ + { + "collection": "alerts", + "objectId": "hw-alert-f187cbc304cb" + }, + { + "collection": "challenges", + "objectId": "challenge:hardware:5f54ef32073d" + } + ], + "observedAt": "2026-05-13T17:01:30Z", + "payloadBytesEstimate": 0, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-2474b9971f93", + "signalType": "offline_alert_challenge_input", + "sourcePacketId": "emergency_offline_signal:1049", + "sourcePacketType": "emergency_offline_signal", + "status": "pending" + }, + "receivedAt": "2026-05-13T17:01:30Z", + "signalId": "hw-sig-2474b9971f93", + "signalType": "offline_alert_challenge_input", + "sourcePacketType": "emergency_offline_signal", + "status": "pending", + "summary": "Offline alert that can seed a local challenge candidate.", + "transport": "local-simulator" + }, + { + "envelopeId": "hw-env-3787edd45bfa", + "id": "hw-sig-97f6fef1f868", + "linkedObjectIds": [ + "artifact:hardware:dffc8c3e46ff", + "memory:hardware:9f8165ee1a5a" + ], + "localOnly": true, + "loraEligible": false, + "nodeId": "fr-e1e7878a2aa8", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "rawEnvelope": { + "envelopeId": "hw-env-3787edd45bfa", + "localOnly": true, + "loraEligible": false, + "objectRefs": [ + { + "collection": "artifactCommitments", + "objectId": "artifact:hardware:dffc8c3e46ff" + }, + { + "collection": "memoryCells", + "objectId": "memory:hardware:9f8165ee1a5a" + } + ], + "observedAt": "2026-05-13T17:01:20Z", + "payloadBytesEstimate": 0, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-97f6fef1f868", + "signalType": "nfc_memory_cartridge_metadata", + "sourcePacketId": "nfc_memory_cartridge_metadata:42", + "sourcePacketType": "nfc_memory_cartridge_metadata", + "status": "observed" + }, + "receivedAt": "2026-05-13T17:01:20Z", + "signalId": "hw-sig-97f6fef1f868", + "signalType": "nfc_memory_cartridge_metadata", + "sourcePacketType": "nfc_memory_cartridge_metadata", + "status": "observed", + "summary": "NFC metadata pointer projected into artifact and memory references.", + "transport": "local-simulator" + } + ], + "memoryCells": [ + { + "artifactId": "artifact:hardware:dffc8c3e46ff", + "currentRoot": "0x7bb78aa4de0935712809a8e46e13b832ba5a761416731e51aeb02d753bbca5b0", + "latestRoot": "0x7bb78aa4de0935712809a8e46e13b832ba5a761416731e51aeb02d753bbca5b0", + "localOnly": true, + "memoryCellId": "memory:hardware:9f8165ee1a5a", + "receiptId": "receipt:hardware:1e92f586a767", + "resolutionState": "untrusted-metadata-only", + "rootfieldId": "rootfield:hardware:flowrouter-local-alpha", + "sourcePacketType": "nfc_memory_cartridge_metadata", + "status": "observed", + "summary": "NFC cartridge metadata pointer projected into a local memory cell candidate.", + "updatedAt": "2026-05-13T17:01:20Z" + } + ], + "packetMappings": [ + { + "flowchainSignal": "hardware_node_status", + "localAlphaRole": "shows FlowRouter reachability and coarse device state", + "objectCollection": "hardwareNodes", + "objectRef": "fr-e1e7878a2aa8", + "sourcePacketType": "heartbeat", + "trustBoundary": "local advisory status, not hardware attestation" + }, + { + "flowchainSignal": "work_receipt_reference", + "localAlphaRole": "points the workbench at a WorkReceipt candidate", + "objectCollection": "workReceipts", + "objectRef": "receipt:hardware:1e92f586a767", + "sourcePacketType": "compact_receipt_relay", + "trustBoundary": "digest and locator hints require normal receipt reconciliation" + }, + { + "flowchainSignal": "verifier_report_reference", + "localAlphaRole": "points the workbench at a VerifierReport candidate", + "objectCollection": "verifierReports", + "objectRef": "report:hardware:bd367723d169", + "sourcePacketType": "verifier_report_digest_relay", + "trustBoundary": "digest relay is not the full verifier report" + }, + { + "flowchainSignal": "alert_challenge_input", + "localAlphaRole": "creates an operator alert and optional challenge input", + "objectCollection": "challenges", + "objectRef": "challenge:hardware:5f54ef32073d", + "sourcePacketType": "emergency_offline_signal", + "trustBoundary": "local operator attention only; no public emergency-service claim" + }, + { + "flowchainSignal": "artifact_memory_reference", + "localAlphaRole": "connects cartridge metadata to an artifact or memory reference", + "objectCollection": "artifactCommitments", + "objectRef": "artifact:hardware:dffc8c3e46ff", + "sourcePacketType": "nfc_memory_cartridge_metadata", + "trustBoundary": "untrusted metadata pointer, not a secret store or proof" + } + ], + "schema": "flowmemory.hardware_operator_signals.local_alpha.v0", + "signalEnvelopes": [ + { + "envelopeId": "hw-env-69eab6533abb", + "localOnly": true, + "loraEligible": false, + "objectRefs": [ + { + "collection": "hardwareNodes", + "objectId": "fr-e1e7878a2aa8" + } + ], + "observedAt": "2026-05-13T17:00:10Z", + "payloadBytesEstimate": 0, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-cd45a2ab8b1d", + "signalType": "heartbeat", + "sourcePacketId": "heartbeat:1042", + "sourcePacketType": "heartbeat", + "status": "observed" + }, + { + "envelopeId": "hw-env-88c288e8803c", + "localOnly": true, + "loraEligible": true, + "objectRefs": [ + { + "collection": "workReceipts", + "objectId": "receipt:hardware:1e92f586a767" + } + ], + "observedAt": "2026-05-13T17:00:40Z", + "payloadBytesEstimate": 96, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-5dd1dbdec22d", + "signalType": "receipt_relay", + "sourcePacketId": "compact_receipt_relay:1045", + "sourcePacketType": "compact_receipt_relay", + "status": "unresolved" + }, + { + "envelopeId": "hw-env-3c18d09ea961", + "localOnly": true, + "loraEligible": true, + "objectRefs": [ + { + "collection": "verifierReports", + "objectId": "report:hardware:bd367723d169" + } + ], + "observedAt": "2026-05-13T17:00:30Z", + "payloadBytesEstimate": 128, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-d7087f4f3257", + "signalType": "verifier_digest_relay", + "sourcePacketId": "verifier_report_digest_relay:1044", + "sourcePacketType": "verifier_report_digest_relay", + "status": "unresolved" + }, + { + "envelopeId": "hw-env-2d165bbf5812", + "localOnly": true, + "loraEligible": false, + "objectRefs": [ + { + "collection": "alerts", + "objectId": "hw-alert-f187cbc304cb" + }, + { + "collection": "challenges", + "objectId": "challenge:hardware:5f54ef32073d" + } + ], + "observedAt": "2026-05-13T17:01:30Z", + "payloadBytesEstimate": 0, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-2474b9971f93", + "signalType": "offline_alert_challenge_input", + "sourcePacketId": "emergency_offline_signal:1049", + "sourcePacketType": "emergency_offline_signal", + "status": "pending" + }, + { + "envelopeId": "hw-env-3787edd45bfa", + "localOnly": true, + "loraEligible": false, + "objectRefs": [ + { + "collection": "artifactCommitments", + "objectId": "artifact:hardware:dffc8c3e46ff" + }, + { + "collection": "memoryCells", + "objectId": "memory:hardware:9f8165ee1a5a" + } + ], + "observedAt": "2026-05-13T17:01:20Z", + "payloadBytesEstimate": 0, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-97f6fef1f868", + "signalType": "nfc_memory_cartridge_metadata", + "sourcePacketId": "nfc_memory_cartridge_metadata:42", + "sourcePacketType": "nfc_memory_cartridge_metadata", + "status": "observed" + } + ], + "source": "fixture", + "sourcePaths": { + "mappingDoc": "hardware/flowrouter/FLOWCHAIN_LOCAL_ALPHA_SIGNALS.md", + "operatorFixture": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "operatorSchema": "hardware/simulator/schemas/flowchain_operator_signals.schema.json", + "packetFixture": "hardware/fixtures/flowrouter_sample_seed42.json" + }, + "verifierReports": [ + { + "localOnly": true, + "loraEligible": true, + "payloadBytesEstimate": 128, + "reasonCodes": [ + "hardware_digest_relay_only" + ], + "receiptId": "receipt:hardware:1e92f586a767", + "relayReportId": "vr-14d051ae590e", + "reportDigest": "0xb988417bf67c48bab7208ee1fe0531d66fbcb45a1be1b853b70423239c4c8870", + "reportId": "report:hardware:bd367723d169", + "resolutionState": "needs-full-report", + "rootfieldId": "rootfield:hardware:flowrouter-local-alpha", + "sourcePacketType": "verifier_report_digest_relay", + "status": "unresolved", + "subjectDigest": "0x1d5a28ff5af6335dccc9412d01d434aa58bf0870011f781bd614a5266740da3b", + "verifierId": "hardware-relay:fr-e1e7878a2aa8" + } + ], + "workReceipts": [ + { + "artifactCommitment": "0x7bb78aa4de0935712809a8e46e13b832ba5a761416731e51aeb02d753bbca5b0", + "chain": "base-sepolia-sim", + "inputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "localOnly": true, + "locatorHint": { + "blockHint": 1200012, + "logIndexHint": 3, + "txHashPrefix": "0xea723a0a09aa25b7" + }, + "loraEligible": true, + "outputRoot": "0xfbe8a762b036d20581160b7e58a3adccf61f53c653713c439f85cc7bee5246fa", + "payloadBytesEstimate": 96, + "receiptDigest": "0xfbe8a762b036d20581160b7e58a3adccf61f53c653713c439f85cc7bee5246fa", + "receiptId": "receipt:hardware:1e92f586a767", + "resolutionState": "needs-normal-network-reconciliation", + "rootfieldId": "rootfield:hardware:flowrouter-local-alpha", + "ruleSet": "flowmemory.hardware.operator_signal.local_alpha.v0", + "sourcePacketType": "compact_receipt_relay", + "status": "unresolved", + "workerId": "hardware-node:fr-e1e7878a2aa8" + } + ], + "workbenchRecords": { + "artifacts": [ + { + "facts": [ + { + "label": "cartridge", + "value": "cart-0cfd3cfcb210" + }, + { + "label": "pointer", + "value": "flowmemory://cache/4549dba629bc" + }, + { + "label": "commitment", + "value": "0x7bb78aa4de0935712809a8e46e13b832ba5a761416731e51aeb02d753bbca5b0" + }, + { + "label": "expires", + "value": "2026-06-13T17:00:00Z" + } + ], + "id": "artifact:hardware:dffc8c3e46ff", + "kind": "NFC cartridge artifact reference", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "artifactId": "artifact:hardware:dffc8c3e46ff", + "availabilityStatus": "metadata-only", + "cartridgeId": "cart-0cfd3cfcb210", + "commitment": "0x7bb78aa4de0935712809a8e46e13b832ba5a761416731e51aeb02d753bbca5b0", + "containsSecrets": false, + "expiresAt": "2026-06-13T17:00:00Z", + "label": "field-test-cache-alpha", + "localOnly": true, + "rootfieldId": "rootfield:hardware:flowrouter-local-alpha", + "sourcePacketType": "nfc_memory_cartridge_metadata", + "status": "observed", + "trustLevel": "untrusted-pointer", + "uriHint": "flowmemory://cache/4549dba629bc" + }, + "status": "observed", + "summary": "NFC cartridge metadata pointer; content is untrusted until commitment checks pass.", + "title": "field-test-cache-alpha" + } + ], + "challenges": [ + { + "facts": [ + { + "label": "target", + "value": "receipt:hardware:1e92f586a767" + }, + { + "label": "report", + "value": "report:hardware:bd367723d169" + }, + { + "label": "ttl seconds", + "value": "900" + }, + { + "label": "action", + "value": "check-upstream-and-power" + } + ], + "id": "challenge:hardware:5f54ef32073d", + "kind": "Offline alert challenge candidate", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "challengeId": "challenge:hardware:5f54ef32073d", + "doesNotExecuteRemoteAction": true, + "localOnly": true, + "openedAt": "2026-05-13T17:01:30Z", + "openedBy": "hardware-node:fr-e1e7878a2aa8", + "reason": "offline-alert-candidate", + "receiptId": "receipt:hardware:1e92f586a767", + "recommendedAction": "check-upstream-and-power", + "reportId": "report:hardware:bd367723d169", + "sourcePacketType": "emergency_offline_signal", + "status": "pending", + "summary": "Upstream unavailable; LAN dashboard and local cache still reachable.", + "targetId": "receipt:hardware:1e92f586a767", + "ttlSeconds": 900 + }, + "status": "pending", + "summary": "Upstream unavailable; LAN dashboard and local cache still reachable.", + "title": "UPSTREAM_LOSS" + } + ], + "hardwareSignals": [ + { + "facts": [ + { + "label": "node", + "value": "fr-e1e7878a2aa8" + }, + { + "label": "transport", + "value": "local-simulator" + }, + { + "label": "source packet", + "value": "heartbeat" + }, + { + "label": "linked objects", + "value": "fr-e1e7878a2aa8" + } + ], + "id": "hw-sig-cd45a2ab8b1d", + "kind": "Hardware operator signal", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "envelopeId": "hw-env-69eab6533abb", + "id": "hw-sig-cd45a2ab8b1d", + "linkedObjectIds": [ + "fr-e1e7878a2aa8" + ], + "localOnly": true, + "loraEligible": false, + "nodeId": "fr-e1e7878a2aa8", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "rawEnvelope": { + "envelopeId": "hw-env-69eab6533abb", + "localOnly": true, + "loraEligible": false, + "objectRefs": [ + { + "collection": "hardwareNodes", + "objectId": "fr-e1e7878a2aa8" + } + ], + "observedAt": "2026-05-13T17:00:10Z", + "payloadBytesEstimate": 0, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-cd45a2ab8b1d", + "signalType": "heartbeat", + "sourcePacketId": "heartbeat:1042", + "sourcePacketType": "heartbeat", + "status": "observed" + }, + "receivedAt": "2026-05-13T17:00:10Z", + "signalId": "hw-sig-cd45a2ab8b1d", + "signalType": "heartbeat", + "sourcePacketType": "heartbeat", + "status": "observed", + "summary": "FlowRouter heartbeat and coarse node state.", + "transport": "local-simulator" + }, + "status": "observed", + "summary": "FlowRouter heartbeat and coarse node state.", + "title": "heartbeat" + }, + { + "facts": [ + { + "label": "node", + "value": "fr-e1e7878a2aa8" + }, + { + "label": "transport", + "value": "meshtastic-control-sim" + }, + { + "label": "source packet", + "value": "compact_receipt_relay" + }, + { + "label": "linked objects", + "value": "receipt:hardware:1e92f586a767" + } + ], + "id": "hw-sig-5dd1dbdec22d", + "kind": "Hardware operator signal", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "envelopeId": "hw-env-88c288e8803c", + "id": "hw-sig-5dd1dbdec22d", + "linkedObjectIds": [ + "receipt:hardware:1e92f586a767" + ], + "localOnly": true, + "loraEligible": true, + "nodeId": "fr-e1e7878a2aa8", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "rawEnvelope": { + "envelopeId": "hw-env-88c288e8803c", + "localOnly": true, + "loraEligible": true, + "objectRefs": [ + { + "collection": "workReceipts", + "objectId": "receipt:hardware:1e92f586a767" + } + ], + "observedAt": "2026-05-13T17:00:40Z", + "payloadBytesEstimate": 96, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-5dd1dbdec22d", + "signalType": "receipt_relay", + "sourcePacketId": "compact_receipt_relay:1045", + "sourcePacketType": "compact_receipt_relay", + "status": "unresolved" + }, + "receivedAt": "2026-05-13T17:00:40Z", + "signalId": "hw-sig-5dd1dbdec22d", + "signalType": "receipt_relay", + "sourcePacketType": "compact_receipt_relay", + "status": "unresolved", + "summary": "Compact WorkReceipt digest relay awaiting normal reconciliation.", + "transport": "meshtastic-control-sim" + }, + "status": "unresolved", + "summary": "Compact WorkReceipt digest relay awaiting normal reconciliation.", + "title": "receipt_relay" + }, + { + "facts": [ + { + "label": "node", + "value": "fr-e1e7878a2aa8" + }, + { + "label": "transport", + "value": "meshtastic-control-sim" + }, + { + "label": "source packet", + "value": "verifier_report_digest_relay" + }, + { + "label": "linked objects", + "value": "report:hardware:bd367723d169" + } + ], + "id": "hw-sig-d7087f4f3257", + "kind": "Hardware operator signal", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "envelopeId": "hw-env-3c18d09ea961", + "id": "hw-sig-d7087f4f3257", + "linkedObjectIds": [ + "report:hardware:bd367723d169" + ], + "localOnly": true, + "loraEligible": true, + "nodeId": "fr-e1e7878a2aa8", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "rawEnvelope": { + "envelopeId": "hw-env-3c18d09ea961", + "localOnly": true, + "loraEligible": true, + "objectRefs": [ + { + "collection": "verifierReports", + "objectId": "report:hardware:bd367723d169" + } + ], + "observedAt": "2026-05-13T17:00:30Z", + "payloadBytesEstimate": 128, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-d7087f4f3257", + "signalType": "verifier_digest_relay", + "sourcePacketId": "verifier_report_digest_relay:1044", + "sourcePacketType": "verifier_report_digest_relay", + "status": "unresolved" + }, + "receivedAt": "2026-05-13T17:00:30Z", + "signalId": "hw-sig-d7087f4f3257", + "signalType": "verifier_digest_relay", + "sourcePacketType": "verifier_report_digest_relay", + "status": "unresolved", + "summary": "Compact VerifierReport digest relay awaiting the full report.", + "transport": "meshtastic-control-sim" + }, + "status": "unresolved", + "summary": "Compact VerifierReport digest relay awaiting the full report.", + "title": "verifier_digest_relay" + }, + { + "facts": [ + { + "label": "node", + "value": "fr-e1e7878a2aa8" + }, + { + "label": "transport", + "value": "local-simulator" + }, + { + "label": "source packet", + "value": "emergency_offline_signal" + }, + { + "label": "linked objects", + "value": "hw-alert-f187cbc304cb, challenge:hardware:5f54ef32073d" + } + ], + "id": "hw-sig-2474b9971f93", + "kind": "Hardware operator signal", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "envelopeId": "hw-env-2d165bbf5812", + "id": "hw-sig-2474b9971f93", + "linkedObjectIds": [ + "hw-alert-f187cbc304cb", + "challenge:hardware:5f54ef32073d" + ], + "localOnly": true, + "loraEligible": false, + "nodeId": "fr-e1e7878a2aa8", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "rawEnvelope": { + "envelopeId": "hw-env-2d165bbf5812", + "localOnly": true, + "loraEligible": false, + "objectRefs": [ + { + "collection": "alerts", + "objectId": "hw-alert-f187cbc304cb" + }, + { + "collection": "challenges", + "objectId": "challenge:hardware:5f54ef32073d" + } + ], + "observedAt": "2026-05-13T17:01:30Z", + "payloadBytesEstimate": 0, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-2474b9971f93", + "signalType": "offline_alert_challenge_input", + "sourcePacketId": "emergency_offline_signal:1049", + "sourcePacketType": "emergency_offline_signal", + "status": "pending" + }, + "receivedAt": "2026-05-13T17:01:30Z", + "signalId": "hw-sig-2474b9971f93", + "signalType": "offline_alert_challenge_input", + "sourcePacketType": "emergency_offline_signal", + "status": "pending", + "summary": "Offline alert that can seed a local challenge candidate.", + "transport": "local-simulator" + }, + "status": "pending", + "summary": "Offline alert that can seed a local challenge candidate.", + "title": "offline_alert_challenge_input" + }, + { + "facts": [ + { + "label": "node", + "value": "fr-e1e7878a2aa8" + }, + { + "label": "transport", + "value": "local-simulator" + }, + { + "label": "source packet", + "value": "nfc_memory_cartridge_metadata" + }, + { + "label": "linked objects", + "value": "artifact:hardware:dffc8c3e46ff, memory:hardware:9f8165ee1a5a" + } + ], + "id": "hw-sig-97f6fef1f868", + "kind": "Hardware operator signal", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "envelopeId": "hw-env-3787edd45bfa", + "id": "hw-sig-97f6fef1f868", + "linkedObjectIds": [ + "artifact:hardware:dffc8c3e46ff", + "memory:hardware:9f8165ee1a5a" + ], + "localOnly": true, + "loraEligible": false, + "nodeId": "fr-e1e7878a2aa8", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "rawEnvelope": { + "envelopeId": "hw-env-3787edd45bfa", + "localOnly": true, + "loraEligible": false, + "objectRefs": [ + { + "collection": "artifactCommitments", + "objectId": "artifact:hardware:dffc8c3e46ff" + }, + { + "collection": "memoryCells", + "objectId": "memory:hardware:9f8165ee1a5a" + } + ], + "observedAt": "2026-05-13T17:01:20Z", + "payloadBytesEstimate": 0, + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "signalId": "hw-sig-97f6fef1f868", + "signalType": "nfc_memory_cartridge_metadata", + "sourcePacketId": "nfc_memory_cartridge_metadata:42", + "sourcePacketType": "nfc_memory_cartridge_metadata", + "status": "observed" + }, + "receivedAt": "2026-05-13T17:01:20Z", + "signalId": "hw-sig-97f6fef1f868", + "signalType": "nfc_memory_cartridge_metadata", + "sourcePacketType": "nfc_memory_cartridge_metadata", + "status": "observed", + "summary": "NFC metadata pointer projected into artifact and memory references.", + "transport": "local-simulator" + }, + "status": "observed", + "summary": "NFC metadata pointer projected into artifact and memory references.", + "title": "nfc_memory_cartridge_metadata" + } + ], + "memoryCells": [ + { + "facts": [ + { + "label": "rootfield", + "value": "rootfield:hardware:flowrouter-local-alpha" + }, + { + "label": "latest root", + "value": "0x7bb78aa4de0935712809a8e46e13b832ba5a761416731e51aeb02d753bbca5b0" + }, + { + "label": "receipt", + "value": "receipt:hardware:1e92f586a767" + }, + { + "label": "artifact", + "value": "artifact:hardware:dffc8c3e46ff" + } + ], + "id": "memory:hardware:9f8165ee1a5a", + "kind": "Hardware memory cell candidate", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "artifactId": "artifact:hardware:dffc8c3e46ff", + "currentRoot": "0x7bb78aa4de0935712809a8e46e13b832ba5a761416731e51aeb02d753bbca5b0", + "latestRoot": "0x7bb78aa4de0935712809a8e46e13b832ba5a761416731e51aeb02d753bbca5b0", + "localOnly": true, + "memoryCellId": "memory:hardware:9f8165ee1a5a", + "receiptId": "receipt:hardware:1e92f586a767", + "resolutionState": "untrusted-metadata-only", + "rootfieldId": "rootfield:hardware:flowrouter-local-alpha", + "sourcePacketType": "nfc_memory_cartridge_metadata", + "status": "observed", + "summary": "NFC cartridge metadata pointer projected into a local memory cell candidate.", + "updatedAt": "2026-05-13T17:01:20Z" + }, + "status": "observed", + "summary": "Projected from NFC cartridge metadata for local operator inspection.", + "title": "memory:hardware:9f8165ee1a5a" + } + ], + "provenance": [ + { + "facts": [ + { + "label": "packet fixture", + "value": "hardware/fixtures/flowrouter_sample_seed42.json" + }, + { + "label": "schema", + "value": "flowmemory.hardware_operator_signals.local_alpha.v0" + }, + { + "label": "seed", + "value": "42" + }, + { + "label": "hardware required", + "value": "false" + } + ], + "id": "hardware-operator-signal-fixture", + "kind": "Hardware operator signal fixture", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "sourcePaths": { + "operatorFixture": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "packetFixture": "hardware/fixtures/flowrouter_sample_seed42.json" + } + }, + "status": "verified", + "summary": "Deterministic optional hardware signal projection for control-plane/workbench import.", + "title": "fixtures/hardware/flowrouter_local_alpha_seed42.json" + } + ], + "receipts": [ + { + "facts": [ + { + "label": "rootfield", + "value": "rootfield:hardware:flowrouter-local-alpha" + }, + { + "label": "receipt digest", + "value": "0xfbe8a762b036d20581160b7e58a3adccf61f53c653713c439f85cc7bee5246fa" + }, + { + "label": "block hint", + "value": "1200012" + }, + { + "label": "tx prefix", + "value": "0xea723a0a09aa25b7" + } + ], + "id": "receipt:hardware:1e92f586a767", + "kind": "Hardware WorkReceipt relay", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "artifactCommitment": "0x7bb78aa4de0935712809a8e46e13b832ba5a761416731e51aeb02d753bbca5b0", + "chain": "base-sepolia-sim", + "inputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "localOnly": true, + "locatorHint": { + "blockHint": 1200012, + "logIndexHint": 3, + "txHashPrefix": "0xea723a0a09aa25b7" + }, + "loraEligible": true, + "outputRoot": "0xfbe8a762b036d20581160b7e58a3adccf61f53c653713c439f85cc7bee5246fa", + "payloadBytesEstimate": 96, + "receiptDigest": "0xfbe8a762b036d20581160b7e58a3adccf61f53c653713c439f85cc7bee5246fa", + "receiptId": "receipt:hardware:1e92f586a767", + "resolutionState": "needs-normal-network-reconciliation", + "rootfieldId": "rootfield:hardware:flowrouter-local-alpha", + "ruleSet": "flowmemory.hardware.operator_signal.local_alpha.v0", + "sourcePacketType": "compact_receipt_relay", + "status": "unresolved", + "workerId": "hardware-node:fr-e1e7878a2aa8" + }, + "status": "unresolved", + "summary": "Compact hardware receipt relay awaiting normal network reconciliation.", + "title": "receipt:hardware:1e92f586a767" + } + ], + "verifierReports": [ + { + "facts": [ + { + "label": "relay report id", + "value": "vr-14d051ae590e" + }, + { + "label": "report digest", + "value": "0xb988417bf67c48bab7208ee1fe0531d66fbcb45a1be1b853b70423239c4c8870" + }, + { + "label": "subject digest", + "value": "0x1d5a28ff5af6335dccc9412d01d434aa58bf0870011f781bd614a5266740da3b" + }, + { + "label": "result", + "value": "unresolved" + } + ], + "id": "report:hardware:bd367723d169", + "kind": "Hardware VerifierReport relay", + "provenance": { + "capturedAt": "2026-05-13T17:01:40Z", + "chainContext": "flowchain-private-local-testnet", + "fixturePath": "fixtures/hardware/flowrouter_local_alpha_seed42.json", + "localPathHint": "hardware/fixtures/flowrouter_sample_seed42.json", + "origin": "fixture", + "subsystem": "hardware" + }, + "raw": { + "localOnly": true, + "loraEligible": true, + "payloadBytesEstimate": 128, + "reasonCodes": [ + "hardware_digest_relay_only" + ], + "receiptId": "receipt:hardware:1e92f586a767", + "relayReportId": "vr-14d051ae590e", + "reportDigest": "0xb988417bf67c48bab7208ee1fe0531d66fbcb45a1be1b853b70423239c4c8870", + "reportId": "report:hardware:bd367723d169", + "resolutionState": "needs-full-report", + "rootfieldId": "rootfield:hardware:flowrouter-local-alpha", + "sourcePacketType": "verifier_report_digest_relay", + "status": "unresolved", + "subjectDigest": "0x1d5a28ff5af6335dccc9412d01d434aa58bf0870011f781bd614a5266740da3b", + "verifierId": "hardware-relay:fr-e1e7878a2aa8" + }, + "status": "unresolved", + "summary": "Compact verifier report digest relay; full report is still required.", + "title": "report:hardware:bd367723d169" + } + ] + } +} diff --git a/hardware/README.md b/hardware/README.md index 8a831518..eb561f44 100644 --- a/hardware/README.md +++ b/hardware/README.md @@ -12,6 +12,7 @@ This directory contains the FlowRouter V0 proof-of-concept hardware package. It - `simulator/`: deterministic FlowRouter POC packet generator and schema validator. - `fixtures/`: generated sample packet feeds for tests and future dashboard/service consumers. - `field-tests/`: field-test plans and logs for controlled hardware experiments. +- `../fixtures/hardware/`: generated local-alpha FlowRouter operator-signal projection for dashboard, workbench, or control-plane consumers. ## V0 Purpose @@ -27,6 +28,7 @@ FlowRouter V0 is a local FlowMemory gateway POC. It can model or test: - NFC Memory Cartridge metadata. - FlowCore light-pipe status. - Enclosure measurement direction. +- FlowChain local-alpha operator signals derived from hardware packets, including optional control-plane/workbench fixture collections. ## V0 Non-Goals @@ -50,4 +52,13 @@ python hardware/simulator/flowrouter_sim.py --seed 42 --out hardware/fixtures/fl python hardware/simulator/flowrouter_sim.py --validate-file hardware/fixtures/flowrouter_sample_seed42.json ``` +Generate and validate the local-alpha FlowChain operator-signal projection: + +```powershell +python hardware/simulator/flowrouter_sim.py --seed 42 --out hardware/fixtures/flowrouter_sample_seed42.json --operator-out fixtures/hardware/flowrouter_local_alpha_seed42.json +python hardware/simulator/flowrouter_sim.py --validate-operator-file fixtures/hardware/flowrouter_local_alpha_seed42.json +``` + +The operator projection emits `flowmemory.hardware_operator_signals.local_alpha.v0`, with local-only `signalEnvelopes`, a direct `hardwareSignals` view, control-plane-style collections, and `workbenchRecords`. Hardware remains optional for the private/local testnet path. + The simulator uses only the Python standard library. diff --git a/hardware/flowrouter/FLOWCHAIN_LOCAL_ALPHA_SIGNALS.md b/hardware/flowrouter/FLOWCHAIN_LOCAL_ALPHA_SIGNALS.md new file mode 100644 index 00000000..c894ae3e --- /dev/null +++ b/hardware/flowrouter/FLOWCHAIN_LOCAL_ALPHA_SIGNALS.md @@ -0,0 +1,120 @@ +# FlowRouter FlowChain Local Alpha Signals + +Last updated: 2026-05-13 + +Status: local-alpha operator signal mapping for the FlowRouter V0 proof of concept. + +This document defines how the FlowRouter simulator feed becomes useful FlowChain control-plane and workbench input without changing contracts, services, dashboard code, firmware, or manufacturing scope. + +## Source Fixtures + +The raw deterministic packet feed remains: + +```text +hardware/fixtures/flowrouter_sample_seed42.json +``` + +The FlowChain/workbench projection is: + +```text +fixtures/hardware/flowrouter_local_alpha_seed42.json +``` + +The projection is generated by `hardware/simulator/flowrouter_sim.py` from the same seed as the raw packet fixture. It is local-only, advisory, and schema-validated by: + +```text +hardware/simulator/schemas/flowchain_operator_signals.schema.json +``` + +## Fixture Envelope + +The projection uses the local private-testnet fixture style where applicable: + +- top-level `schema`, `generatedAt`, `chainId`, `environment`, and `source`; +- `signalEnvelopes` with stable local signal ids, source packet references, object references, status, provenance, and payload-size hints; +- `hardwareSignals` as direct workbench/control-plane hardware signal rows for the same five envelopes; +- control-plane-friendly collections: `hardwareNodes`, `workReceipts`, `verifierReports`, `artifactCommitments`, `memoryCells`, `challenges`, `finalityReceipts`, and `alerts`; +- `workbenchRecords` grouped by `receipts`, `verifierReports`, `artifacts`, `memoryCells`, `challenges`, `hardwareSignals`, and `provenance`; +- `boundary.hardwareRequiredForPrivateTestnet = false`. + +This is an optional fixture projection. It is not a devnet transaction source and it does not make hardware required for the private/local chain, indexer, verifier, control-plane, or workbench to run. + +## Packet Mapping + +| FlowRouter packet | Projection collection | Why it is useful | Boundary | +| --- | --- | --- | --- | +| `heartbeat` | `hardwareNodes` | Shows FlowRouter reachability, power, cache, sidecar, and FlowCore state to an operator. | Local advisory status only; not hardware attestation. | +| `compact_receipt_relay` | `workReceipts` and `finalityReceipts` | Gives the workbench a compact WorkReceipt candidate using receipt digest plus block, tx-prefix, and log-index hints. | Requires normal network/indexer reconciliation before it can be trusted. | +| `verifier_report_digest_relay` | `verifierReports` | Gives the workbench a VerifierReport candidate using report id, report digest, subject digest, and result. | Digest relay is not the full verifier report. | +| `emergency_offline_signal` | `alerts` and `challenges` | Creates a local operator alert and optional challenge input when upstream or local conditions degrade. | Candidate input only; it does not execute remote commands or claim public emergency-service reliability. | +| `nfc_memory_cartridge_metadata` | `artifactCommitments` and `memoryCells` | Lets a cartridge label, pointer, digest, and expiration become an artifact/memory reference for operator workflows. | Untrusted metadata pointer only; it is not a secret store or proof. | + +## Control-Plane And Workbench Consumption + +The fixture is intentionally shaped so another agent can add it to the local control-plane without creating a second hardware pipeline: + +- `compatibility.controlPlaneStateKeys` names the collections a local read API can expose or merge. +- `workReceipts`, `verifierReports`, `artifactCommitments`, `memoryCells`, `challenges`, and `finalityReceipts` use the same object names the private/local workbench already scans for in fixture state. +- `hardwareSignals` is present as a direct collection for workbench hardware-signal sections that do not want to re-project `signalEnvelopes`. +- `workbenchRecords` provides ready-to-render records when a UI chooses not to re-project the raw collections. +- Every projected object keeps `sourcePacketType`, `localOnly`, and provenance back to `hardware/fixtures/flowrouter_sample_seed42.json`. + +The receipt, report, memory cell, challenge, and finality objects are hints. They should never be treated as final evidence until the normal control-plane/indexer/verifier path resolves them. + +## What Hardware Contributes + +- Operator-visible status for a FlowRouter-like node. +- Compact receipt and verifier-report breadcrumbs during degraded connectivity. +- A local alert signal that can seed dashboard/operator attention. +- A physical metadata path for memory/artifact references through NFC cartridge reads. +- A low-bandwidth control-signal fixture that workbench, dashboard, or control-plane code can import. + +## What Remains Local Only + +- Device status and packet timing. +- Receipt and verifier digest relays until reconciled against normal receipt, indexer, and verifier data. +- NFC labels, pointers, and cartridge ids until checked against expected commitments. +- Emergency/offline alert state until a local operator or later challenge workflow acts on it. +- Any simulated radio, cache, display, FlowCore, and cartridge state. + +## What Cannot Be Claimed + +- No production manufacturing readiness. +- No production firmware, custom RF board, amplifier, antenna, final CAD, or certification claim. +- No public field deployment or public safety reliability claim. +- No high-bandwidth LoRa or Meshtastic transport. +- No transfer of AI memory artifacts, model weights, media, raw memory, full receipts, or full verifier reports over LoRa. +- No hardware trustlessness, validator role, or verifier proof claim. +- No requirement that FlowRouter hardware is online for the main local chain, indexer, verifier, or dashboard fixture flow to run. + +## Validation Commands + +Generate the raw packet fixture and the local-alpha projection: + +```powershell +python hardware/simulator/flowrouter_sim.py --seed 42 --out hardware/fixtures/flowrouter_sample_seed42.json --operator-out fixtures/hardware/flowrouter_local_alpha_seed42.json +``` + +This command is the simulator smoke path because the generator validates both outputs before writing them. + +Validate the raw simulator packet fixture: + +```powershell +python hardware/simulator/flowrouter_sim.py --validate-file hardware/fixtures/flowrouter_sample_seed42.json +``` + +Validate the FlowChain local-alpha projection: + +```powershell +python hardware/simulator/flowrouter_sim.py --validate-operator-file fixtures/hardware/flowrouter_local_alpha_seed42.json +``` + +## Integration Notes + +- A dashboard, workbench, or control-plane can read `packetMappings` to understand which packet produced each local-alpha object. +- `hardwareSignals` can feed workbench hardware-signal tables directly. +- `hardwareNodes` can feed hardware node cards or operator status rows. +- `workReceipts` and `verifierReports` are breadcrumbs for later reconciliation; they are not final evidence. +- `alerts` and `challenges` can seed local operator attention without blocking the rest of the local flow. +- `artifactCommitments` and `memoryCells` can seed artifact or memory-reference panels while keeping cartridge contents untrusted. +- `workbenchRecords` can be rendered directly by a fixture-backed workbench, or ignored if the workbench re-projects the canonical collections itself. diff --git a/hardware/flowrouter/README.md b/hardware/flowrouter/README.md index 3b886382..a86565cf 100644 --- a/hardware/flowrouter/README.md +++ b/hardware/flowrouter/README.md @@ -38,6 +38,7 @@ V0 uses certified router/radio hardware and off-the-shelf compute. It does not i ## Directory Map - `FLOWROUTER_V0_SCOPE.md`: scope, non-goals, hardware assumptions, and tier definitions. +- `FLOWCHAIN_LOCAL_ALPHA_SIGNALS.md`: FlowRouter packet mapping into local-alpha FlowChain operator-signal objects. - `BOM.md`: research BOM candidates and tier summaries. - `ASSEMBLY.md`: safe prototype assembly sequence. - `PRINTING_GUIDE.md`: enclosure and material constraints before CAD. @@ -57,5 +58,6 @@ V0 uses certified router/radio hardware and off-the-shelf compute. It does not i - A local operator can tell whether the node has upstream internet, LAN availability, cache health, power/thermal status, and sidecar status. - A second node can receive compact Meshtastic status or digest messages during degraded IP connectivity. - Cached state is clearly marked local-only until verified through normal network, indexer, or chain-derived paths. +- Hardware packets can be projected into local-alpha `hardwareSignals`, `hardwareNodes`, `workReceipts`, `verifierReports`, `alerts`, `challenges`, `artifactCommitments`, and `memoryCells` without blocking the main local chain flow. - The prototype can be measured for thermal, power, serviceability, and enclosure-fit constraints. - The docs make it difficult to overclaim bandwidth, production readiness, trustlessness, or regulatory status. diff --git a/hardware/simulator/README.md b/hardware/simulator/README.md index 0e75a304..ed1be3db 100644 --- a/hardware/simulator/README.md +++ b/hardware/simulator/README.md @@ -10,12 +10,26 @@ The simulator emits deterministic FlowRouter V0 proof-of-concept packets for das python hardware/simulator/flowrouter_sim.py --seed 42 --out hardware/fixtures/flowrouter_sample_seed42.json ``` +## Generate Local-Alpha Operator Signals + +```powershell +python hardware/simulator/flowrouter_sim.py --seed 42 --out hardware/fixtures/flowrouter_sample_seed42.json --operator-out fixtures/hardware/flowrouter_local_alpha_seed42.json +``` + +This is also the simulator smoke command: generation validates the raw packet fixture and the local-alpha operator projection before writing either output file. + ## Validate Existing Fixture ```powershell python hardware/simulator/flowrouter_sim.py --validate-file hardware/fixtures/flowrouter_sample_seed42.json ``` +## Validate Local-Alpha Operator Signals + +```powershell +python hardware/simulator/flowrouter_sim.py --validate-operator-file fixtures/hardware/flowrouter_local_alpha_seed42.json +``` + ## Packet Types - Device manifest @@ -29,5 +43,16 @@ python hardware/simulator/flowrouter_sim.py --validate-file hardware/fixtures/fl - NFC Memory Cartridge metadata - Emergency/offline signal - Dashboard feed +- FlowChain local-alpha operator signal projection The packets are JSON versions of compact, binary-inspired fields. They are not production protocol commitments and should remain small enough to reason about LoRa constraints. + +The local-alpha projection is a `flowmemory.hardware_operator_signals.local_alpha.v0` document. It uses camelCase, a top-level `schema`, local-only `signalEnvelopes`, a direct `hardwareSignals` view, and workbench/control-plane-ready collections: + +- `heartbeat` -> `hardwareNodes` +- `compact_receipt_relay` -> `workReceipts` +- `verifier_report_digest_relay` -> `verifierReports` +- `emergency_offline_signal` -> `alerts` and `challenges` +- `nfc_memory_cartridge_metadata` -> `artifactCommitments` and `memoryCells` + +It also includes `workbenchRecords` grouped by `receipts`, `verifierReports`, `artifacts`, `memoryCells`, `challenges`, `hardwareSignals`, and `provenance`. These projection objects are local-only and advisory until reconciled through normal FlowMemory indexer, receipt, verifier, or operator workflows. diff --git a/hardware/simulator/flowrouter_sim.py b/hardware/simulator/flowrouter_sim.py index bb242a57..643bacf9 100644 --- a/hardware/simulator/flowrouter_sim.py +++ b/hardware/simulator/flowrouter_sim.py @@ -25,6 +25,11 @@ "dashboard_feed": "dashboard_feed.schema.json", } +OPERATOR_SIGNALS_SCHEMA_FILE = "flowchain_operator_signals.schema.json" +ZERO_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000" +HARDWARE_ROOTFIELD_ID = "rootfield:hardware:flowrouter-local-alpha" +HARDWARE_CHAIN_CONTEXT = "flowchain-private-local-testnet" + def digest(seed: int, label: str, length: int = 64) -> str: return hashlib.sha256(f"flowrouter-v0:{seed}:{label}".encode("utf-8")).hexdigest()[:length] @@ -34,6 +39,10 @@ def short_id(seed: int, label: str) -> str: return digest(seed, label, 12) +def ensure_hex(value: str) -> str: + return value if value.startswith("0x") else f"0x{value}" + + def iso_tick(offset_seconds: int) -> str: # Fixed clock keeps fixtures deterministic. base_hour = 17 @@ -262,6 +271,513 @@ def build_packets(seed: int) -> dict[str, Any]: } +def build_operator_signals(seed: int, packets: dict[str, Any] | None = None) -> dict[str, Any]: + packet_set = packets if packets is not None else build_packets(seed) + heartbeat = packet_set["heartbeat"] + receipt = packet_set["compact_receipt_relay"] + verifier = packet_set["verifier_report_digest_relay"] + emergency = packet_set["emergency_offline_signal"] + cartridge = packet_set["nfc_memory_cartridge_metadata"] + dashboard = packet_set["dashboard_feed"] + + device_id = heartbeat["device_id"] + generated_at = dashboard["generated_at"] + packet_fixture_path = f"hardware/fixtures/flowrouter_sample_seed{seed}.json" + operator_fixture_path = f"fixtures/hardware/flowrouter_local_alpha_seed{seed}.json" + worker_id = f"hardware-node:{device_id}" + verifier_id = f"hardware-relay:{device_id}" + receipt_id = f"receipt:hardware:{short_id(seed, 'work-receipt-ref')}" + verifier_report_id = f"report:hardware:{short_id(seed, 'verifier-report-ref')}" + alert_id = f"hw-alert-{short_id(seed, 'offline-alert')}" + challenge_id = f"challenge:hardware:{short_id(seed, 'offline-challenge')}" + artifact_id = f"artifact:hardware:{short_id(seed, 'cartridge-artifact-ref')}" + memory_cell_id = f"memory:hardware:{short_id(seed, 'cartridge-memory-ref')}" + finality_receipt_id = f"finality:hardware:{short_id(seed, 'receipt-finality')}" + + provenance = { + "subsystem": "hardware", + "origin": "fixture", + "chainContext": HARDWARE_CHAIN_CONTEXT, + "fixturePath": operator_fixture_path, + "capturedAt": generated_at, + "localPathHint": packet_fixture_path, + } + + hardware_node = { + "id": device_id, + "nodeId": device_id, + "callsign": "FlowRouter local-alpha fixture", + "role": "router", + "firmware": "flowrouter.poc.v0", + "transport": "local-wifi+meshtastic-sidecar-sim", + "lastHeartbeatAt": heartbeat["emitted_at"], + "linkedWorkLaneId": "CHECKPOINT_STORAGE", + "locationHint": "local lab fixture", + "status": "verified" if heartbeat["network_state"] == "online" else "stale", + "powerState": heartbeat["power_state"], + "cacheState": heartbeat["cache_state"], + "sidecarState": heartbeat["sidecar_state"], + "flowcoreState": heartbeat["flowcore_state"], + "warnings": heartbeat["warnings"], + "localOnly": True, + "sourcePacketType": "heartbeat", + "provenance": provenance, + } + + work_receipt = { + "receiptId": receipt_id, + "rootfieldId": HARDWARE_ROOTFIELD_ID, + "workerId": worker_id, + "inputRoot": ZERO_HASH, + "outputRoot": ensure_hex(receipt["receipt_digest"]), + "artifactCommitment": ensure_hex(cartridge["digest"]), + "ruleSet": "flowmemory.hardware.operator_signal.local_alpha.v0", + "status": "unresolved", + "receiptDigest": ensure_hex(receipt["receipt_digest"]), + "chain": receipt["chain"], + "locatorHint": { + "blockHint": receipt["block_hint"], + "txHashPrefix": receipt["tx_hash_prefix"], + "logIndexHint": receipt["log_index_hint"], + }, + "resolutionState": "needs-normal-network-reconciliation", + "payloadBytesEstimate": receipt["payload_bytes_estimate"], + "loraEligible": receipt["lora_eligible"], + "localOnly": True, + "sourcePacketType": "compact_receipt_relay", + } + + verifier_report = { + "reportId": verifier_report_id, + "relayReportId": verifier["report_id"], + "rootfieldId": HARDWARE_ROOTFIELD_ID, + "receiptId": receipt_id, + "verifierId": verifier_id, + "reportDigest": ensure_hex(verifier["report_digest"]), + "subjectDigest": ensure_hex(verifier["subject_digest"]), + "status": verifier["result"], + "reasonCodes": ["hardware_digest_relay_only"], + "resolutionState": "needs-full-report", + "payloadBytesEstimate": verifier["payload_bytes_estimate"], + "loraEligible": verifier["lora_eligible"], + "localOnly": True, + "sourcePacketType": "verifier_report_digest_relay", + } + + artifact = { + "artifactId": artifact_id, + "rootfieldId": HARDWARE_ROOTFIELD_ID, + "commitment": ensure_hex(cartridge["digest"]), + "uriHint": cartridge["pointer"], + "status": "observed", + "availabilityStatus": "metadata-only", + "cartridgeId": cartridge["cartridge_id"], + "label": cartridge["label"], + "expiresAt": cartridge["expires_at"], + "containsSecrets": cartridge["contains_secrets"], + "trustLevel": cartridge["trust_level"], + "localOnly": True, + "sourcePacketType": "nfc_memory_cartridge_metadata", + } + + memory_cell = { + "memoryCellId": memory_cell_id, + "rootfieldId": HARDWARE_ROOTFIELD_ID, + "currentRoot": ensure_hex(cartridge["digest"]), + "latestRoot": ensure_hex(cartridge["digest"]), + "receiptId": receipt_id, + "artifactId": artifact_id, + "status": "observed", + "summary": "NFC cartridge metadata pointer projected into a local memory cell candidate.", + "updatedAt": cartridge["created_at"], + "resolutionState": "untrusted-metadata-only", + "localOnly": True, + "sourcePacketType": "nfc_memory_cartridge_metadata", + } + + challenge = { + "challengeId": challenge_id, + "targetId": receipt_id, + "receiptId": receipt_id, + "reportId": verifier_report_id, + "openedBy": worker_id, + "status": "pending", + "reason": "offline-alert-candidate", + "summary": emergency["summary"], + "openedAt": emergency["emitted_at"], + "ttlSeconds": emergency["ttl_seconds"], + "recommendedAction": emergency["operator_action"], + "doesNotExecuteRemoteAction": True, + "localOnly": True, + "sourcePacketType": "emergency_offline_signal", + } + + finality_receipt = { + "finalityReceiptId": finality_receipt_id, + "objectId": receipt_id, + "receiptId": receipt_id, + "rootfieldId": HARDWARE_ROOTFIELD_ID, + "finalityStatus": "local-pending", + "settlement": "local-fixture", + "status": "pending", + "localOnly": True, + "sourcePacketType": "compact_receipt_relay", + } + + alert = { + "id": alert_id, + "incidentId": alert_id, + "severity": "warning", + "title": emergency["code"], + "summary": emergency["summary"], + "openedAt": emergency["emitted_at"], + "linkedObjectIds": [device_id, receipt_id, challenge_id], + "recommendedAction": emergency["operator_action"], + "status": "unresolved", + "localOnly": True, + "sourcePacketType": "emergency_offline_signal", + "provenance": provenance, + } + + def signal_envelope( + label: str, + signal_type: str, + packet: dict[str, Any], + object_refs: list[dict[str, str]], + status: str, + ) -> dict[str, Any]: + packet_type = packet["packet_type"] + sequence = packet.get("sequence", seed) + return { + "schema": "flowmemory.hardware_operator_signal_envelope.local_alpha.v0", + "envelopeId": f"hw-env-{short_id(seed, f'{label}-envelope')}", + "signalId": f"hw-sig-{short_id(seed, f'{label}-signal')}", + "signalType": signal_type, + "sourcePacketType": packet_type, + "sourcePacketId": f"{packet_type}:{sequence}", + "observedAt": packet.get("emitted_at", packet.get("created_at", generated_at)), + "status": status, + "localOnly": True, + "payloadBytesEstimate": packet.get("payload_bytes_estimate", 0), + "loraEligible": packet.get("lora_eligible", False), + "objectRefs": object_refs, + "provenance": provenance, + } + + def workbench_record( + record_id: str, + kind: str, + title: str, + summary: str, + status: str, + facts: list[dict[str, str]], + raw: dict[str, Any], + ) -> dict[str, Any]: + return { + "id": record_id, + "kind": kind, + "title": title, + "summary": summary, + "status": status, + "facts": facts, + "provenance": provenance, + "raw": raw, + } + + signal_envelopes = [ + signal_envelope( + "heartbeat", + "heartbeat", + heartbeat, + [{"collection": "hardwareNodes", "objectId": device_id}], + "observed", + ), + signal_envelope( + "receipt-relay", + "receipt_relay", + receipt, + [{"collection": "workReceipts", "objectId": receipt_id}], + "unresolved", + ), + signal_envelope( + "verifier-digest-relay", + "verifier_digest_relay", + verifier, + [{"collection": "verifierReports", "objectId": verifier_report_id}], + "unresolved", + ), + signal_envelope( + "offline-alert-challenge", + "offline_alert_challenge_input", + emergency, + [ + {"collection": "alerts", "objectId": alert_id}, + {"collection": "challenges", "objectId": challenge_id}, + ], + "pending", + ), + signal_envelope( + "nfc-memory-cartridge", + "nfc_memory_cartridge_metadata", + cartridge, + [ + {"collection": "artifactCommitments", "objectId": artifact_id}, + {"collection": "memoryCells", "objectId": memory_cell_id}, + ], + "observed", + ), + ] + + signal_summaries = { + "heartbeat": "FlowRouter heartbeat and coarse node state.", + "receipt_relay": "Compact WorkReceipt digest relay awaiting normal reconciliation.", + "verifier_digest_relay": "Compact VerifierReport digest relay awaiting the full report.", + "offline_alert_challenge_input": "Offline alert that can seed a local challenge candidate.", + "nfc_memory_cartridge_metadata": "NFC metadata pointer projected into artifact and memory references.", + } + hardware_signals = [ + { + "id": envelope["signalId"], + "signalId": envelope["signalId"], + "envelopeId": envelope["envelopeId"], + "nodeId": device_id, + "signalType": envelope["signalType"], + "sourcePacketType": envelope["sourcePacketType"], + "summary": signal_summaries[envelope["signalType"]], + "status": envelope["status"], + "transport": "local-simulator" if not envelope["loraEligible"] else "meshtastic-control-sim", + "receivedAt": envelope["observedAt"], + "localOnly": True, + "loraEligible": envelope["loraEligible"], + "linkedObjectIds": [ref["objectId"] for ref in envelope["objectRefs"]], + "provenance": provenance, + "rawEnvelope": envelope, + } + for envelope in signal_envelopes + ] + + return { + "schema": "flowmemory.hardware_operator_signals.local_alpha.v0", + "generatedAt": generated_at, + "chainId": "flowmemory-local-alpha", + "environment": "local-devnet-fixture", + "source": "fixture", + "sourcePaths": { + "packetFixture": packet_fixture_path, + "operatorFixture": operator_fixture_path, + "operatorSchema": "hardware/simulator/schemas/flowchain_operator_signals.schema.json", + "mappingDoc": "hardware/flowrouter/FLOWCHAIN_LOCAL_ALPHA_SIGNALS.md", + }, + "boundary": { + "localOnly": True, + "advisory": True, + "normalNetworkReconciliationRequired": True, + "hardwareRequiredForPrivateTestnet": False, + "claimLimitations": [ + "Hardware-originated references are hints until reconciled by normal indexer, receipt, and verifier paths.", + "LoRa and Meshtastic packets carry compact control signals, not artifacts, model data, media, or raw memory.", + "NFC cartridge metadata is an untrusted pointer until checked against expected commitments.", + "Emergency offline signals are operator alerts or challenge inputs only; they do not execute remote actions.", + ], + }, + "packetMappings": [ + { + "sourcePacketType": "heartbeat", + "flowchainSignal": "hardware_node_status", + "objectCollection": "hardwareNodes", + "objectRef": device_id, + "localAlphaRole": "shows FlowRouter reachability and coarse device state", + "trustBoundary": "local advisory status, not hardware attestation", + }, + { + "sourcePacketType": "compact_receipt_relay", + "flowchainSignal": "work_receipt_reference", + "objectCollection": "workReceipts", + "objectRef": receipt_id, + "localAlphaRole": "points the workbench at a WorkReceipt candidate", + "trustBoundary": "digest and locator hints require normal receipt reconciliation", + }, + { + "sourcePacketType": "verifier_report_digest_relay", + "flowchainSignal": "verifier_report_reference", + "objectCollection": "verifierReports", + "objectRef": verifier_report_id, + "localAlphaRole": "points the workbench at a VerifierReport candidate", + "trustBoundary": "digest relay is not the full verifier report", + }, + { + "sourcePacketType": "emergency_offline_signal", + "flowchainSignal": "alert_challenge_input", + "objectCollection": "challenges", + "objectRef": challenge_id, + "localAlphaRole": "creates an operator alert and optional challenge input", + "trustBoundary": "local operator attention only; no public emergency-service claim", + }, + { + "sourcePacketType": "nfc_memory_cartridge_metadata", + "flowchainSignal": "artifact_memory_reference", + "objectCollection": "artifactCommitments", + "objectRef": artifact_id, + "localAlphaRole": "connects cartridge metadata to an artifact or memory reference", + "trustBoundary": "untrusted metadata pointer, not a secret store or proof", + }, + ], + "signalEnvelopes": signal_envelopes, + "hardwareSignals": hardware_signals, + "hardwareNodes": [hardware_node], + "workReceipts": [work_receipt], + "verifierReports": [verifier_report], + "artifactCommitments": [artifact], + "memoryCells": [memory_cell], + "challenges": [challenge], + "finalityReceipts": [finality_receipt], + "alerts": [alert], + "workbenchRecords": { + "receipts": [ + workbench_record( + receipt_id, + "Hardware WorkReceipt relay", + receipt_id, + "Compact hardware receipt relay awaiting normal network reconciliation.", + "unresolved", + [ + {"label": "rootfield", "value": HARDWARE_ROOTFIELD_ID}, + {"label": "receipt digest", "value": ensure_hex(receipt["receipt_digest"])}, + {"label": "block hint", "value": str(receipt["block_hint"])}, + {"label": "tx prefix", "value": receipt["tx_hash_prefix"]}, + ], + work_receipt, + ) + ], + "verifierReports": [ + workbench_record( + verifier_report_id, + "Hardware VerifierReport relay", + verifier_report_id, + "Compact verifier report digest relay; full report is still required.", + "unresolved", + [ + {"label": "relay report id", "value": verifier["report_id"]}, + {"label": "report digest", "value": ensure_hex(verifier["report_digest"])}, + {"label": "subject digest", "value": ensure_hex(verifier["subject_digest"])}, + {"label": "result", "value": verifier["result"]}, + ], + verifier_report, + ) + ], + "artifacts": [ + workbench_record( + artifact_id, + "NFC cartridge artifact reference", + cartridge["label"], + "NFC cartridge metadata pointer; content is untrusted until commitment checks pass.", + "observed", + [ + {"label": "cartridge", "value": cartridge["cartridge_id"]}, + {"label": "pointer", "value": cartridge["pointer"]}, + {"label": "commitment", "value": ensure_hex(cartridge["digest"])}, + {"label": "expires", "value": cartridge["expires_at"]}, + ], + artifact, + ) + ], + "memoryCells": [ + workbench_record( + memory_cell_id, + "Hardware memory cell candidate", + memory_cell_id, + "Projected from NFC cartridge metadata for local operator inspection.", + "observed", + [ + {"label": "rootfield", "value": HARDWARE_ROOTFIELD_ID}, + {"label": "latest root", "value": ensure_hex(cartridge["digest"])}, + {"label": "receipt", "value": receipt_id}, + {"label": "artifact", "value": artifact_id}, + ], + memory_cell, + ) + ], + "challenges": [ + workbench_record( + challenge_id, + "Offline alert challenge candidate", + emergency["code"], + emergency["summary"], + "pending", + [ + {"label": "target", "value": receipt_id}, + {"label": "report", "value": verifier_report_id}, + {"label": "ttl seconds", "value": str(emergency["ttl_seconds"])}, + {"label": "action", "value": emergency["operator_action"]}, + ], + challenge, + ) + ], + "hardwareSignals": [ + workbench_record( + signal["signalId"], + "Hardware operator signal", + signal["signalType"], + signal["summary"], + signal["status"], + [ + {"label": "node", "value": signal["nodeId"]}, + {"label": "transport", "value": signal["transport"]}, + {"label": "source packet", "value": signal["sourcePacketType"]}, + {"label": "linked objects", "value": ", ".join(signal["linkedObjectIds"])}, + ], + signal, + ) + for signal in hardware_signals + ], + "provenance": [ + workbench_record( + "hardware-operator-signal-fixture", + "Hardware operator signal fixture", + operator_fixture_path, + "Deterministic optional hardware signal projection for control-plane/workbench import.", + "verified", + [ + {"label": "packet fixture", "value": packet_fixture_path}, + {"label": "schema", "value": "flowmemory.hardware_operator_signals.local_alpha.v0"}, + {"label": "seed", "value": str(seed)}, + {"label": "hardware required", "value": "false"}, + ], + { + "sourcePaths": { + "packetFixture": packet_fixture_path, + "operatorFixture": operator_fixture_path, + } + }, + ) + ], + }, + "compatibility": { + "controlPlaneStateKeys": [ + "hardwareSignals", + "hardwareNodes", + "workReceipts", + "verifierReports", + "artifactCommitments", + "memoryCells", + "challenges", + "finalityReceipts", + "alerts", + ], + "workbenchSectionKeys": [ + "receipts", + "verifierReports", + "artifacts", + "memoryCells", + "challenges", + "hardwareSignals", + "provenance", + ], + "jsonRpcBoundary": "Read-only fixture data; no submit, wallet, live indexing, or production settlement method is implied.", + }, + } + + class ValidationError(Exception): pass @@ -337,6 +853,11 @@ def validate_packets(packets: dict[str, Any], schema_dir: Path) -> None: validate_value(schema, packet, name) +def validate_operator_signals(operator_signals: dict[str, Any], schema_dir: Path) -> None: + schema = json.loads((schema_dir / OPERATOR_SIGNALS_SCHEMA_FILE).read_text(encoding="utf-8")) + validate_value(schema, operator_signals, "operator_signals") + + def output_document(seed: int) -> dict[str, Any]: return { "simulator": "flowrouter-v0-poc", @@ -350,20 +871,36 @@ def main() -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--seed", type=int, default=42, help="deterministic seed") parser.add_argument("--out", type=Path, help="write generated JSON to this path") + parser.add_argument("--operator-out", type=Path, help="write FlowChain local-alpha operator signal JSON to this path") parser.add_argument("--validate-file", type=Path, help="validate an existing simulator JSON file") + parser.add_argument("--validate-operator-file", type=Path, help="validate an existing FlowChain local-alpha operator signal JSON file") args = parser.parse_args() schema_dir = Path(__file__).resolve().parent / "schemas" try: + if args.validate_operator_file: + operator_doc = json.loads(args.validate_operator_file.read_text(encoding="utf-8")) + validate_operator_signals(operator_doc, schema_dir) + print(f"valid: {args.validate_operator_file}") + return 0 + if args.validate_file: doc = json.loads(args.validate_file.read_text(encoding="utf-8")) validate_packets(doc["packets"], schema_dir) print(f"valid: {args.validate_file}") return 0 - doc = output_document(args.seed) + packets = build_packets(args.seed) + doc = { + "simulator": "flowrouter-v0-poc", + "seed": args.seed, + "generated_at": iso_tick(120), + "packets": packets, + } validate_packets(doc["packets"], schema_dir) + operator_doc = build_operator_signals(args.seed, packets) + validate_operator_signals(operator_doc, schema_dir) encoded = json.dumps(doc, indent=2, sort_keys=True) + "\n" if args.out: args.out.parent.mkdir(parents=True, exist_ok=True) @@ -371,6 +908,10 @@ def main() -> int: print(f"wrote: {args.out}") else: sys.stdout.write(encoded) + if args.operator_out: + args.operator_out.parent.mkdir(parents=True, exist_ok=True) + args.operator_out.write_text(json.dumps(operator_doc, indent=2, sort_keys=True) + "\n", encoding="utf-8") + print(f"wrote: {args.operator_out}") return 0 except (KeyError, json.JSONDecodeError, OSError, ValidationError) as exc: print(f"error: {exc}", file=sys.stderr) diff --git a/hardware/simulator/schemas/flowchain_operator_signals.schema.json b/hardware/simulator/schemas/flowchain_operator_signals.schema.json new file mode 100644 index 00000000..05926abe --- /dev/null +++ b/hardware/simulator/schemas/flowchain_operator_signals.schema.json @@ -0,0 +1,429 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "FlowMemory Hardware Operator Signals Local Alpha", + "type": "object", + "additionalProperties": false, + "required": [ + "schema", + "generatedAt", + "chainId", + "environment", + "source", + "sourcePaths", + "boundary", + "packetMappings", + "signalEnvelopes", + "hardwareSignals", + "hardwareNodes", + "workReceipts", + "verifierReports", + "artifactCommitments", + "memoryCells", + "challenges", + "finalityReceipts", + "alerts", + "workbenchRecords", + "compatibility" + ], + "properties": { + "schema": { + "type": "string", + "enum": ["flowmemory.hardware_operator_signals.local_alpha.v0"] + }, + "generatedAt": { "type": "string" }, + "chainId": { "type": "string", "enum": ["flowmemory-local-alpha"] }, + "environment": { "type": "string", "enum": ["local-devnet-fixture"] }, + "source": { "type": "string", "enum": ["fixture"] }, + "sourcePaths": { + "type": "object", + "additionalProperties": false, + "required": ["packetFixture", "operatorFixture", "operatorSchema", "mappingDoc"], + "properties": { + "packetFixture": { "type": "string", "maxLength": 128 }, + "operatorFixture": { "type": "string", "maxLength": 128 }, + "operatorSchema": { "type": "string", "maxLength": 128 }, + "mappingDoc": { "type": "string", "maxLength": 128 } + } + }, + "boundary": { + "type": "object", + "additionalProperties": false, + "required": [ + "localOnly", + "advisory", + "normalNetworkReconciliationRequired", + "hardwareRequiredForPrivateTestnet", + "claimLimitations" + ], + "properties": { + "localOnly": { "type": "boolean", "enum": [true] }, + "advisory": { "type": "boolean", "enum": [true] }, + "normalNetworkReconciliationRequired": { "type": "boolean", "enum": [true] }, + "hardwareRequiredForPrivateTestnet": { "type": "boolean", "enum": [false] }, + "claimLimitations": { + "type": "array", + "items": { "type": "string", "maxLength": 180 } + } + } + }, + "packetMappings": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "sourcePacketType", + "flowchainSignal", + "objectCollection", + "objectRef", + "localAlphaRole", + "trustBoundary" + ], + "properties": { + "sourcePacketType": { + "type": "string", + "enum": [ + "heartbeat", + "compact_receipt_relay", + "verifier_report_digest_relay", + "emergency_offline_signal", + "nfc_memory_cartridge_metadata" + ] + }, + "flowchainSignal": { + "type": "string", + "enum": [ + "hardware_node_status", + "work_receipt_reference", + "verifier_report_reference", + "alert_challenge_input", + "artifact_memory_reference" + ] + }, + "objectCollection": { + "type": "string", + "enum": [ + "hardwareNodes", + "workReceipts", + "verifierReports", + "challenges", + "artifactCommitments" + ] + }, + "objectRef": { "type": "string", "maxLength": 96 }, + "localAlphaRole": { "type": "string", "maxLength": 140 }, + "trustBoundary": { "type": "string", "maxLength": 160 } + } + } + }, + "signalEnvelopes": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "schema", + "envelopeId", + "signalId", + "signalType", + "sourcePacketType", + "sourcePacketId", + "observedAt", + "status", + "localOnly", + "payloadBytesEstimate", + "loraEligible", + "objectRefs", + "provenance" + ], + "properties": { + "schema": { + "type": "string", + "enum": ["flowmemory.hardware_operator_signal_envelope.local_alpha.v0"] + }, + "envelopeId": { "type": "string", "maxLength": 64 }, + "signalId": { "type": "string", "maxLength": 64 }, + "signalType": { + "type": "string", + "enum": [ + "heartbeat", + "receipt_relay", + "verifier_digest_relay", + "offline_alert_challenge_input", + "nfc_memory_cartridge_metadata" + ] + }, + "sourcePacketType": { "type": "string", "maxLength": 64 }, + "sourcePacketId": { "type": "string", "maxLength": 96 }, + "observedAt": { "type": "string" }, + "status": { "type": "string", "enum": ["observed", "pending", "unresolved"] }, + "localOnly": { "type": "boolean", "enum": [true] }, + "payloadBytesEstimate": { "type": "integer", "minimum": 0, "maximum": 200 }, + "loraEligible": { "type": "boolean" }, + "objectRefs": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["collection", "objectId"], + "properties": { + "collection": { "type": "string", "maxLength": 64 }, + "objectId": { "type": "string", "maxLength": 96 } + } + } + }, + "provenance": { "type": "object" } + } + } + }, + "hardwareSignals": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "signalId", + "envelopeId", + "nodeId", + "signalType", + "sourcePacketType", + "summary", + "status", + "transport", + "receivedAt", + "localOnly", + "loraEligible", + "linkedObjectIds", + "provenance", + "rawEnvelope" + ], + "properties": { + "id": { "type": "string", "maxLength": 64 }, + "signalId": { "type": "string", "maxLength": 64 }, + "envelopeId": { "type": "string", "maxLength": 64 }, + "nodeId": { "type": "string", "maxLength": 64 }, + "signalType": { + "type": "string", + "enum": [ + "heartbeat", + "receipt_relay", + "verifier_digest_relay", + "offline_alert_challenge_input", + "nfc_memory_cartridge_metadata" + ] + }, + "sourcePacketType": { "type": "string", "maxLength": 64 }, + "summary": { "type": "string", "maxLength": 160 }, + "status": { "type": "string", "enum": ["observed", "pending", "unresolved"] }, + "transport": { "type": "string", "enum": ["local-simulator", "meshtastic-control-sim"] }, + "receivedAt": { "type": "string" }, + "localOnly": { "type": "boolean", "enum": [true] }, + "loraEligible": { "type": "boolean" }, + "linkedObjectIds": { "type": "array", "items": { "type": "string", "maxLength": 96 } }, + "provenance": { "type": "object" }, + "rawEnvelope": { "type": "object" } + } + } + }, + "hardwareNodes": { + "type": "array", + "items": { + "type": "object", + "required": ["id", "nodeId", "role", "transport", "lastHeartbeatAt", "status", "localOnly", "sourcePacketType"], + "properties": { + "id": { "type": "string", "maxLength": 64 }, + "nodeId": { "type": "string", "maxLength": 64 }, + "role": { "type": "string", "enum": ["router", "gateway", "sidecar", "field-kit"] }, + "transport": { "type": "string", "maxLength": 96 }, + "lastHeartbeatAt": { "type": "string" }, + "status": { "type": "string", "enum": ["verified", "stale", "offline", "observed"] }, + "localOnly": { "type": "boolean", "enum": [true] }, + "sourcePacketType": { "type": "string", "enum": ["heartbeat"] } + } + } + }, + "workReceipts": { + "type": "array", + "items": { + "type": "object", + "required": [ + "receiptId", + "rootfieldId", + "workerId", + "inputRoot", + "outputRoot", + "artifactCommitment", + "ruleSet", + "status", + "receiptDigest", + "locatorHint", + "resolutionState", + "localOnly", + "sourcePacketType" + ], + "properties": { + "receiptId": { "type": "string", "maxLength": 96 }, + "rootfieldId": { "type": "string", "maxLength": 96 }, + "workerId": { "type": "string", "maxLength": 96 }, + "inputRoot": { "type": "string", "maxLength": 66 }, + "outputRoot": { "type": "string", "maxLength": 66 }, + "artifactCommitment": { "type": "string", "maxLength": 66 }, + "ruleSet": { "type": "string", "maxLength": 96 }, + "status": { "type": "string", "enum": ["observed", "pending", "unresolved", "verified", "failed"] }, + "receiptDigest": { "type": "string", "maxLength": 66 }, + "locatorHint": { "type": "object" }, + "resolutionState": { "type": "string", "enum": ["needs-normal-network-reconciliation"] }, + "localOnly": { "type": "boolean", "enum": [true] }, + "sourcePacketType": { "type": "string", "enum": ["compact_receipt_relay"] } + } + } + }, + "verifierReports": { + "type": "array", + "items": { + "type": "object", + "required": [ + "reportId", + "rootfieldId", + "receiptId", + "verifierId", + "reportDigest", + "subjectDigest", + "status", + "reasonCodes", + "resolutionState", + "localOnly", + "sourcePacketType" + ], + "properties": { + "reportId": { "type": "string", "maxLength": 96 }, + "rootfieldId": { "type": "string", "maxLength": 96 }, + "receiptId": { "type": "string", "maxLength": 96 }, + "verifierId": { "type": "string", "maxLength": 96 }, + "reportDigest": { "type": "string", "maxLength": 66 }, + "subjectDigest": { "type": "string", "maxLength": 66 }, + "status": { "type": "string", "enum": ["valid", "invalid", "unresolved", "stale"] }, + "reasonCodes": { "type": "array", "items": { "type": "string", "maxLength": 96 } }, + "resolutionState": { "type": "string", "enum": ["needs-full-report"] }, + "localOnly": { "type": "boolean", "enum": [true] }, + "sourcePacketType": { "type": "string", "enum": ["verifier_report_digest_relay"] } + } + } + }, + "artifactCommitments": { + "type": "array", + "items": { + "type": "object", + "required": ["artifactId", "rootfieldId", "commitment", "uriHint", "status", "localOnly", "sourcePacketType"], + "properties": { + "artifactId": { "type": "string", "maxLength": 96 }, + "rootfieldId": { "type": "string", "maxLength": 96 }, + "commitment": { "type": "string", "maxLength": 66 }, + "uriHint": { "type": "string", "maxLength": 128 }, + "status": { "type": "string", "enum": ["observed", "pending", "verified", "failed"] }, + "localOnly": { "type": "boolean", "enum": [true] }, + "sourcePacketType": { "type": "string", "enum": ["nfc_memory_cartridge_metadata"] } + } + } + }, + "memoryCells": { + "type": "array", + "items": { + "type": "object", + "required": ["memoryCellId", "rootfieldId", "latestRoot", "receiptId", "artifactId", "status", "localOnly", "sourcePacketType"], + "properties": { + "memoryCellId": { "type": "string", "maxLength": 96 }, + "rootfieldId": { "type": "string", "maxLength": 96 }, + "latestRoot": { "type": "string", "maxLength": 66 }, + "receiptId": { "type": "string", "maxLength": 96 }, + "artifactId": { "type": "string", "maxLength": 96 }, + "status": { "type": "string", "enum": ["observed", "pending", "verified", "failed"] }, + "localOnly": { "type": "boolean", "enum": [true] }, + "sourcePacketType": { "type": "string", "enum": ["nfc_memory_cartridge_metadata"] } + } + } + }, + "challenges": { + "type": "array", + "items": { + "type": "object", + "required": ["challengeId", "targetId", "receiptId", "reportId", "openedBy", "status", "summary", "doesNotExecuteRemoteAction", "localOnly", "sourcePacketType"], + "properties": { + "challengeId": { "type": "string", "maxLength": 96 }, + "targetId": { "type": "string", "maxLength": 96 }, + "receiptId": { "type": "string", "maxLength": 96 }, + "reportId": { "type": "string", "maxLength": 96 }, + "openedBy": { "type": "string", "maxLength": 96 }, + "status": { "type": "string", "enum": ["pending"] }, + "summary": { "type": "string", "maxLength": 180 }, + "doesNotExecuteRemoteAction": { "type": "boolean", "enum": [true] }, + "localOnly": { "type": "boolean", "enum": [true] }, + "sourcePacketType": { "type": "string", "enum": ["emergency_offline_signal"] } + } + } + }, + "finalityReceipts": { + "type": "array", + "items": { + "type": "object", + "required": ["finalityReceiptId", "objectId", "receiptId", "rootfieldId", "finalityStatus", "settlement", "status", "localOnly", "sourcePacketType"], + "properties": { + "finalityReceiptId": { "type": "string", "maxLength": 96 }, + "objectId": { "type": "string", "maxLength": 96 }, + "receiptId": { "type": "string", "maxLength": 96 }, + "rootfieldId": { "type": "string", "maxLength": 96 }, + "finalityStatus": { "type": "string", "enum": ["local-pending"] }, + "settlement": { "type": "string", "enum": ["local-fixture"] }, + "status": { "type": "string", "enum": ["pending"] }, + "localOnly": { "type": "boolean", "enum": [true] }, + "sourcePacketType": { "type": "string", "enum": ["compact_receipt_relay"] } + } + } + }, + "alerts": { + "type": "array", + "items": { + "type": "object", + "required": ["id", "incidentId", "severity", "title", "summary", "openedAt", "linkedObjectIds", "recommendedAction", "status", "localOnly", "sourcePacketType"], + "properties": { + "id": { "type": "string", "maxLength": 96 }, + "incidentId": { "type": "string", "maxLength": 96 }, + "severity": { "type": "string", "enum": ["info", "warning", "critical"] }, + "title": { "type": "string", "maxLength": 96 }, + "summary": { "type": "string", "maxLength": 180 }, + "openedAt": { "type": "string" }, + "linkedObjectIds": { "type": "array", "items": { "type": "string", "maxLength": 96 } }, + "recommendedAction": { "type": "string", "maxLength": 96 }, + "status": { "type": "string", "enum": ["unresolved", "pending", "verified", "failed"] }, + "localOnly": { "type": "boolean", "enum": [true] }, + "sourcePacketType": { "type": "string", "enum": ["emergency_offline_signal"] } + } + } + }, + "workbenchRecords": { + "type": "object", + "additionalProperties": false, + "required": ["receipts", "verifierReports", "artifacts", "memoryCells", "challenges", "hardwareSignals", "provenance"], + "properties": { + "receipts": { "type": "array", "items": { "type": "object" } }, + "verifierReports": { "type": "array", "items": { "type": "object" } }, + "artifacts": { "type": "array", "items": { "type": "object" } }, + "memoryCells": { "type": "array", "items": { "type": "object" } }, + "challenges": { "type": "array", "items": { "type": "object" } }, + "hardwareSignals": { "type": "array", "items": { "type": "object" } }, + "provenance": { "type": "array", "items": { "type": "object" } } + } + }, + "compatibility": { + "type": "object", + "additionalProperties": false, + "required": ["controlPlaneStateKeys", "workbenchSectionKeys", "jsonRpcBoundary"], + "properties": { + "controlPlaneStateKeys": { "type": "array", "items": { "type": "string", "maxLength": 64 } }, + "workbenchSectionKeys": { "type": "array", "items": { "type": "string", "maxLength": 64 } }, + "jsonRpcBoundary": { "type": "string", "maxLength": 160 } + } + } + } +}