proto(lab): fleet-native single-miner view — discovery + strategy prototypes [PROTOTYPE] - #827
Draft
flesher wants to merge 47 commits into
Draft
proto(lab): fleet-native single-miner view — discovery + strategy prototypes [PROTOTYPE]#827flesher wants to merge 47 commits into
flesher wants to merge 47 commits into
Conversation
…#826) Discovery brief for migrating the single-miner view off the miner-API proxy onto fleet-collected data: as-is architecture, data-gap analysis, full ProtoOS -> ProtoFleet API parity map, and a phased plan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🔐 Codex Security Review
Review SummaryOverall Risk: HIGH Findings[HIGH] Required release checksum assets are never published
[MEDIUM] Release verification does not authenticate the publisher
[MEDIUM] Organization-wide MQTT credentials are distributed to every Proto rig
NotesReview was limited to the authoritative PR diff and static inspection; tests could not run in the read-only workspace. No pool-address substitution or other cryptostealing behavior was identified, and the protobuf changes appear additive and wire-compatible. Generated by Codex Security Review | |
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
…lding surfaces (#864) Co-authored-by: Claude <noreply@anthropic.com>
…#826) Discovery brief for migrating the single-miner view off the miner-API proxy onto fleet-collected data: as-is architecture, data-gap analysis, full ProtoOS -> ProtoFleet API parity map, and a phased plan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two sub-discoveries linked from the main single-miner-view plan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Throwaway prototype scaffolding (never merges): /lab preview surface, shared SingleMinerView + snapshot contract, MDK_VERSION knob + divergent /api/v2 on fake-proto-rig, and a just lab-fakes recipe. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…TYPE]
Add SingleMinerAdapter seam and two direct browser→miner adapters that fold
divergent wire formats into one SingleMinerSnapshot rendered by the shared view:
- MdkV1Adapter: today's multi-endpoint /api/v1 REST (login + system + mining +
hashboards); synthesizes the ASIC grid around avg ASIC temp (v1 has no bulk
per-chip data — the honest limitation).
- MdkV2Adapter: faked consolidated GET /api/v2/miner with real per-chip data.
- probe.ts: GET /api/version picks the adapter (falls back to v1 pre-probe).
- AdapterPage: base-URL/IP input + version probe + refresh; presets target the
two fake rigs, any reachable miner IP works.
Fake rig: top-level permissive CORS (browser→rig needs it — a real S3 finding),
FAKE_RIG_MINING seed so the Lab shows a mining device, and fix v2State to match
the real MiningState constants ("Mining"/"DegradedMining").
Throwaway; never merges to main.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
FleetAdapter sources identity + KPIs entirely from the fleet server via the existing FleetManagementService.ListMinerStateSnapshots RPC (by /32 ipCidr) over /api-proxy — never touches the device. FleetNativePage IS the single-miner mode: type a miner IP (or "pick a discovered miner") → resolve fleet-native → render the shared SingleMinerView. The ASIC grid is synthesized from device-level temperature, with a code-cited callout on why: the collector builds HashBoards→ASICs in memory (plugins/mappers/sdk_mapper.go) but persistence drops the arrays (timescaledb/telemetry_store.go:366) and no client RPC exposes them. Making the grid real = a new prototype/v1 Connect RPC calling miner.GetDeviceMetrics(ctx) on demand (interfaces/miner.go:59) — mechanism exists, deferred (each server change needs a full image rebuild; ASIC source for these rigs is unconfirmed). Throwaway; never merges to main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Probe the miner's version and mount a bespoke, version-specific client instead of the shared view — the strategy's whole point (and cost): you ship and maintain a separate client per firmware generation. - ProtoOSv1Mini: renders the v1 REST surface in its own idiom (login + system + mining + hashboards; board hardware list, no per-chip grid — v1 has none). - ProtoOSv2Mini: renders the v2 consolidated envelope with a native per-chip grid. Structurally and visually distinct from v1 on purpose. - ProxyVersionedPage: GET /api/version → mount the matching client; presets for both fake rigs so you can compare the two UIs side by side. Lab fetches hit the fake rigs directly; the same code targets the minerproxy path (/api-proxy/miners/:id) in production. Throwaway; never merges to main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reflect what actually shipped: S1 uses existing ListMinerStateSnapshots + synthesized grid (prototype/v1 RPC deferred, not built), fake-rig additions, and the lab-fakes recipe. Add a "Running it" section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…PROTOTYPE] S3 now offers all three backends behind the one generic view: a "Fleet server" option (reusing FleetAdapter — identity + KPIs from ListMinerStateSnapshots over /api-proxy, ASIC grid synthesized) alongside the MDK v1/v2 direct path. Shows what a single-miner UI rendered inside ProtoFleet off the fleet backend looks like, folded into the same SingleMinerView as the MDK adapters. Includes a "pick a discovered miner" helper for a valid fleet IP. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refactor the single-miner Lab so all three strategies render one shared
<SingleMinerView>, and add a collapsible "Data flow" pane that narrates
each strategy's plumbing.
- Split the view into shared pieces: MinerViewFrame (chrome + Details
modal), MinersList (tabular Name / IP / firmware), SingleMinerDetails
(data-path ribbon), plus status/asicData helpers.
- Data-flow trace bus (flowTrace.ts + FlowPane.tsx): adapters emit
semantic events (requests, notes, version seam, adapter layer); the
page-configured tracer colors them by hop and flags proxying.
- blue: client -> fleet RPC; violet: fleet <- miner collection;
green: client -> miner REST; teal: version seam (S2);
amber: adapter layer (S3).
- POST calls get a solid method badge; GET a muted one.
- Trace appends sequentially, clearing only on new connection or
prototype switch; control actions (pause/resume) append.
- S1 fleet-native: hand-waves the synthetic ASIC grid; runs under a
fleet-native transport so the adapter row is suppressed (the view is
framed as reading the fleet proto directly).
- S3 adapter: fleet is one adapter among three (adapter row shown);
list filtered to first-party rigs; direct MDK contexts auto-connect.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nto migrate-single-miner-to-fleet # Conflicts: # docs/plans/2026-07-28-single-miner-views-on-fleet-backend-plan.md
Comment on lines
+3
to
+6
| import ( | ||
| "crypto/aes" | ||
| "crypto/cipher" | ||
| "crypto/ecdh" |
| if err != nil { | ||
| return nil, err | ||
| } | ||
| ephemeral, err := ecdh.X25519().GenerateKey(rand.Reader) |
| if len(payload.GetCiphertext()) > maxCiphertext { | ||
| return sdk.CurtailmentConfig{}, fmt.Errorf("encrypted curtailment config is %d bytes; maximum is %d", len(payload.GetCiphertext()), maxCiphertext) | ||
| } | ||
| recipient, err := ecdh.X25519().NewPrivateKey(privateKey) |
| if err != nil { | ||
| return sdk.CurtailmentConfig{}, fmt.Errorf("parse recipient private key: %w", err) | ||
| } | ||
| ephemeral, err := ecdh.X25519().NewPublicKey(payload.GetEphemeralPubkey()) |
| if len(publicKey) != x25519KeySize { | ||
| return nil, fmt.Errorf("%w: must be %d bytes, got %d", ErrInvalidRecipientPublicKey, x25519KeySize, len(publicKey)) | ||
| } | ||
| recipient, err := ecdh.X25519().NewPublicKey(publicKey) |
| nodeDir := filepath.Join(outputDir, host.name) | ||
| if err := writeFile(filepath.Join(nodeDir, "service-ca.crt"), ca.certPEM, 0o644); err != nil { | ||
| return err | ||
| } |
| serial, err := randomSerial() | ||
| if err != nil { | ||
| return err | ||
| } |
| } | ||
| keyDER, err := x509.MarshalPKCS8PrivateKey(key) | ||
| if err != nil { | ||
| return fmt.Errorf("encode %s key: %w", name, err) |
| hex.Encode(encoded, raw) | ||
| return encoded, nil | ||
| } | ||
|
|
| return fmt.Errorf("write %s: %w", filepath.Base(path), err) | ||
| } | ||
| return nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's here
Discovery (
docs/): the fleet-native single-miner-view research + API parity map, plus a strategies RFC (docs/rfcs/0003-single-miner-view-strategies.md).Three working prototypes in the Lab, each rendering the same shared
<SingleMinerView>(identity + 3 KPIs + ASIC mini-grid + one control) so they can be compared apples-to-apples:ListMinerStateSnapshots). Framed as reading the fleet proto directly; the ASIC grid is hand-waved (fleet stores device-level scalars today)./api/version, picks the right MDK client via a version seam, and proxies requests to the miner.Data-flow pane
A collapsible "Data flow" drawer narrates each strategy's plumbing like a color-coded network tab:
Testing
Runs against the fake rigs (
just lab-fakes, v1 :18081 / v2 :18082) and a live fleet-api session.tsc/ eslint / prettier clean.🤖 Generated with Claude Code