From a17834493c3c1cece33e3ece5d4aee47a519456b Mon Sep 17 00:00:00 2001 From: FlowMemory Bootstrap Agent Date: Wed, 13 May 2026 00:55:58 -0500 Subject: [PATCH 1/2] Build FlowMemory dashboard V0 - add fixture-backed Vite React dashboard app - add dashboard V0 fixture data and sync path - document MVP scope, run commands, and future generated fixture boundary --- apps/dashboard/.gitignore | 8 + apps/dashboard/README.md | 78 + apps/dashboard/index.html | 17 + apps/dashboard/package-lock.json | 1486 +++++++++++++++++ apps/dashboard/package.json | 27 + .../public/data/flowmemory-dashboard-v0.json | 802 +++++++++ apps/dashboard/scripts/sync-fixtures.mjs | 15 + apps/dashboard/src/App.tsx | 102 ++ apps/dashboard/src/components/AppShell.tsx | 87 + apps/dashboard/src/components/EmptyState.tsx | 19 + apps/dashboard/src/components/HashValue.tsx | 24 + .../src/components/ProvenanceLine.tsx | 42 + .../src/components/SectionHeader.tsx | 22 + apps/dashboard/src/components/StatusBadge.tsx | 17 + apps/dashboard/src/data/format.ts | 21 + apps/dashboard/src/data/loadDashboardData.ts | 49 + apps/dashboard/src/data/selectors.ts | 107 ++ apps/dashboard/src/data/status.ts | 49 + apps/dashboard/src/data/types.ts | 183 ++ apps/dashboard/src/main.tsx | 14 + apps/dashboard/src/styles.css | 891 ++++++++++ apps/dashboard/src/test/dashboardData.test.ts | 61 + apps/dashboard/src/views/AlertsView.tsx | 72 + apps/dashboard/src/views/DevnetBlocksView.tsx | 100 ++ .../src/views/FlowPulseStreamView.tsx | 123 ++ .../dashboard/src/views/HardwareNodesView.tsx | 92 + apps/dashboard/src/views/OverviewView.tsx | 167 ++ .../src/views/RawJsonInspectorView.tsx | 58 + apps/dashboard/src/views/RootfieldsView.tsx | 94 ++ .../src/views/VerifierReportsView.tsx | 116 ++ apps/dashboard/src/views/WorkReceiptsView.tsx | 122 ++ apps/dashboard/tsconfig.json | 23 + apps/dashboard/vite.config.ts | 10 + docs/DASHBOARD_MVP.md | 80 + .../dashboard/flowmemory-dashboard-v0.json | 802 +++++++++ 35 files changed, 5980 insertions(+) create mode 100644 apps/dashboard/.gitignore create mode 100644 apps/dashboard/README.md create mode 100644 apps/dashboard/index.html create mode 100644 apps/dashboard/package-lock.json create mode 100644 apps/dashboard/package.json create mode 100644 apps/dashboard/public/data/flowmemory-dashboard-v0.json create mode 100644 apps/dashboard/scripts/sync-fixtures.mjs create mode 100644 apps/dashboard/src/App.tsx create mode 100644 apps/dashboard/src/components/AppShell.tsx create mode 100644 apps/dashboard/src/components/EmptyState.tsx create mode 100644 apps/dashboard/src/components/HashValue.tsx create mode 100644 apps/dashboard/src/components/ProvenanceLine.tsx create mode 100644 apps/dashboard/src/components/SectionHeader.tsx create mode 100644 apps/dashboard/src/components/StatusBadge.tsx create mode 100644 apps/dashboard/src/data/format.ts create mode 100644 apps/dashboard/src/data/loadDashboardData.ts create mode 100644 apps/dashboard/src/data/selectors.ts create mode 100644 apps/dashboard/src/data/status.ts create mode 100644 apps/dashboard/src/data/types.ts create mode 100644 apps/dashboard/src/main.tsx create mode 100644 apps/dashboard/src/styles.css create mode 100644 apps/dashboard/src/test/dashboardData.test.ts create mode 100644 apps/dashboard/src/views/AlertsView.tsx create mode 100644 apps/dashboard/src/views/DevnetBlocksView.tsx create mode 100644 apps/dashboard/src/views/FlowPulseStreamView.tsx create mode 100644 apps/dashboard/src/views/HardwareNodesView.tsx create mode 100644 apps/dashboard/src/views/OverviewView.tsx create mode 100644 apps/dashboard/src/views/RawJsonInspectorView.tsx create mode 100644 apps/dashboard/src/views/RootfieldsView.tsx create mode 100644 apps/dashboard/src/views/VerifierReportsView.tsx create mode 100644 apps/dashboard/src/views/WorkReceiptsView.tsx create mode 100644 apps/dashboard/tsconfig.json create mode 100644 apps/dashboard/vite.config.ts create mode 100644 docs/DASHBOARD_MVP.md create mode 100644 fixtures/dashboard/flowmemory-dashboard-v0.json diff --git a/apps/dashboard/.gitignore b/apps/dashboard/.gitignore new file mode 100644 index 00000000..361bf2de --- /dev/null +++ b/apps/dashboard/.gitignore @@ -0,0 +1,8 @@ +node_modules/ +dist/ +.vite/ +coverage/ +*.tsbuildinfo +.vite-dev.*.log +tmp-screenshots/ +tmp-chrome-profile/ diff --git a/apps/dashboard/README.md b/apps/dashboard/README.md new file mode 100644 index 00000000..f528e45b --- /dev/null +++ b/apps/dashboard/README.md @@ -0,0 +1,78 @@ +# FlowMemory Dashboard V0 + +Local operator/explorer app for inspecting FlowMemory V0 fixture output. It is intentionally fixture-backed and does not claim production live data, wallet support, token pricing, or hosted deployment. + +## Run Locally + +From this directory: + +```powershell +npm install +npm run dev +``` + +Default Vite URL: + +```text +http://127.0.0.1:5173/ +``` + +Useful checks: + +```powershell +npm run typecheck +npm test +npm run build +``` + +## Data Boundary + +The canonical dashboard fixture lives at: + +```text +fixtures/dashboard/flowmemory-dashboard-v0.json +``` + +The app loads its runtime copy from: + +```text +apps/dashboard/public/data/flowmemory-dashboard-v0.json +``` + +The `dev` and `build` scripts run `npm run sync:fixtures`, which copies the canonical fixture into the Vite public data folder before the app starts or builds. + +Future generated local outputs should land under the fixture boundary first: + +```text +fixtures/dashboard/generated/indexer-state.json +fixtures/dashboard/generated/verifier-reports.json +fixtures/dashboard/generated/devnet-state.json +fixtures/dashboard/generated/hardware-heartbeats.json +``` + +The dashboard schema can then be updated to merge those generated files into `flowmemory-dashboard-v0.json` or replace the loader with a local API once that boundary exists. + +## Current Views + +- Overview +- FlowPulse stream +- Rootfields +- Work lanes and receipts +- Verifier reports +- Devnet blocks +- Hardware nodes +- Alerts +- Raw JSON inspector + +Every displayed record carries source subsystem, fixture/local origin, chain context, ID/hash, status, and last-updated metadata when available. + +## Status Vocabulary + +Dashboard V0 visually distinguishes: + +```text +observed, pending, finalized, verified, unresolved, invalid, unsupported, reorged, offline, stale +``` + +These are app-facing display states for local fixture inspection. They should stay aligned with indexer and verifier terminology as those packages mature. + diff --git a/apps/dashboard/index.html b/apps/dashboard/index.html new file mode 100644 index 00000000..cd503264 --- /dev/null +++ b/apps/dashboard/index.html @@ -0,0 +1,17 @@ + + + + + + + FlowMemory Dashboard V0 + + +
+ + + + diff --git a/apps/dashboard/package-lock.json b/apps/dashboard/package-lock.json new file mode 100644 index 00000000..684afda4 --- /dev/null +++ b/apps/dashboard/package-lock.json @@ -0,0 +1,1486 @@ +{ + "name": "@flowmemory/dashboard", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@flowmemory/dashboard", + "version": "0.0.0", + "dependencies": { + "lucide-react": "^0.468.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.0" + }, + "devDependencies": { + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", + "@vitejs/plugin-react": "^6.0.1", + "typescript": "^5.6.3", + "vite": "^8.0.12", + "vitest": "^4.1.6" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.129.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.129.0.tgz", + "integrity": "sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz", + "integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0.tgz", + "integrity": "sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0.tgz", + "integrity": "sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0.tgz", + "integrity": "sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0.tgz", + "integrity": "sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0.tgz", + "integrity": "sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0.tgz", + "integrity": "sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0.tgz", + "integrity": "sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0.tgz", + "integrity": "sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0.tgz", + "integrity": "sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0.tgz", + "integrity": "sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0.tgz", + "integrity": "sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0.tgz", + "integrity": "sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0.tgz", + "integrity": "sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0.tgz", + "integrity": "sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0.tgz", + "integrity": "sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.7" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.6.tgz", + "integrity": "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.6", + "@vitest/utils": "4.1.6", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.6.tgz", + "integrity": "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.6.tgz", + "integrity": "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.6.tgz", + "integrity": "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.6", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.6.tgz", + "integrity": "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.6", + "@vitest/utils": "4.1.6", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.6.tgz", + "integrity": "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.6.tgz", + "integrity": "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.6", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lucide-react": { + "version": "0.468.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.468.0.tgz", + "integrity": "sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-router": { + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz", + "integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz", + "integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.2", + "react-router": "6.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/rolldown": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0.tgz", + "integrity": "sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.129.0", + "@rolldown/pluginutils": "1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0", + "@rolldown/binding-darwin-arm64": "1.0.0", + "@rolldown/binding-darwin-x64": "1.0.0", + "@rolldown/binding-freebsd-x64": "1.0.0", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0", + "@rolldown/binding-linux-arm64-gnu": "1.0.0", + "@rolldown/binding-linux-arm64-musl": "1.0.0", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0", + "@rolldown/binding-linux-s390x-gnu": "1.0.0", + "@rolldown/binding-linux-x64-gnu": "1.0.0", + "@rolldown/binding-linux-x64-musl": "1.0.0", + "@rolldown/binding-openharmony-arm64": "1.0.0", + "@rolldown/binding-wasm32-wasi": "1.0.0", + "@rolldown/binding-win32-arm64-msvc": "1.0.0", + "@rolldown/binding-win32-x64-msvc": "1.0.0" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0.tgz", + "integrity": "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", + "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "8.0.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.12.tgz", + "integrity": "sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.14", + "rolldown": "1.0.0", + "tinyglobby": "^0.2.16" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.6.tgz", + "integrity": "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.6", + "@vitest/mocker": "4.1.6", + "@vitest/pretty-format": "4.1.6", + "@vitest/runner": "4.1.6", + "@vitest/snapshot": "4.1.6", + "@vitest/spy": "4.1.6", + "@vitest/utils": "4.1.6", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.6", + "@vitest/browser-preview": "4.1.6", + "@vitest/browser-webdriverio": "4.1.6", + "@vitest/coverage-istanbul": "4.1.6", + "@vitest/coverage-v8": "4.1.6", + "@vitest/ui": "4.1.6", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json new file mode 100644 index 00000000..cda2a83a --- /dev/null +++ b/apps/dashboard/package.json @@ -0,0 +1,27 @@ +{ + "name": "@flowmemory/dashboard", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "npm run sync:fixtures && vite --host 127.0.0.1", + "build": "npm run sync:fixtures && tsc -b && vite build", + "test": "vitest run", + "typecheck": "tsc -b", + "sync:fixtures": "node scripts/sync-fixtures.mjs" + }, + "dependencies": { + "lucide-react": "^0.468.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.0" + }, + "devDependencies": { + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", + "@vitejs/plugin-react": "^6.0.1", + "typescript": "^5.6.3", + "vite": "^8.0.12", + "vitest": "^4.1.6" + } +} diff --git a/apps/dashboard/public/data/flowmemory-dashboard-v0.json b/apps/dashboard/public/data/flowmemory-dashboard-v0.json new file mode 100644 index 00000000..dcd99f4b --- /dev/null +++ b/apps/dashboard/public/data/flowmemory-dashboard-v0.json @@ -0,0 +1,802 @@ +{ + "metadata": { + "schema": "flowmemory.dashboard.fixture.v0", + "generatedAt": "2026-05-13T16:00:00.000Z", + "mode": "fixture", + "description": "Synthetic local FlowMemory Dashboard V0 fixture. Values are operator/explorer test vectors only and do not claim live production data.", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "runtimeDataPath": "apps/dashboard/public/data/flowmemory-dashboard-v0.json", + "futureGeneratedPaths": { + "indexer": "fixtures/dashboard/generated/indexer-state.json", + "verifier": "fixtures/dashboard/generated/verifier-reports.json", + "devnet": "fixtures/dashboard/generated/devnet-state.json", + "hardware": "fixtures/dashboard/generated/hardware-heartbeats.json" + } + }, + "chain": { + "chainId": "31337", + "name": "Anvil local FlowMemory devnet", + "environment": "local-devnet", + "settlementContext": "Base-first project path; this fixture is not Base mainnet or Base Sepolia data.", + "currentBlock": 123482, + "finalizedBlock": 123450, + "source": "fixture", + "lastUpdated": "2026-05-13T15:58:42.000Z" + }, + "flowPulseObservations": [ + { + "id": "0x9717b7bad57bd0fa089e672e75cede4ae0bf3c86321dc0525ba00e9e0cc2da91", + "observationId": "0x9717b7bad57bd0fa089e672e75cede4ae0bf3c86321dc0525ba00e9e0cc2da91", + "pulseId": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123456", + "blockHash": "0x2222222222222222222222222222222222222222222222222222222222222222", + "txHash": "0x3333333333333333333333333333333333333333333333333333333333333333", + "transactionIndex": "7", + "logIndex": "2", + "receiptStatus": "success", + "actor": "0x4444444444444444444444444444444444444444", + "pulseType": "1", + "subject": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "commitment": "0x4122209ff672fc04b2ec3af31ab1af79813971f86de000aa6534038cc79de6b5", + "parentPulseId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "sequence": "1", + "occurredAt": "2026-05-13T14:30:00.000Z", + "uri": "ipfs://bafy-flowmemory-example", + "summary": "Rootfield registration observed from fixture receipt log.", + "status": "finalized", + "lastUpdated": "2026-05-13T15:51:00.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:51:00.000Z", + "localPathHint": "services/indexer/fixtures/flowpulse-logs.json" + } + }, + { + "id": "0x2ad24d8e9df0a17f1f6a6427c1ea3b401dc2f16d9a5bb64c3c96206cb3f5e712", + "observationId": "0x2ad24d8e9df0a17f1f6a6427c1ea3b401dc2f16d9a5bb64c3c96206cb3f5e712", + "pulseId": "0xa3f9000000000000000000000000000000000000000000000000000000000112", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123468", + "blockHash": "0x2468246824682468246824682468246824682468246824682468246824682468", + "txHash": "0x5301530153015301530153015301530153015301530153015301530153015301", + "transactionIndex": "3", + "logIndex": "0", + "receiptStatus": "success", + "actor": "0x5555555555555555555555555555555555555555", + "pulseType": "2", + "subject": "0x6f6d65706174682d726f6f742d303030303030303030303030303030303031", + "commitment": "0x81d30d3de2b29b44f23745289dbf214026ed1789983ff7aac135d74531402031", + "parentPulseId": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "sequence": "2", + "occurredAt": "2026-05-13T14:42:25.000Z", + "uri": "file://fixtures/rootfields/omega-path/root-0001.json", + "summary": "Root commitment finalized after local block threshold.", + "status": "finalized", + "lastUpdated": "2026-05-13T15:53:12.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:53:12.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "observationId": "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "pulseId": "0xa3f9000000000000000000000000000000000000000000000000000000000113", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123481", + "blockHash": "0x9595959595959595959595959595959595959595959595959595959595959595", + "txHash": "0x6060606060606060606060606060606060606060606060606060606060606060", + "transactionIndex": "1", + "logIndex": "1", + "receiptStatus": "success", + "actor": "0x5555555555555555555555555555555555555555", + "pulseType": "2", + "subject": "0x6f6d65706174682d726f6f742d303030303030303030303030303030303032", + "commitment": "0x61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff", + "parentPulseId": "0xa3f9000000000000000000000000000000000000000000000000000000000112", + "sequence": "3", + "occurredAt": "2026-05-13T15:55:28.000Z", + "uri": "file://fixtures/rootfields/omega-path/root-0002.json", + "summary": "Recent root commitment observed below finality threshold.", + "status": "observed", + "lastUpdated": "2026-05-13T15:56:02.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:02.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "0x7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e", + "observationId": "0x7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e", + "pulseId": "0xc0ffee0000000000000000000000000000000000000000000000000000000417", + "rootfieldId": "0xdededededededededededededededededededededededededededededededede", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123449", + "blockHash": "0x1717171717171717171717171717171717171717171717171717171717171717", + "txHash": "0x1818181818181818181818181818181818181818181818181818181818181818", + "transactionIndex": "9", + "logIndex": "3", + "receiptStatus": "success", + "actor": "0x9999999999999999999999999999999999999999", + "pulseType": "9", + "subject": "0xdededededededededededededededededededededededededededededededede", + "commitment": "0x9090909090909090909090909090909090909090909090909090909090909090", + "parentPulseId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "sequence": "1", + "occurredAt": "2026-05-13T13:12:14.000Z", + "uri": "file://fixtures/rootfields/unsupported-pulse.json", + "summary": "Unsupported pulse type preserved for verifier policy review.", + "status": "unsupported", + "lastUpdated": "2026-05-13T15:18:00.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:18:00.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "0xabababababababababababababababababababababababababababababababab", + "observationId": "0xabababababababababababababababababababababababababababababababab", + "pulseId": "0xa3f90000000000000000000000000000000000000000000000000000000000ff", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123438", + "blockHash": "0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000", + "txHash": "0x4242424242424242424242424242424242424242424242424242424242424242", + "transactionIndex": "2", + "logIndex": "4", + "receiptStatus": "success", + "actor": "0x5555555555555555555555555555555555555555", + "pulseType": "2", + "subject": "0x72656f72672d726f6f742d3030303030303030303030303030303030303030", + "commitment": "0xe5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5", + "parentPulseId": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "sequence": "2", + "occurredAt": "2026-05-13T12:07:44.000Z", + "uri": "file://fixtures/rootfields/omega-path/reorged-root.json", + "summary": "Observation retained as noncanonical after local reorg fixture.", + "status": "reorged", + "lastUpdated": "2026-05-13T12:31:10.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T12:31:10.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", + "observationId": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", + "pulseId": "0x1212121212121212121212121212121212121212121212121212121212121212", + "rootfieldId": "0x3434343434343434343434343434343434343434343434343434343434343434", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123482", + "blockHash": "0xa1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1", + "txHash": "0xb1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1", + "transactionIndex": "0", + "logIndex": "0", + "receiptStatus": "unknown", + "actor": "0x7777777777777777777777777777777777777777", + "pulseType": "2", + "subject": "0x70656e64696e672d726f6f742d3030303030303030303030303030303030", + "commitment": "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "parentPulseId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "sequence": "0", + "occurredAt": "2026-05-13T15:58:20.000Z", + "uri": "file://fixtures/rootfields/pending-root.json", + "summary": "Pending candidate from local scan window before receipt finality.", + "status": "pending", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + } + ], + "rootfields": [ + { + "id": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "owner": "0x4444444444444444444444444444444444444444", + "schemaHash": "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "metadataHash": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "latestRoot": "0x6f6d65706174682d726f6f742d303030303030303030303030303030303032", + "latestObservationId": "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "pulseCount": 4, + "workLaneIds": ["lane-indexer-a", "lane-verifier-a"], + "evidenceUri": "file://fixtures/rootfields/omega-path/", + "status": "finalized", + "lastUpdated": "2026-05-13T15:56:02.000Z", + "provenance": { + "subsystem": "contracts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:02.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + }, + { + "id": "0xdededededededededededededededededededededededededededededededede", + "rootfieldId": "0xdededededededededededededededededededededededededededededededede", + "owner": "0x9999999999999999999999999999999999999999", + "schemaHash": "0x1919191919191919191919191919191919191919191919191919191919191919", + "metadataHash": "0x2929292929292929292929292929292929292929292929292929292929292929", + "latestRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestObservationId": "0x7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e", + "pulseCount": 1, + "workLaneIds": ["lane-verifier-b"], + "evidenceUri": "file://fixtures/rootfields/unsupported/", + "status": "stale", + "lastUpdated": "2026-05-13T15:18:00.000Z", + "provenance": { + "subsystem": "contracts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:18:00.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + }, + { + "id": "0x3434343434343434343434343434343434343434343434343434343434343434", + "rootfieldId": "0x3434343434343434343434343434343434343434343434343434343434343434", + "owner": "0x7777777777777777777777777777777777777777", + "schemaHash": "0x3838383838383838383838383838383838383838383838383838383838383838", + "metadataHash": "0x3939393939393939393939393939393939393939393939393939393939393939", + "latestRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestObservationId": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", + "pulseCount": 0, + "workLaneIds": ["lane-indexer-a"], + "evidenceUri": "file://fixtures/rootfields/pending-root.json", + "status": "pending", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "contracts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + } + ], + "workLanes": [ + { + "id": "lane-indexer-a", + "laneId": "lane-indexer-a", + "name": "Indexer receipt ingest", + "queueDepth": 3, + "inflight": 1, + "completed24h": 37, + "p95LatencyMs": 840, + "operator": "local-codex-fixture", + "status": "pending", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "lane-verifier-a", + "laneId": "lane-verifier-a", + "name": "Verifier policy v0", + "queueDepth": 1, + "inflight": 1, + "completed24h": 22, + "p95LatencyMs": 1280, + "operator": "local-codex-fixture", + "status": "observed", + "lastUpdated": "2026-05-13T15:56:37.000Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:37.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "lane-verifier-b", + "laneId": "lane-verifier-b", + "name": "Unsupported pulse review", + "queueDepth": 0, + "inflight": 0, + "completed24h": 4, + "p95LatencyMs": 2120, + "operator": "local-codex-fixture", + "status": "stale", + "lastUpdated": "2026-05-13T15:19:05.000Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:19:05.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + } + ], + "workReceipts": [ + { + "id": "0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", + "receiptId": "0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", + "laneId": "lane-verifier-a", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "observationId": "0x2ad24d8e9df0a17f1f6a6427c1ea3b401dc2f16d9a5bb64c3c96206cb3f5e712", + "reportId": "0x8080808080808080808080808080808080808080808080808080808080808080", + "workType": "verify-root-commitment", + "artifactUri": "file://fixtures/rootfields/omega-path/root-0001.json", + "startedAt": "2026-05-13T14:43:00.000Z", + "completedAt": "2026-05-13T14:43:01.120Z", + "resultHash": "0x7100710071007100710071007100710071007100710071007100710071007100", + "status": "verified", + "lastUpdated": "2026-05-13T14:43:01.120Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T14:43:01.120Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x0101010101010101010101010101010101010101010101010101010101010101", + "receiptId": "0x0101010101010101010101010101010101010101010101010101010101010101", + "laneId": "lane-indexer-a", + "rootfieldId": "0x3434343434343434343434343434343434343434343434343434343434343434", + "observationId": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", + "workType": "scan-receipt-window", + "artifactUri": "file://fixtures/devnet/block-123482.json", + "startedAt": "2026-05-13T15:58:20.000Z", + "resultHash": "0x1111110000001111110000001111110000001111110000001111110000001111", + "status": "pending", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "0x5656565656565656565656565656565656565656565656565656565656565656", + "receiptId": "0x5656565656565656565656565656565656565656565656565656565656565656", + "laneId": "lane-verifier-a", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "observationId": "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "reportId": "0x5959595959595959595959595959595959595959595959595959595959595959", + "workType": "verify-root-commitment", + "artifactUri": "file://fixtures/rootfields/omega-path/root-0002.json", + "startedAt": "2026-05-13T15:56:04.000Z", + "completedAt": "2026-05-13T15:56:04.640Z", + "resultHash": "0x6161616161616161616161616161616161616161616161616161616161616161", + "status": "invalid", + "lastUpdated": "2026-05-13T15:56:04.640Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:04.640Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + } + ], + "verifierReports": [ + { + "id": "0xe0ac708c933782ef6797b3ab4b6550cdd1a993fb1170361e5e05641ab801e66e", + "reportId": "0xe0ac708c933782ef6797b3ab4b6550cdd1a993fb1170361e5e05641ab801e66e", + "observationId": "0x9717b7bad57bd0fa089e672e75cede4ae0bf3c86321dc0525ba00e9e0cc2da91", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 3, + "checksTotal": 3, + "reasonCodes": [], + "reportHash": "0xe0ac708c933782ef6797b3ab4b6550cdd1a993fb1170361e5e05641ab801e66e", + "status": "verified", + "lastUpdated": "2026-05-13T15:51:31.000Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:51:31.000Z", + "localPathHint": "services/verifier/fixtures/artifacts.json" + } + }, + { + "id": "0x8080808080808080808080808080808080808080808080808080808080808080", + "reportId": "0x8080808080808080808080808080808080808080808080808080808080808080", + "observationId": "0x2ad24d8e9df0a17f1f6a6427c1ea3b401dc2f16d9a5bb64c3c96206cb3f5e712", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 4, + "checksTotal": 4, + "reasonCodes": [], + "reportHash": "0x8080808080808080808080808080808080808080808080808080808080808080", + "status": "verified", + "lastUpdated": "2026-05-13T14:43:01.120Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T14:43:01.120Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x5959595959595959595959595959595959595959595959595959595959595959", + "reportId": "0x5959595959595959595959595959595959595959595959595959595959595959", + "observationId": "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 3, + "checksTotal": 4, + "reasonCodes": ["commitment.mismatch"], + "reportHash": "0x5959595959595959595959595959595959595959595959595959595959595959", + "status": "invalid", + "lastUpdated": "2026-05-13T15:56:04.640Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:04.640Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x6464646464646464646464646464646464646464646464646464646464646464", + "reportId": "0x6464646464646464646464646464646464646464646464646464646464646464", + "observationId": "0x7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e", + "rootfieldId": "0xdededededededededededededededededededededededededededededededede", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 1, + "checksTotal": 1, + "reasonCodes": ["pulse.type.unsupported"], + "reportHash": "0x6464646464646464646464646464646464646464646464646464646464646464", + "status": "unsupported", + "lastUpdated": "2026-05-13T15:18:11.000Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:18:11.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x7373737373737373737373737373737373737373737373737373737373737373", + "reportId": "0x7373737373737373737373737373737373737373737373737373737373737373", + "observationId": "0xabababababababababababababababababababababababababababababababab", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 1, + "checksTotal": 1, + "reasonCodes": ["observation.reorged"], + "reportHash": "0x7373737373737373737373737373737373737373737373737373737373737373", + "status": "reorged", + "lastUpdated": "2026-05-13T12:31:15.000Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T12:31:15.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x7474747474747474747474747474747474747474747474747474747474747474", + "reportId": "0x7474747474747474747474747474747474747474747474747474747474747474", + "observationId": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", + "rootfieldId": "0x3434343434343434343434343434343434343434343434343434343434343434", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 1, + "checksTotal": 2, + "reasonCodes": ["artifact.unavailable"], + "reportHash": "0x7474747474747474747474747474747474747474747474747474747474747474", + "status": "unresolved", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x7575757575757575757575757575757575757575757575757575757575757575", + "reportId": "0x7575757575757575757575757575757575757575757575757575757575757575", + "observationId": "0x2ad24d8e9df0a17f1f6a6427c1ea3b401dc2f16d9a5bb64c3c96206cb3f5e712", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "resolverPolicyId": "flowmemory.resolver.policy.v0.previous-fixture", + "verifierSpecVersion": "0", + "checksPassed": 2, + "checksTotal": 4, + "reasonCodes": ["report.stale_policy"], + "reportHash": "0x7575757575757575757575757575757575757575757575757575757575757575", + "status": "stale", + "lastUpdated": "2026-05-13T14:12:00.000Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T14:12:00.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + } + ], + "devnetBlocks": [ + { + "id": "0x1717171717171717171717171717171717171717171717171717171717171717", + "blockNumber": 123449, + "blockHash": "0x1717171717171717171717171717171717171717171717171717171717171717", + "parentHash": "0x1616161616161616161616161616161616161616161616161616161616161616", + "stateRoot": "0x5050505050505050505050505050505050505050505050505050505050505050", + "receiptsRoot": "0x5151515151515151515151515151515151515151515151515151515151515151", + "timestamp": "2026-05-13T13:12:14.000Z", + "observationCount": 1, + "reportCount": 1, + "finalityDistance": 33, + "status": "finalized", + "lastUpdated": "2026-05-13T15:45:00.000Z", + "provenance": { + "subsystem": "devnet", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:45:00.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + }, + { + "id": "0x2468246824682468246824682468246824682468246824682468246824682468", + "blockNumber": 123468, + "blockHash": "0x2468246824682468246824682468246824682468246824682468246824682468", + "parentHash": "0x2358235823582358235823582358235823582358235823582358235823582358", + "stateRoot": "0x6262626262626262626262626262626262626262626262626262626262626262", + "receiptsRoot": "0x6363636363636363636363636363636363636363636363636363636363636363", + "timestamp": "2026-05-13T14:42:25.000Z", + "observationCount": 1, + "reportCount": 1, + "finalityDistance": 14, + "status": "finalized", + "lastUpdated": "2026-05-13T15:45:00.000Z", + "provenance": { + "subsystem": "devnet", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:45:00.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + }, + { + "id": "0x9595959595959595959595959595959595959595959595959595959595959595", + "blockNumber": 123481, + "blockHash": "0x9595959595959595959595959595959595959595959595959595959595959595", + "parentHash": "0x9494949494949494949494949494949494949494949494949494949494949494", + "stateRoot": "0x7070707070707070707070707070707070707070707070707070707070707070", + "receiptsRoot": "0x7171717171717171717171717171717171717171717171717171717171717171", + "timestamp": "2026-05-13T15:55:28.000Z", + "observationCount": 1, + "reportCount": 1, + "finalityDistance": 1, + "status": "pending", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "devnet", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + }, + { + "id": "0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000", + "blockNumber": 123438, + "blockHash": "0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000", + "parentHash": "0x4343434343434343434343434343434343434343434343434343434343434343", + "stateRoot": "0x8888000088880000888800008888000088880000888800008888000088880000", + "receiptsRoot": "0x9999000099990000999900009999000099990000999900009999000099990000", + "timestamp": "2026-05-13T12:07:44.000Z", + "observationCount": 1, + "reportCount": 1, + "finalityDistance": 0, + "status": "reorged", + "lastUpdated": "2026-05-13T12:31:10.000Z", + "provenance": { + "subsystem": "devnet", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T12:31:10.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + } + ], + "hardwareNodes": [ + { + "id": "fm-node-lab-01", + "nodeId": "fm-node-lab-01", + "callsign": "Lab Gateway 01", + "role": "gateway", + "firmware": "flowrouter-v0.1.0-fixture", + "transport": "ethernet + meshtastic sidecar", + "lastHeartbeatAt": "2026-05-13T15:57:58.000Z", + "batteryPercent": 100, + "signalDbm": -51, + "temperatureC": 39, + "linkedWorkLaneId": "lane-indexer-a", + "locationHint": "bench-east", + "status": "observed", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "hardware", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/hardware-heartbeats.json" + } + }, + { + "id": "fm-node-router-03", + "nodeId": "fm-node-router-03", + "callsign": "Router Shelf 03", + "role": "router", + "firmware": "flowrouter-v0.1.0-fixture", + "transport": "wifi + lora control", + "lastHeartbeatAt": "2026-05-13T15:11:08.000Z", + "batteryPercent": 72, + "signalDbm": -88, + "temperatureC": 44, + "linkedWorkLaneId": "lane-verifier-b", + "locationHint": "workshop-shelf", + "status": "stale", + "lastUpdated": "2026-05-13T15:11:08.000Z", + "provenance": { + "subsystem": "hardware", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:11:08.000Z", + "localPathHint": "fixtures/dashboard/generated/hardware-heartbeats.json" + } + }, + { + "id": "fm-node-field-07", + "nodeId": "fm-node-field-07", + "callsign": "Field Kit 07", + "role": "field-kit", + "firmware": "flowrouter-v0.1.0-fixture", + "transport": "meshtastic control only", + "locationHint": "packed-case", + "status": "offline", + "lastUpdated": "2026-05-13T14:20:00.000Z", + "provenance": { + "subsystem": "hardware", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T14:20:00.000Z", + "localPathHint": "fixtures/dashboard/generated/hardware-heartbeats.json" + } + } + ], + "alerts": [ + { + "id": "incident-2026-05-13-001", + "incidentId": "incident-2026-05-13-001", + "severity": "critical", + "title": "Verifier commitment mismatch", + "summary": "Report 0x5959 records a deterministic commitment mismatch for the latest omega-path root fixture.", + "openedAt": "2026-05-13T15:56:04.640Z", + "linkedObjectIds": [ + "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "0x5959595959595959595959595959595959595959595959595959595959595959" + ], + "recommendedAction": "Compare the generated root artifact with the emitted commitment before promoting this fixture to verified.", + "status": "unresolved", + "lastUpdated": "2026-05-13T15:56:04.640Z", + "provenance": { + "subsystem": "alerts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:04.640Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "incident-2026-05-13-002", + "incidentId": "incident-2026-05-13-002", + "severity": "warning", + "title": "Hardware heartbeat stale", + "summary": "Router Shelf 03 has not reported a fresh heartbeat inside the fixture freshness window.", + "openedAt": "2026-05-13T15:41:00.000Z", + "linkedObjectIds": ["fm-node-router-03", "lane-verifier-b"], + "recommendedAction": "Check local power and radio sidecar telemetry before assigning verifier work to the node.", + "status": "stale", + "lastUpdated": "2026-05-13T15:41:00.000Z", + "provenance": { + "subsystem": "alerts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:41:00.000Z", + "localPathHint": "fixtures/dashboard/generated/hardware-heartbeats.json" + } + }, + { + "id": "incident-2026-05-13-003", + "incidentId": "incident-2026-05-13-003", + "severity": "info", + "title": "Reorg replacement recorded", + "summary": "A noncanonical block and observation remain in the fixture so the explorer can show reorg history.", + "openedAt": "2026-05-13T12:31:10.000Z", + "linkedObjectIds": [ + "0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000", + "0xabababababababababababababababababababababababababababababababab" + ], + "recommendedAction": "Keep the reorged records visible, but exclude them from current verified root summaries.", + "status": "verified", + "lastUpdated": "2026-05-13T13:02:00.000Z", + "provenance": { + "subsystem": "alerts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T13:02:00.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + } + ] +} diff --git a/apps/dashboard/scripts/sync-fixtures.mjs b/apps/dashboard/scripts/sync-fixtures.mjs new file mode 100644 index 00000000..3db1ff2d --- /dev/null +++ b/apps/dashboard/scripts/sync-fixtures.mjs @@ -0,0 +1,15 @@ +import { copyFileSync, mkdirSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const scriptDir = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(scriptDir, "../../.."); +const source = resolve(repoRoot, "fixtures/dashboard/flowmemory-dashboard-v0.json"); +const destinationDir = resolve(repoRoot, "apps/dashboard/public/data"); +const destination = resolve(destinationDir, "flowmemory-dashboard-v0.json"); + +mkdirSync(destinationDir, { recursive: true }); +copyFileSync(source, destination); + +console.log(`Synced dashboard fixture: ${destination}`); + diff --git a/apps/dashboard/src/App.tsx b/apps/dashboard/src/App.tsx new file mode 100644 index 00000000..f802e015 --- /dev/null +++ b/apps/dashboard/src/App.tsx @@ -0,0 +1,102 @@ +import { useEffect, useState } from "react"; +import { Route, Routes } from "react-router-dom"; +import { AlertTriangle, RefreshCw } from "lucide-react"; +import { AppShell } from "./components/AppShell"; +import { fetchDashboardData } from "./data/loadDashboardData"; +import type { DashboardData } from "./data/types"; +import { AlertsView } from "./views/AlertsView"; +import { DevnetBlocksView } from "./views/DevnetBlocksView"; +import { FlowPulseStreamView } from "./views/FlowPulseStreamView"; +import { HardwareNodesView } from "./views/HardwareNodesView"; +import { OverviewView } from "./views/OverviewView"; +import { RawJsonInspectorView } from "./views/RawJsonInspectorView"; +import { RootfieldsView } from "./views/RootfieldsView"; +import { VerifierReportsView } from "./views/VerifierReportsView"; +import { WorkReceiptsView } from "./views/WorkReceiptsView"; + +function LoadingState() { + return ( +
+
+
+
+
+
+
+
+
+
+
+
+ ); +} + +function ErrorState({ message, onRetry }: { message: string; onRetry: () => void }) { + return ( +
+
+
+
+ ); +} + +export default function App() { + const [data, setData] = useState(null); + const [error, setError] = useState(null); + const [version, setVersion] = useState(0); + + useEffect(() => { + let cancelled = false; + + fetchDashboardData() + .then((nextData) => { + if (!cancelled) { + setData(nextData); + setError(null); + } + }) + .catch((nextError: unknown) => { + if (!cancelled) { + setError(nextError instanceof Error ? nextError.message : "Unknown fixture load error."); + } + }); + + return () => { + cancelled = true; + }; + }, [version]); + + if (error) { + return setVersion((current) => current + 1)} />; + } + + if (data === null) { + return ; + } + + return ( + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + + ); +} + diff --git a/apps/dashboard/src/components/AppShell.tsx b/apps/dashboard/src/components/AppShell.tsx new file mode 100644 index 00000000..3731ee30 --- /dev/null +++ b/apps/dashboard/src/components/AppShell.tsx @@ -0,0 +1,87 @@ +import type { ReactNode } from "react"; +import { NavLink } from "react-router-dom"; +import { + Activity, + Bell, + Binary, + Braces, + Boxes, + ClipboardCheck, + LayoutDashboard, + Network, + RadioTower, + ShieldCheck, +} from "lucide-react"; +import type { DashboardData } from "../data/types"; +import { StatusBadge } from "./StatusBadge"; + +interface AppShellProps { + data: DashboardData; + children: ReactNode; +} + +const NAV_ITEMS = [ + { to: "/", label: "Overview", icon: LayoutDashboard }, + { to: "/flowpulse", label: "FlowPulse", icon: Activity }, + { to: "/rootfields", label: "Rootfields", icon: Boxes }, + { to: "/work", label: "Work lanes", icon: ClipboardCheck }, + { to: "/verifier", label: "Verifier", icon: ShieldCheck }, + { to: "/devnet", label: "Devnet", icon: Network }, + { to: "/hardware", label: "Hardware", icon: RadioTower }, + { to: "/alerts", label: "Alerts", icon: Bell }, + { to: "/raw", label: "Raw JSON", icon: Braces }, +]; + +export function AppShell({ data, children }: AppShellProps) { + return ( +
+ + +
+
+
+ local operator surface +

{data.chain.name}

+
+
+ chain {data.chain.chainId} + {data.chain.source} + updated {new Date(data.chain.lastUpdated).toLocaleString()} +
+
+
+ Fixture/local data only. + + Runtime JSON is loaded from {data.metadata.runtimeDataPath}; future generated outputs should land in the + documented fixture boundary before becoming live APIs. + +
+
{children}
+
+
+ ); +} + diff --git a/apps/dashboard/src/components/EmptyState.tsx b/apps/dashboard/src/components/EmptyState.tsx new file mode 100644 index 00000000..e496ee9b --- /dev/null +++ b/apps/dashboard/src/components/EmptyState.tsx @@ -0,0 +1,19 @@ +import { CircleDashed } from "lucide-react"; + +interface EmptyStateProps { + title: string; + detail: string; +} + +export function EmptyState({ title, detail }: EmptyStateProps) { + return ( +
+
+ ); +} + diff --git a/apps/dashboard/src/components/HashValue.tsx b/apps/dashboard/src/components/HashValue.tsx new file mode 100644 index 00000000..c77814fb --- /dev/null +++ b/apps/dashboard/src/components/HashValue.tsx @@ -0,0 +1,24 @@ +interface HashValueProps { + value: string; + label?: string; + trim?: "short" | "medium" | "none"; +} + +function formatHash(value: string, trim: HashValueProps["trim"]): string { + if (trim === "none" || value.length <= 18) { + return value; + } + + const head = trim === "short" ? 8 : 12; + const tail = trim === "short" ? 6 : 10; + return `${value.slice(0, head)}...${value.slice(-tail)}`; +} + +export function HashValue({ value, label, trim = "medium" }: HashValueProps) { + return ( + + {formatHash(value, trim)} + + ); +} + diff --git a/apps/dashboard/src/components/ProvenanceLine.tsx b/apps/dashboard/src/components/ProvenanceLine.tsx new file mode 100644 index 00000000..49f1d26d --- /dev/null +++ b/apps/dashboard/src/components/ProvenanceLine.tsx @@ -0,0 +1,42 @@ +import { Database, HardDrive, Radio, ServerCog } from "lucide-react"; +import type { Provenance } from "../data/types"; + +const ORIGIN_LABELS: Record = { + fixture: "fixture", + local: "local", + live: "live", +}; + +function OriginIcon({ origin }: { origin: Provenance["origin"] }) { + if (origin === "fixture") { + return
+ ); +} + diff --git a/apps/dashboard/src/views/HardwareNodesView.tsx b/apps/dashboard/src/views/HardwareNodesView.tsx new file mode 100644 index 00000000..63a345c6 --- /dev/null +++ b/apps/dashboard/src/views/HardwareNodesView.tsx @@ -0,0 +1,92 @@ +import { useMemo, useState } from "react"; +import { Search } from "lucide-react"; +import { EmptyState } from "../components/EmptyState"; +import { ProvenanceLine } from "../components/ProvenanceLine"; +import { SectionHeader } from "../components/SectionHeader"; +import { StatusBadge } from "../components/StatusBadge"; +import { formatDateTime, formatPercent } from "../data/format"; +import { searchRecords } from "../data/selectors"; +import type { DashboardData } from "../data/types"; + +export function HardwareNodesView({ data }: { data: DashboardData }) { + const [query, setQuery] = useState(""); + const nodes = useMemo(() => searchRecords(data.hardwareNodes, query), [data.hardwareNodes, query]); + + return ( +
+ +
+ ); +} + diff --git a/apps/dashboard/src/views/OverviewView.tsx b/apps/dashboard/src/views/OverviewView.tsx new file mode 100644 index 00000000..9c58a43f --- /dev/null +++ b/apps/dashboard/src/views/OverviewView.tsx @@ -0,0 +1,167 @@ +import { AlertTriangle, Cpu, DatabaseZap, RadioTower } from "lucide-react"; +import { EmptyState } from "../components/EmptyState"; +import { HashValue } from "../components/HashValue"; +import { ProvenanceLine } from "../components/ProvenanceLine"; +import { SectionHeader } from "../components/SectionHeader"; +import { StatusBadge } from "../components/StatusBadge"; +import { formatDateTime } from "../data/format"; +import { + computeOverviewMetrics, + getHardwareRiskNodes, + getLatestBlocks, + getLatestFlowPulses, + getVerifierRiskReports, +} from "../data/selectors"; +import type { DashboardData } from "../data/types"; + +export function OverviewView({ data }: { data: DashboardData }) { + const metrics = computeOverviewMetrics(data); + const latestPulses = getLatestFlowPulses(data, 5); + const latestBlocks = getLatestBlocks(data, 4); + const verifierRisk = getVerifierRiskReports(data); + const hardwareRisk = getHardwareRiskNodes(data); + + return ( +
+ + +
+ {metrics.map((metric) => ( +
+ {metric.label} + {metric.value} +
+ + {metric.detail} +
+
+ ))} +
+ +
+
+
+
+
+ {data.flowPulseObservations.length} total +
+ {latestPulses.length > 0 ? ( +
+ {latestPulses.map((pulse) => ( +
+
+
+ + +
+

{pulse.summary}

+ +
+
+
+
block
+
{pulse.blockNumber}
+
+
+
sequence
+
{pulse.sequence}
+
+
+
tx
+
+ +
+
+
+
+ ))} +
+ ) : ( + + )} +
+ +
+
+
+
+ {verifierRisk.length} reports +
+ {verifierRisk.length > 0 ? ( +
+ {verifierRisk.map((report) => ( +
+ +
+ + + + {report.reasonCodes.join(", ") || "no reason code"} +
+
+ ))} +
+ ) : ( + + )} +
+ +
+
+
+
+ {hardwareRisk.length} nodes +
+ {hardwareRisk.length > 0 ? ( +
+ {hardwareRisk.map((node) => ( +
+ +
+ {node.callsign} + {node.lastHeartbeatAt ? formatDateTime(node.lastHeartbeatAt) : "no heartbeat"} +
+
+ ))} +
+ ) : ( + + )} +
+ +
+
+
+
+ {data.chain.finalizedBlock} finalized +
+
+ {latestBlocks.map((block) => ( +
+ + {block.blockNumber} + + + + {block.observationCount} observations +
+ ))} +
+
+
+
+ ); +} + diff --git a/apps/dashboard/src/views/RawJsonInspectorView.tsx b/apps/dashboard/src/views/RawJsonInspectorView.tsx new file mode 100644 index 00000000..b10d0646 --- /dev/null +++ b/apps/dashboard/src/views/RawJsonInspectorView.tsx @@ -0,0 +1,58 @@ +import { useMemo, useState } from "react"; +import { Braces } from "lucide-react"; +import { SectionHeader } from "../components/SectionHeader"; +import type { DashboardData } from "../data/types"; + +const DATASET_LABELS = [ + "all", + "metadata", + "chain", + "flowPulseObservations", + "rootfields", + "workLanes", + "workReceipts", + "verifierReports", + "devnetBlocks", + "hardwareNodes", + "alerts", +] as const; + +type DatasetKey = (typeof DATASET_LABELS)[number]; + +export function RawJsonInspectorView({ data }: { data: DashboardData }) { + const [dataset, setDataset] = useState("all"); + + const rawJson = useMemo(() => { + const value = dataset === "all" ? data : data[dataset]; + return JSON.stringify(value, null, 2); + }, [data, dataset]); + + return ( +
+ setDataset(event.target.value as DatasetKey)}> + {DATASET_LABELS.map((label) => ( + + ))} + + } + /> + +
+
+
+
{rawJson}
+
+
+ ); +} + diff --git a/apps/dashboard/src/views/RootfieldsView.tsx b/apps/dashboard/src/views/RootfieldsView.tsx new file mode 100644 index 00000000..b86d3a25 --- /dev/null +++ b/apps/dashboard/src/views/RootfieldsView.tsx @@ -0,0 +1,94 @@ +import { useMemo, useState } from "react"; +import { Search } from "lucide-react"; +import { EmptyState } from "../components/EmptyState"; +import { HashValue } from "../components/HashValue"; +import { ProvenanceLine } from "../components/ProvenanceLine"; +import { SectionHeader } from "../components/SectionHeader"; +import { StatusBadge } from "../components/StatusBadge"; +import { searchRecords } from "../data/selectors"; +import type { DashboardData } from "../data/types"; + +export function RootfieldsView({ data }: { data: DashboardData }) { + const [query, setQuery] = useState(""); + const rootfields = useMemo(() => searchRecords(data.rootfields, query), [data.rootfields, query]); + + return ( +
+ +
+ ); +} + diff --git a/apps/dashboard/src/views/VerifierReportsView.tsx b/apps/dashboard/src/views/VerifierReportsView.tsx new file mode 100644 index 00000000..d317efa0 --- /dev/null +++ b/apps/dashboard/src/views/VerifierReportsView.tsx @@ -0,0 +1,116 @@ +import { useMemo, useState } from "react"; +import { Search } from "lucide-react"; +import { EmptyState } from "../components/EmptyState"; +import { HashValue } from "../components/HashValue"; +import { ProvenanceLine } from "../components/ProvenanceLine"; +import { SectionHeader } from "../components/SectionHeader"; +import { StatusBadge } from "../components/StatusBadge"; +import { DASHBOARD_STATUSES } from "../data/status"; +import { searchRecords } from "../data/selectors"; +import type { DashboardData, DashboardStatus } from "../data/types"; + +export function VerifierReportsView({ data }: { data: DashboardData }) { + const [query, setQuery] = useState(""); + const [status, setStatus] = useState("all"); + + const reports = useMemo(() => { + const statusFiltered = + status === "all" ? data.verifierReports : data.verifierReports.filter((report) => report.status === status); + return searchRecords(statusFiltered, query); + }, [data.verifierReports, query, status]); + + return ( +
+ + + +
+ } + /> + +
+ {reports.length > 0 ? ( +
+ + + + + + + + + + + + + {reports.map((report) => ( + + + + + + + + + ))} + +
StatusReportObservation / rootfieldPolicyChecksProvenance
+ + +
+ + + hash + +
+
+
+ + obs + + + root + +
+
+
+ {report.resolverPolicyId} + spec {report.verifierSpecVersion} +
+
+
+ + {report.checksPassed}/{report.checksTotal} + + {report.reasonCodes.join(", ") || "none"} +
+
+ +
+
+ ) : ( + + )} +
+
+ ); +} + diff --git a/apps/dashboard/src/views/WorkReceiptsView.tsx b/apps/dashboard/src/views/WorkReceiptsView.tsx new file mode 100644 index 00000000..cf809898 --- /dev/null +++ b/apps/dashboard/src/views/WorkReceiptsView.tsx @@ -0,0 +1,122 @@ +import { useMemo, useState } from "react"; +import { Search } from "lucide-react"; +import { EmptyState } from "../components/EmptyState"; +import { HashValue } from "../components/HashValue"; +import { ProvenanceLine } from "../components/ProvenanceLine"; +import { SectionHeader } from "../components/SectionHeader"; +import { StatusBadge } from "../components/StatusBadge"; +import { formatDateTime, formatMs } from "../data/format"; +import { searchRecords } from "../data/selectors"; +import type { DashboardData } from "../data/types"; + +export function WorkReceiptsView({ data }: { data: DashboardData }) { + const [query, setQuery] = useState(""); + const receipts = useMemo(() => searchRecords(data.workReceipts, query), [data.workReceipts, query]); + + return ( +
+ +
+ ); +} + diff --git a/apps/dashboard/tsconfig.json b/apps/dashboard/tsconfig.json new file mode 100644 index 00000000..ca91c526 --- /dev/null +++ b/apps/dashboard/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "composite": true, + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "types": ["vitest/globals"] + }, + "include": ["src", "vite.config.ts"] +} + diff --git a/apps/dashboard/vite.config.ts b/apps/dashboard/vite.config.ts new file mode 100644 index 00000000..bd068e16 --- /dev/null +++ b/apps/dashboard/vite.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from "vitest/config"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [react()], + test: { + environment: "node", + globals: true, + }, +}); diff --git a/docs/DASHBOARD_MVP.md b/docs/DASHBOARD_MVP.md new file mode 100644 index 00000000..44869b84 --- /dev/null +++ b/docs/DASHBOARD_MVP.md @@ -0,0 +1,80 @@ +# Dashboard MVP + +FlowMemory Dashboard V0 is a local React/Vite operator app under `apps/dashboard/`. It visualizes fixture data for the first app-facing explorer surface without introducing production APIs, wallet flows, token data, or live network claims. + +## Scope + +The MVP covers local inspection of: + +- FlowPulse observations from indexer-style receipt/log data +- Rootfield registry state +- Work lanes and work receipts +- Verifier reports +- Devnet blocks and state roots +- Hardware node heartbeats +- Alerts and incidents +- Raw JSON fixture data + +## Fixture Contract + +Canonical fixture: + +```text +fixtures/dashboard/flowmemory-dashboard-v0.json +``` + +Runtime copy loaded by Vite: + +```text +apps/dashboard/public/data/flowmemory-dashboard-v0.json +``` + +Copy command: + +```powershell +npm run sync:fixtures --prefix apps/dashboard +``` + +Each displayed object should include: + +- `id` or hash +- `status` +- `lastUpdated` when available +- `provenance.subsystem` +- `provenance.origin` +- `provenance.chainContext` +- fixture or generated local path hints when known + +## Future Generated Inputs + +Future local jobs can write generated data here before a live API exists: + +```text +fixtures/dashboard/generated/indexer-state.json +fixtures/dashboard/generated/verifier-reports.json +fixtures/dashboard/generated/devnet-state.json +fixtures/dashboard/generated/hardware-heartbeats.json +``` + +The app should keep treating those files as local/fixture data until a separate API decision defines authentication, caching, freshness, and failure semantics. + +## Non-Goals + +- No backend service required for V0 +- No wallet connect +- No token price, TVL, rewards, staking, or market data +- No production monitoring claims +- No secrets or RPC credentials +- No contract, service, or hardware behavior changes + +## Local Checks + +From `apps/dashboard/`: + +```powershell +npm install +npm run typecheck +npm test +npm run build +``` + diff --git a/fixtures/dashboard/flowmemory-dashboard-v0.json b/fixtures/dashboard/flowmemory-dashboard-v0.json new file mode 100644 index 00000000..dcd99f4b --- /dev/null +++ b/fixtures/dashboard/flowmemory-dashboard-v0.json @@ -0,0 +1,802 @@ +{ + "metadata": { + "schema": "flowmemory.dashboard.fixture.v0", + "generatedAt": "2026-05-13T16:00:00.000Z", + "mode": "fixture", + "description": "Synthetic local FlowMemory Dashboard V0 fixture. Values are operator/explorer test vectors only and do not claim live production data.", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "runtimeDataPath": "apps/dashboard/public/data/flowmemory-dashboard-v0.json", + "futureGeneratedPaths": { + "indexer": "fixtures/dashboard/generated/indexer-state.json", + "verifier": "fixtures/dashboard/generated/verifier-reports.json", + "devnet": "fixtures/dashboard/generated/devnet-state.json", + "hardware": "fixtures/dashboard/generated/hardware-heartbeats.json" + } + }, + "chain": { + "chainId": "31337", + "name": "Anvil local FlowMemory devnet", + "environment": "local-devnet", + "settlementContext": "Base-first project path; this fixture is not Base mainnet or Base Sepolia data.", + "currentBlock": 123482, + "finalizedBlock": 123450, + "source": "fixture", + "lastUpdated": "2026-05-13T15:58:42.000Z" + }, + "flowPulseObservations": [ + { + "id": "0x9717b7bad57bd0fa089e672e75cede4ae0bf3c86321dc0525ba00e9e0cc2da91", + "observationId": "0x9717b7bad57bd0fa089e672e75cede4ae0bf3c86321dc0525ba00e9e0cc2da91", + "pulseId": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123456", + "blockHash": "0x2222222222222222222222222222222222222222222222222222222222222222", + "txHash": "0x3333333333333333333333333333333333333333333333333333333333333333", + "transactionIndex": "7", + "logIndex": "2", + "receiptStatus": "success", + "actor": "0x4444444444444444444444444444444444444444", + "pulseType": "1", + "subject": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "commitment": "0x4122209ff672fc04b2ec3af31ab1af79813971f86de000aa6534038cc79de6b5", + "parentPulseId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "sequence": "1", + "occurredAt": "2026-05-13T14:30:00.000Z", + "uri": "ipfs://bafy-flowmemory-example", + "summary": "Rootfield registration observed from fixture receipt log.", + "status": "finalized", + "lastUpdated": "2026-05-13T15:51:00.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:51:00.000Z", + "localPathHint": "services/indexer/fixtures/flowpulse-logs.json" + } + }, + { + "id": "0x2ad24d8e9df0a17f1f6a6427c1ea3b401dc2f16d9a5bb64c3c96206cb3f5e712", + "observationId": "0x2ad24d8e9df0a17f1f6a6427c1ea3b401dc2f16d9a5bb64c3c96206cb3f5e712", + "pulseId": "0xa3f9000000000000000000000000000000000000000000000000000000000112", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123468", + "blockHash": "0x2468246824682468246824682468246824682468246824682468246824682468", + "txHash": "0x5301530153015301530153015301530153015301530153015301530153015301", + "transactionIndex": "3", + "logIndex": "0", + "receiptStatus": "success", + "actor": "0x5555555555555555555555555555555555555555", + "pulseType": "2", + "subject": "0x6f6d65706174682d726f6f742d303030303030303030303030303030303031", + "commitment": "0x81d30d3de2b29b44f23745289dbf214026ed1789983ff7aac135d74531402031", + "parentPulseId": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "sequence": "2", + "occurredAt": "2026-05-13T14:42:25.000Z", + "uri": "file://fixtures/rootfields/omega-path/root-0001.json", + "summary": "Root commitment finalized after local block threshold.", + "status": "finalized", + "lastUpdated": "2026-05-13T15:53:12.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:53:12.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "observationId": "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "pulseId": "0xa3f9000000000000000000000000000000000000000000000000000000000113", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123481", + "blockHash": "0x9595959595959595959595959595959595959595959595959595959595959595", + "txHash": "0x6060606060606060606060606060606060606060606060606060606060606060", + "transactionIndex": "1", + "logIndex": "1", + "receiptStatus": "success", + "actor": "0x5555555555555555555555555555555555555555", + "pulseType": "2", + "subject": "0x6f6d65706174682d726f6f742d303030303030303030303030303030303032", + "commitment": "0x61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff61ff", + "parentPulseId": "0xa3f9000000000000000000000000000000000000000000000000000000000112", + "sequence": "3", + "occurredAt": "2026-05-13T15:55:28.000Z", + "uri": "file://fixtures/rootfields/omega-path/root-0002.json", + "summary": "Recent root commitment observed below finality threshold.", + "status": "observed", + "lastUpdated": "2026-05-13T15:56:02.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:02.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "0x7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e", + "observationId": "0x7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e", + "pulseId": "0xc0ffee0000000000000000000000000000000000000000000000000000000417", + "rootfieldId": "0xdededededededededededededededededededededededededededededededede", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123449", + "blockHash": "0x1717171717171717171717171717171717171717171717171717171717171717", + "txHash": "0x1818181818181818181818181818181818181818181818181818181818181818", + "transactionIndex": "9", + "logIndex": "3", + "receiptStatus": "success", + "actor": "0x9999999999999999999999999999999999999999", + "pulseType": "9", + "subject": "0xdededededededededededededededededededededededededededededededede", + "commitment": "0x9090909090909090909090909090909090909090909090909090909090909090", + "parentPulseId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "sequence": "1", + "occurredAt": "2026-05-13T13:12:14.000Z", + "uri": "file://fixtures/rootfields/unsupported-pulse.json", + "summary": "Unsupported pulse type preserved for verifier policy review.", + "status": "unsupported", + "lastUpdated": "2026-05-13T15:18:00.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:18:00.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "0xabababababababababababababababababababababababababababababababab", + "observationId": "0xabababababababababababababababababababababababababababababababab", + "pulseId": "0xa3f90000000000000000000000000000000000000000000000000000000000ff", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123438", + "blockHash": "0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000", + "txHash": "0x4242424242424242424242424242424242424242424242424242424242424242", + "transactionIndex": "2", + "logIndex": "4", + "receiptStatus": "success", + "actor": "0x5555555555555555555555555555555555555555", + "pulseType": "2", + "subject": "0x72656f72672d726f6f742d3030303030303030303030303030303030303030", + "commitment": "0xe5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5", + "parentPulseId": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "sequence": "2", + "occurredAt": "2026-05-13T12:07:44.000Z", + "uri": "file://fixtures/rootfields/omega-path/reorged-root.json", + "summary": "Observation retained as noncanonical after local reorg fixture.", + "status": "reorged", + "lastUpdated": "2026-05-13T12:31:10.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T12:31:10.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", + "observationId": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", + "pulseId": "0x1212121212121212121212121212121212121212121212121212121212121212", + "rootfieldId": "0x3434343434343434343434343434343434343434343434343434343434343434", + "eventSignature": "0x5d07190b9ae441b4d7b16259a48424acd451492b12f5f99a29f5bfd992c13e43", + "blockNumber": "123482", + "blockHash": "0xa1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1", + "txHash": "0xb1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1", + "transactionIndex": "0", + "logIndex": "0", + "receiptStatus": "unknown", + "actor": "0x7777777777777777777777777777777777777777", + "pulseType": "2", + "subject": "0x70656e64696e672d726f6f742d3030303030303030303030303030303030", + "commitment": "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "parentPulseId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "sequence": "0", + "occurredAt": "2026-05-13T15:58:20.000Z", + "uri": "file://fixtures/rootfields/pending-root.json", + "summary": "Pending candidate from local scan window before receipt finality.", + "status": "pending", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "indexer", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + } + ], + "rootfields": [ + { + "id": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "owner": "0x4444444444444444444444444444444444444444", + "schemaHash": "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "metadataHash": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "latestRoot": "0x6f6d65706174682d726f6f742d303030303030303030303030303030303032", + "latestObservationId": "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "pulseCount": 4, + "workLaneIds": ["lane-indexer-a", "lane-verifier-a"], + "evidenceUri": "file://fixtures/rootfields/omega-path/", + "status": "finalized", + "lastUpdated": "2026-05-13T15:56:02.000Z", + "provenance": { + "subsystem": "contracts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:02.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + }, + { + "id": "0xdededededededededededededededededededededededededededededededede", + "rootfieldId": "0xdededededededededededededededededededededededededededededededede", + "owner": "0x9999999999999999999999999999999999999999", + "schemaHash": "0x1919191919191919191919191919191919191919191919191919191919191919", + "metadataHash": "0x2929292929292929292929292929292929292929292929292929292929292929", + "latestRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestObservationId": "0x7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e", + "pulseCount": 1, + "workLaneIds": ["lane-verifier-b"], + "evidenceUri": "file://fixtures/rootfields/unsupported/", + "status": "stale", + "lastUpdated": "2026-05-13T15:18:00.000Z", + "provenance": { + "subsystem": "contracts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:18:00.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + }, + { + "id": "0x3434343434343434343434343434343434343434343434343434343434343434", + "rootfieldId": "0x3434343434343434343434343434343434343434343434343434343434343434", + "owner": "0x7777777777777777777777777777777777777777", + "schemaHash": "0x3838383838383838383838383838383838383838383838383838383838383838", + "metadataHash": "0x3939393939393939393939393939393939393939393939393939393939393939", + "latestRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "latestObservationId": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", + "pulseCount": 0, + "workLaneIds": ["lane-indexer-a"], + "evidenceUri": "file://fixtures/rootfields/pending-root.json", + "status": "pending", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "contracts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + } + ], + "workLanes": [ + { + "id": "lane-indexer-a", + "laneId": "lane-indexer-a", + "name": "Indexer receipt ingest", + "queueDepth": 3, + "inflight": 1, + "completed24h": 37, + "p95LatencyMs": 840, + "operator": "local-codex-fixture", + "status": "pending", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "lane-verifier-a", + "laneId": "lane-verifier-a", + "name": "Verifier policy v0", + "queueDepth": 1, + "inflight": 1, + "completed24h": 22, + "p95LatencyMs": 1280, + "operator": "local-codex-fixture", + "status": "observed", + "lastUpdated": "2026-05-13T15:56:37.000Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:37.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "lane-verifier-b", + "laneId": "lane-verifier-b", + "name": "Unsupported pulse review", + "queueDepth": 0, + "inflight": 0, + "completed24h": 4, + "p95LatencyMs": 2120, + "operator": "local-codex-fixture", + "status": "stale", + "lastUpdated": "2026-05-13T15:19:05.000Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:19:05.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + } + ], + "workReceipts": [ + { + "id": "0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", + "receiptId": "0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f", + "laneId": "lane-verifier-a", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "observationId": "0x2ad24d8e9df0a17f1f6a6427c1ea3b401dc2f16d9a5bb64c3c96206cb3f5e712", + "reportId": "0x8080808080808080808080808080808080808080808080808080808080808080", + "workType": "verify-root-commitment", + "artifactUri": "file://fixtures/rootfields/omega-path/root-0001.json", + "startedAt": "2026-05-13T14:43:00.000Z", + "completedAt": "2026-05-13T14:43:01.120Z", + "resultHash": "0x7100710071007100710071007100710071007100710071007100710071007100", + "status": "verified", + "lastUpdated": "2026-05-13T14:43:01.120Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T14:43:01.120Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x0101010101010101010101010101010101010101010101010101010101010101", + "receiptId": "0x0101010101010101010101010101010101010101010101010101010101010101", + "laneId": "lane-indexer-a", + "rootfieldId": "0x3434343434343434343434343434343434343434343434343434343434343434", + "observationId": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", + "workType": "scan-receipt-window", + "artifactUri": "file://fixtures/devnet/block-123482.json", + "startedAt": "2026-05-13T15:58:20.000Z", + "resultHash": "0x1111110000001111110000001111110000001111110000001111110000001111", + "status": "pending", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/indexer-state.json" + } + }, + { + "id": "0x5656565656565656565656565656565656565656565656565656565656565656", + "receiptId": "0x5656565656565656565656565656565656565656565656565656565656565656", + "laneId": "lane-verifier-a", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "observationId": "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "reportId": "0x5959595959595959595959595959595959595959595959595959595959595959", + "workType": "verify-root-commitment", + "artifactUri": "file://fixtures/rootfields/omega-path/root-0002.json", + "startedAt": "2026-05-13T15:56:04.000Z", + "completedAt": "2026-05-13T15:56:04.640Z", + "resultHash": "0x6161616161616161616161616161616161616161616161616161616161616161", + "status": "invalid", + "lastUpdated": "2026-05-13T15:56:04.640Z", + "provenance": { + "subsystem": "worker", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:04.640Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + } + ], + "verifierReports": [ + { + "id": "0xe0ac708c933782ef6797b3ab4b6550cdd1a993fb1170361e5e05641ab801e66e", + "reportId": "0xe0ac708c933782ef6797b3ab4b6550cdd1a993fb1170361e5e05641ab801e66e", + "observationId": "0x9717b7bad57bd0fa089e672e75cede4ae0bf3c86321dc0525ba00e9e0cc2da91", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 3, + "checksTotal": 3, + "reasonCodes": [], + "reportHash": "0xe0ac708c933782ef6797b3ab4b6550cdd1a993fb1170361e5e05641ab801e66e", + "status": "verified", + "lastUpdated": "2026-05-13T15:51:31.000Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:51:31.000Z", + "localPathHint": "services/verifier/fixtures/artifacts.json" + } + }, + { + "id": "0x8080808080808080808080808080808080808080808080808080808080808080", + "reportId": "0x8080808080808080808080808080808080808080808080808080808080808080", + "observationId": "0x2ad24d8e9df0a17f1f6a6427c1ea3b401dc2f16d9a5bb64c3c96206cb3f5e712", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 4, + "checksTotal": 4, + "reasonCodes": [], + "reportHash": "0x8080808080808080808080808080808080808080808080808080808080808080", + "status": "verified", + "lastUpdated": "2026-05-13T14:43:01.120Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T14:43:01.120Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x5959595959595959595959595959595959595959595959595959595959595959", + "reportId": "0x5959595959595959595959595959595959595959595959595959595959595959", + "observationId": "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 3, + "checksTotal": 4, + "reasonCodes": ["commitment.mismatch"], + "reportHash": "0x5959595959595959595959595959595959595959595959595959595959595959", + "status": "invalid", + "lastUpdated": "2026-05-13T15:56:04.640Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:04.640Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x6464646464646464646464646464646464646464646464646464646464646464", + "reportId": "0x6464646464646464646464646464646464646464646464646464646464646464", + "observationId": "0x7d7c7b7a797877767574737271706f6e6d6c6b6a696867666564636261605f5e", + "rootfieldId": "0xdededededededededededededededededededededededededededededededede", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 1, + "checksTotal": 1, + "reasonCodes": ["pulse.type.unsupported"], + "reportHash": "0x6464646464646464646464646464646464646464646464646464646464646464", + "status": "unsupported", + "lastUpdated": "2026-05-13T15:18:11.000Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:18:11.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x7373737373737373737373737373737373737373737373737373737373737373", + "reportId": "0x7373737373737373737373737373737373737373737373737373737373737373", + "observationId": "0xabababababababababababababababababababababababababababababababab", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 1, + "checksTotal": 1, + "reasonCodes": ["observation.reorged"], + "reportHash": "0x7373737373737373737373737373737373737373737373737373737373737373", + "status": "reorged", + "lastUpdated": "2026-05-13T12:31:15.000Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T12:31:15.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x7474747474747474747474747474747474747474747474747474747474747474", + "reportId": "0x7474747474747474747474747474747474747474747474747474747474747474", + "observationId": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210", + "rootfieldId": "0x3434343434343434343434343434343434343434343434343434343434343434", + "resolverPolicyId": "flowmemory.resolver.policy.v0.fixture", + "verifierSpecVersion": "0", + "checksPassed": 1, + "checksTotal": 2, + "reasonCodes": ["artifact.unavailable"], + "reportHash": "0x7474747474747474747474747474747474747474747474747474747474747474", + "status": "unresolved", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "0x7575757575757575757575757575757575757575757575757575757575757575", + "reportId": "0x7575757575757575757575757575757575757575757575757575757575757575", + "observationId": "0x2ad24d8e9df0a17f1f6a6427c1ea3b401dc2f16d9a5bb64c3c96206cb3f5e712", + "rootfieldId": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "resolverPolicyId": "flowmemory.resolver.policy.v0.previous-fixture", + "verifierSpecVersion": "0", + "checksPassed": 2, + "checksTotal": 4, + "reasonCodes": ["report.stale_policy"], + "reportHash": "0x7575757575757575757575757575757575757575757575757575757575757575", + "status": "stale", + "lastUpdated": "2026-05-13T14:12:00.000Z", + "provenance": { + "subsystem": "verifier", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T14:12:00.000Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + } + ], + "devnetBlocks": [ + { + "id": "0x1717171717171717171717171717171717171717171717171717171717171717", + "blockNumber": 123449, + "blockHash": "0x1717171717171717171717171717171717171717171717171717171717171717", + "parentHash": "0x1616161616161616161616161616161616161616161616161616161616161616", + "stateRoot": "0x5050505050505050505050505050505050505050505050505050505050505050", + "receiptsRoot": "0x5151515151515151515151515151515151515151515151515151515151515151", + "timestamp": "2026-05-13T13:12:14.000Z", + "observationCount": 1, + "reportCount": 1, + "finalityDistance": 33, + "status": "finalized", + "lastUpdated": "2026-05-13T15:45:00.000Z", + "provenance": { + "subsystem": "devnet", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:45:00.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + }, + { + "id": "0x2468246824682468246824682468246824682468246824682468246824682468", + "blockNumber": 123468, + "blockHash": "0x2468246824682468246824682468246824682468246824682468246824682468", + "parentHash": "0x2358235823582358235823582358235823582358235823582358235823582358", + "stateRoot": "0x6262626262626262626262626262626262626262626262626262626262626262", + "receiptsRoot": "0x6363636363636363636363636363636363636363636363636363636363636363", + "timestamp": "2026-05-13T14:42:25.000Z", + "observationCount": 1, + "reportCount": 1, + "finalityDistance": 14, + "status": "finalized", + "lastUpdated": "2026-05-13T15:45:00.000Z", + "provenance": { + "subsystem": "devnet", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:45:00.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + }, + { + "id": "0x9595959595959595959595959595959595959595959595959595959595959595", + "blockNumber": 123481, + "blockHash": "0x9595959595959595959595959595959595959595959595959595959595959595", + "parentHash": "0x9494949494949494949494949494949494949494949494949494949494949494", + "stateRoot": "0x7070707070707070707070707070707070707070707070707070707070707070", + "receiptsRoot": "0x7171717171717171717171717171717171717171717171717171717171717171", + "timestamp": "2026-05-13T15:55:28.000Z", + "observationCount": 1, + "reportCount": 1, + "finalityDistance": 1, + "status": "pending", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "devnet", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + }, + { + "id": "0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000", + "blockNumber": 123438, + "blockHash": "0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000", + "parentHash": "0x4343434343434343434343434343434343434343434343434343434343434343", + "stateRoot": "0x8888000088880000888800008888000088880000888800008888000088880000", + "receiptsRoot": "0x9999000099990000999900009999000099990000999900009999000099990000", + "timestamp": "2026-05-13T12:07:44.000Z", + "observationCount": 1, + "reportCount": 1, + "finalityDistance": 0, + "status": "reorged", + "lastUpdated": "2026-05-13T12:31:10.000Z", + "provenance": { + "subsystem": "devnet", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T12:31:10.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + } + ], + "hardwareNodes": [ + { + "id": "fm-node-lab-01", + "nodeId": "fm-node-lab-01", + "callsign": "Lab Gateway 01", + "role": "gateway", + "firmware": "flowrouter-v0.1.0-fixture", + "transport": "ethernet + meshtastic sidecar", + "lastHeartbeatAt": "2026-05-13T15:57:58.000Z", + "batteryPercent": 100, + "signalDbm": -51, + "temperatureC": 39, + "linkedWorkLaneId": "lane-indexer-a", + "locationHint": "bench-east", + "status": "observed", + "lastUpdated": "2026-05-13T15:58:42.000Z", + "provenance": { + "subsystem": "hardware", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:58:42.000Z", + "localPathHint": "fixtures/dashboard/generated/hardware-heartbeats.json" + } + }, + { + "id": "fm-node-router-03", + "nodeId": "fm-node-router-03", + "callsign": "Router Shelf 03", + "role": "router", + "firmware": "flowrouter-v0.1.0-fixture", + "transport": "wifi + lora control", + "lastHeartbeatAt": "2026-05-13T15:11:08.000Z", + "batteryPercent": 72, + "signalDbm": -88, + "temperatureC": 44, + "linkedWorkLaneId": "lane-verifier-b", + "locationHint": "workshop-shelf", + "status": "stale", + "lastUpdated": "2026-05-13T15:11:08.000Z", + "provenance": { + "subsystem": "hardware", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:11:08.000Z", + "localPathHint": "fixtures/dashboard/generated/hardware-heartbeats.json" + } + }, + { + "id": "fm-node-field-07", + "nodeId": "fm-node-field-07", + "callsign": "Field Kit 07", + "role": "field-kit", + "firmware": "flowrouter-v0.1.0-fixture", + "transport": "meshtastic control only", + "locationHint": "packed-case", + "status": "offline", + "lastUpdated": "2026-05-13T14:20:00.000Z", + "provenance": { + "subsystem": "hardware", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T14:20:00.000Z", + "localPathHint": "fixtures/dashboard/generated/hardware-heartbeats.json" + } + } + ], + "alerts": [ + { + "id": "incident-2026-05-13-001", + "incidentId": "incident-2026-05-13-001", + "severity": "critical", + "title": "Verifier commitment mismatch", + "summary": "Report 0x5959 records a deterministic commitment mismatch for the latest omega-path root fixture.", + "openedAt": "2026-05-13T15:56:04.640Z", + "linkedObjectIds": [ + "0x82a7c8ef9931b361451efc99d932f615e251b3320ac395545971fe2e64fd14ca", + "0x5959595959595959595959595959595959595959595959595959595959595959" + ], + "recommendedAction": "Compare the generated root artifact with the emitted commitment before promoting this fixture to verified.", + "status": "unresolved", + "lastUpdated": "2026-05-13T15:56:04.640Z", + "provenance": { + "subsystem": "alerts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:56:04.640Z", + "localPathHint": "fixtures/dashboard/generated/verifier-reports.json" + } + }, + { + "id": "incident-2026-05-13-002", + "incidentId": "incident-2026-05-13-002", + "severity": "warning", + "title": "Hardware heartbeat stale", + "summary": "Router Shelf 03 has not reported a fresh heartbeat inside the fixture freshness window.", + "openedAt": "2026-05-13T15:41:00.000Z", + "linkedObjectIds": ["fm-node-router-03", "lane-verifier-b"], + "recommendedAction": "Check local power and radio sidecar telemetry before assigning verifier work to the node.", + "status": "stale", + "lastUpdated": "2026-05-13T15:41:00.000Z", + "provenance": { + "subsystem": "alerts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T15:41:00.000Z", + "localPathHint": "fixtures/dashboard/generated/hardware-heartbeats.json" + } + }, + { + "id": "incident-2026-05-13-003", + "incidentId": "incident-2026-05-13-003", + "severity": "info", + "title": "Reorg replacement recorded", + "summary": "A noncanonical block and observation remain in the fixture so the explorer can show reorg history.", + "openedAt": "2026-05-13T12:31:10.000Z", + "linkedObjectIds": [ + "0xffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000", + "0xabababababababababababababababababababababababababababababababab" + ], + "recommendedAction": "Keep the reorged records visible, but exclude them from current verified root summaries.", + "status": "verified", + "lastUpdated": "2026-05-13T13:02:00.000Z", + "provenance": { + "subsystem": "alerts", + "origin": "fixture", + "chainContext": "anvil-31337", + "fixturePath": "fixtures/dashboard/flowmemory-dashboard-v0.json", + "capturedAt": "2026-05-13T13:02:00.000Z", + "localPathHint": "fixtures/dashboard/generated/devnet-state.json" + } + } + ] +} From 4577968655fc2fb449079b484e05d698bcdc8306 Mon Sep 17 00:00:00 2001 From: FlowmemoryAI <283694809+FlowmemoryAI@users.noreply.github.com> Date: Wed, 13 May 2026 11:15:28 -0500 Subject: [PATCH 2/2] Remove trailing blank lines from dashboard files --- apps/dashboard/README.md | 1 - apps/dashboard/index.html | 1 - apps/dashboard/scripts/sync-fixtures.mjs | 1 - apps/dashboard/src/App.tsx | 1 - apps/dashboard/src/components/AppShell.tsx | 1 - apps/dashboard/src/components/EmptyState.tsx | 1 - apps/dashboard/src/components/HashValue.tsx | 1 - apps/dashboard/src/components/ProvenanceLine.tsx | 1 - apps/dashboard/src/components/SectionHeader.tsx | 1 - apps/dashboard/src/components/StatusBadge.tsx | 1 - apps/dashboard/src/data/format.ts | 1 - apps/dashboard/src/data/loadDashboardData.ts | 1 - apps/dashboard/src/data/status.ts | 1 - apps/dashboard/src/data/types.ts | 1 - apps/dashboard/src/main.tsx | 1 - apps/dashboard/src/test/dashboardData.test.ts | 1 - apps/dashboard/src/views/AlertsView.tsx | 1 - apps/dashboard/src/views/DevnetBlocksView.tsx | 1 - apps/dashboard/src/views/FlowPulseStreamView.tsx | 1 - apps/dashboard/src/views/HardwareNodesView.tsx | 1 - apps/dashboard/src/views/OverviewView.tsx | 1 - apps/dashboard/src/views/RawJsonInspectorView.tsx | 1 - apps/dashboard/src/views/RootfieldsView.tsx | 1 - apps/dashboard/src/views/VerifierReportsView.tsx | 1 - apps/dashboard/src/views/WorkReceiptsView.tsx | 1 - apps/dashboard/tsconfig.json | 1 - docs/DASHBOARD_MVP.md | 1 - 27 files changed, 27 deletions(-) diff --git a/apps/dashboard/README.md b/apps/dashboard/README.md index f528e45b..d0b3daf7 100644 --- a/apps/dashboard/README.md +++ b/apps/dashboard/README.md @@ -75,4 +75,3 @@ observed, pending, finalized, verified, unresolved, invalid, unsupported, reorge ``` These are app-facing display states for local fixture inspection. They should stay aligned with indexer and verifier terminology as those packages mature. - diff --git a/apps/dashboard/index.html b/apps/dashboard/index.html index cd503264..f705964a 100644 --- a/apps/dashboard/index.html +++ b/apps/dashboard/index.html @@ -14,4 +14,3 @@ - diff --git a/apps/dashboard/scripts/sync-fixtures.mjs b/apps/dashboard/scripts/sync-fixtures.mjs index 3db1ff2d..46a84a45 100644 --- a/apps/dashboard/scripts/sync-fixtures.mjs +++ b/apps/dashboard/scripts/sync-fixtures.mjs @@ -12,4 +12,3 @@ mkdirSync(destinationDir, { recursive: true }); copyFileSync(source, destination); console.log(`Synced dashboard fixture: ${destination}`); - diff --git a/apps/dashboard/src/App.tsx b/apps/dashboard/src/App.tsx index f802e015..df5df928 100644 --- a/apps/dashboard/src/App.tsx +++ b/apps/dashboard/src/App.tsx @@ -99,4 +99,3 @@ export default function App() { ); } - diff --git a/apps/dashboard/src/components/AppShell.tsx b/apps/dashboard/src/components/AppShell.tsx index 3731ee30..fb354c16 100644 --- a/apps/dashboard/src/components/AppShell.tsx +++ b/apps/dashboard/src/components/AppShell.tsx @@ -84,4 +84,3 @@ export function AppShell({ data, children }: AppShellProps) {
); } - diff --git a/apps/dashboard/src/components/EmptyState.tsx b/apps/dashboard/src/components/EmptyState.tsx index e496ee9b..13f6f5e7 100644 --- a/apps/dashboard/src/components/EmptyState.tsx +++ b/apps/dashboard/src/components/EmptyState.tsx @@ -16,4 +16,3 @@ export function EmptyState({ title, detail }: EmptyStateProps) {
); } - diff --git a/apps/dashboard/src/components/HashValue.tsx b/apps/dashboard/src/components/HashValue.tsx index c77814fb..f4ce7d2e 100644 --- a/apps/dashboard/src/components/HashValue.tsx +++ b/apps/dashboard/src/components/HashValue.tsx @@ -21,4 +21,3 @@ export function HashValue({ value, label, trim = "medium" }: HashValueProps) { ); } - diff --git a/apps/dashboard/src/components/ProvenanceLine.tsx b/apps/dashboard/src/components/ProvenanceLine.tsx index 49f1d26d..1a608236 100644 --- a/apps/dashboard/src/components/ProvenanceLine.tsx +++ b/apps/dashboard/src/components/ProvenanceLine.tsx @@ -39,4 +39,3 @@ export function ProvenanceLine({ provenance, lastUpdated }: { provenance: Proven
); } - diff --git a/apps/dashboard/src/components/SectionHeader.tsx b/apps/dashboard/src/components/SectionHeader.tsx index f97fb8c7..9d1036fd 100644 --- a/apps/dashboard/src/components/SectionHeader.tsx +++ b/apps/dashboard/src/components/SectionHeader.tsx @@ -19,4 +19,3 @@ export function SectionHeader({ eyebrow, title, detail, action }: SectionHeaderP ); } - diff --git a/apps/dashboard/src/components/StatusBadge.tsx b/apps/dashboard/src/components/StatusBadge.tsx index 727fb9ac..ddfa7e9e 100644 --- a/apps/dashboard/src/components/StatusBadge.tsx +++ b/apps/dashboard/src/components/StatusBadge.tsx @@ -14,4 +14,3 @@ export function StatusBadge({ status, compact = false }: StatusBadgeProps) { ); } - diff --git a/apps/dashboard/src/data/format.ts b/apps/dashboard/src/data/format.ts index f0dd1fb0..d34b0109 100644 --- a/apps/dashboard/src/data/format.ts +++ b/apps/dashboard/src/data/format.ts @@ -18,4 +18,3 @@ export function formatPercent(value?: number): string { } return `${value}%`; } - diff --git a/apps/dashboard/src/data/loadDashboardData.ts b/apps/dashboard/src/data/loadDashboardData.ts index 03e1d8ec..55790b98 100644 --- a/apps/dashboard/src/data/loadDashboardData.ts +++ b/apps/dashboard/src/data/loadDashboardData.ts @@ -46,4 +46,3 @@ export async function fetchDashboardData( return validateDashboardData(await response.json()); } - diff --git a/apps/dashboard/src/data/status.ts b/apps/dashboard/src/data/status.ts index ec61a2ae..762e1c11 100644 --- a/apps/dashboard/src/data/status.ts +++ b/apps/dashboard/src/data/status.ts @@ -46,4 +46,3 @@ export function isDashboardStatus(value: string): value is DashboardStatus { export function statusClassName(status: DashboardStatus): string { return `status-badge status-${status}`; } - diff --git a/apps/dashboard/src/data/types.ts b/apps/dashboard/src/data/types.ts index 1191d5c4..2fb690bb 100644 --- a/apps/dashboard/src/data/types.ts +++ b/apps/dashboard/src/data/types.ts @@ -180,4 +180,3 @@ export interface DashboardData { hardwareNodes: HardwareNode[]; alerts: AlertIncident[]; } - diff --git a/apps/dashboard/src/main.tsx b/apps/dashboard/src/main.tsx index f9a9cefd..04e310d9 100644 --- a/apps/dashboard/src/main.tsx +++ b/apps/dashboard/src/main.tsx @@ -11,4 +11,3 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( , ); - diff --git a/apps/dashboard/src/test/dashboardData.test.ts b/apps/dashboard/src/test/dashboardData.test.ts index 6e0d82b4..45e2997c 100644 --- a/apps/dashboard/src/test/dashboardData.test.ts +++ b/apps/dashboard/src/test/dashboardData.test.ts @@ -58,4 +58,3 @@ describe("dashboard fixture", () => { expect(matches.map((match) => match.status)).toContain("invalid"); }); }); - diff --git a/apps/dashboard/src/views/AlertsView.tsx b/apps/dashboard/src/views/AlertsView.tsx index 4b50c7d6..041f1e3d 100644 --- a/apps/dashboard/src/views/AlertsView.tsx +++ b/apps/dashboard/src/views/AlertsView.tsx @@ -69,4 +69,3 @@ export function AlertsView({ data }: { data: DashboardData }) {
); } - diff --git a/apps/dashboard/src/views/DevnetBlocksView.tsx b/apps/dashboard/src/views/DevnetBlocksView.tsx index 11157cca..e80b2fe3 100644 --- a/apps/dashboard/src/views/DevnetBlocksView.tsx +++ b/apps/dashboard/src/views/DevnetBlocksView.tsx @@ -97,4 +97,3 @@ export function DevnetBlocksView({ data }: { data: DashboardData }) { ); } - diff --git a/apps/dashboard/src/views/FlowPulseStreamView.tsx b/apps/dashboard/src/views/FlowPulseStreamView.tsx index 3d886246..ce655bc8 100644 --- a/apps/dashboard/src/views/FlowPulseStreamView.tsx +++ b/apps/dashboard/src/views/FlowPulseStreamView.tsx @@ -120,4 +120,3 @@ export function FlowPulseStreamView({ data }: { data: DashboardData }) { ); } - diff --git a/apps/dashboard/src/views/HardwareNodesView.tsx b/apps/dashboard/src/views/HardwareNodesView.tsx index 63a345c6..b70ba8ea 100644 --- a/apps/dashboard/src/views/HardwareNodesView.tsx +++ b/apps/dashboard/src/views/HardwareNodesView.tsx @@ -89,4 +89,3 @@ export function HardwareNodesView({ data }: { data: DashboardData }) { ); } - diff --git a/apps/dashboard/src/views/OverviewView.tsx b/apps/dashboard/src/views/OverviewView.tsx index 9c58a43f..369ea80f 100644 --- a/apps/dashboard/src/views/OverviewView.tsx +++ b/apps/dashboard/src/views/OverviewView.tsx @@ -164,4 +164,3 @@ export function OverviewView({ data }: { data: DashboardData }) { ); } - diff --git a/apps/dashboard/src/views/RawJsonInspectorView.tsx b/apps/dashboard/src/views/RawJsonInspectorView.tsx index b10d0646..6a4f00ce 100644 --- a/apps/dashboard/src/views/RawJsonInspectorView.tsx +++ b/apps/dashboard/src/views/RawJsonInspectorView.tsx @@ -55,4 +55,3 @@ export function RawJsonInspectorView({ data }: { data: DashboardData }) { ); } - diff --git a/apps/dashboard/src/views/RootfieldsView.tsx b/apps/dashboard/src/views/RootfieldsView.tsx index b86d3a25..8f4656bc 100644 --- a/apps/dashboard/src/views/RootfieldsView.tsx +++ b/apps/dashboard/src/views/RootfieldsView.tsx @@ -91,4 +91,3 @@ export function RootfieldsView({ data }: { data: DashboardData }) { ); } - diff --git a/apps/dashboard/src/views/VerifierReportsView.tsx b/apps/dashboard/src/views/VerifierReportsView.tsx index d317efa0..402c0c5f 100644 --- a/apps/dashboard/src/views/VerifierReportsView.tsx +++ b/apps/dashboard/src/views/VerifierReportsView.tsx @@ -113,4 +113,3 @@ export function VerifierReportsView({ data }: { data: DashboardData }) { ); } - diff --git a/apps/dashboard/src/views/WorkReceiptsView.tsx b/apps/dashboard/src/views/WorkReceiptsView.tsx index cf809898..80c81475 100644 --- a/apps/dashboard/src/views/WorkReceiptsView.tsx +++ b/apps/dashboard/src/views/WorkReceiptsView.tsx @@ -119,4 +119,3 @@ export function WorkReceiptsView({ data }: { data: DashboardData }) { ); } - diff --git a/apps/dashboard/tsconfig.json b/apps/dashboard/tsconfig.json index ca91c526..e73de76d 100644 --- a/apps/dashboard/tsconfig.json +++ b/apps/dashboard/tsconfig.json @@ -20,4 +20,3 @@ }, "include": ["src", "vite.config.ts"] } - diff --git a/docs/DASHBOARD_MVP.md b/docs/DASHBOARD_MVP.md index 44869b84..6b4d52fc 100644 --- a/docs/DASHBOARD_MVP.md +++ b/docs/DASHBOARD_MVP.md @@ -77,4 +77,3 @@ npm run typecheck npm test npm run build ``` -