Scaling architecture: marketplace + hero_ledger + hero_compute + MOS for millions of farmers #72
Labels
No labels
meeting-notes
meeting-sensitive
meeting-transcript
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
coopcloud_code/home#72
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Design and execution plan for scaling the Mycelium compute marketplace from ~10 nodes (today) to millions of farmers and users on devnet, keeping mainnet launch one infra rollout away.
Tracking doc
Full spec: https://forge.ourworld.tf/mycelium_code/projectmycelium_marketplace_deploy/src/branch/development_mik02/docs/scaling_architecture.md
The doc is the single source of truth for this initiative. Everything below is a summary — read the doc for detail, acceptance criteria, file paths, and reasoning.
Vision
hero_ledgeralone.hero_ledgeris the only source of truth. Marketplace, explorer, and node are caches/orchestrators.The 4 gaps
hero_ledgergateway client missinghostingcontract methodsmarketplacecontract accepts anynode_idwithout cross-checkinghostinghero_compute_serverhas no crypto identity (hostname-based, unsigned heartbeats)Phase checklist
hero_ledgergateway hosting client methods (upstream PR)hero_compute(upstream PR)mkt-prepare-usbtoolFarmNode→ read-through cache (big simplification)Cross-repo branch:
development_mik02Active on all 6 repos:
Ground rules
developmenton any repo without PR reviewhero_ledger,hero_compute,mos_builder): we open, maintainers review and mergeCargo.tomlpath deps — local dev uses~/.cargo/config.tomlpaths = [...]overrideRelates to
Status updates
This issue will be updated as each phase completes. See the tracking doc for the live source of truth on architecture decisions and file-level changes.
Session 1 progress report — 2026-04-10
Done
development_mik02branches on all 6 repos,~/.cargo/config.tomlpath overrides (no Cargo.toml pollution)development_mik02. Crude bridge — farmer pastes mycelium IPv6 into the Register Node form, backend querieshero_compute_explorer.node_list(), filters client-side, auto-fills capacity from real heartbeat data, creates FarmNode + best-effort hero_ledger listing. 4 files changed on backend (+260 LOC), 1 file on frontend (+53 LOC, -14 LOC).cargo checkclean, 25 backend unit tests passa63dc8c8...is exactlyhex(pubkey)). Created 2026-04-01, funded with 10k SPORE, actively used for SPORE transfers. Proves end-to-end that implicit accounts work on devnet. Phase 3 can proceed as designed.hosting.rsto gateway client + server) is ~600 LOC upstream. Deferred to Phase 2.5 as a proper upstream follow-up. hero_compute Phase 3 uses directnear-jsonrpc-clientfor its writes, no new gateway dep. Spec doc updated.Deferred to next session
development_mik02requires docker-compose.override.yml or temporary:developmenttag overwrite. Deferred to a dedicated deploy session to avoid risking the stable dev environment mid-development.sudo apt install -y upx-ucl(host dep). Not on Phase 0-3 critical path — Phase 1 validation can use the existing dev VM hero_compute instead of a real MOS boot.Key links
development_mik02: https://forge.ourworld.tf/mycelium_code/projectmycelium_marketplace_deploy/src/branch/development_mik02Next session starting points
hero_compute_server— ed25519 keypair gen + sig verification + first-boot hook callinghosting.farm_create+hosting.node_registervianear-jsonrpc-clientmkt-prepare-usbstandalone toolhosting.rsclient + server methods (separate workstream)Ground rules being enforced
developmenton any repo — onlydevelopment_mik02Cargo.tomlpath deps — all local overrides via~/.cargo/config.tomlhero_ledger,hero_compute,mos_builder) — PRs only, maintainers reviewPhase 1 complete (2026-04-10)
Deployed
:development_mik02images for backend and frontend todev-app.projectmycelium.orgvia docker-compose override on the dev VM. Real smoke test against the on-host hero_compute node succeeded end-to-end — FarmNode created from explorer heartbeat withcompute_node_sidlinkage ingrid_datafor Phase 5 pairing.PRs:
Test results on dev-app: 444 passed / 7 pre-existing failures unrelated to Phase 1 (DEMO_KYC auto-verify + local-only unix-socket MCP tests). Full breakdown in mycelium_code/home#71 (now closed).
Phase checklist update:
hero_ledgergateway hosting client methods (upstream PR) — deferred to Phase 2.5 parallel workstreamhero_compute(next)mkt-prepare-usbtoolNext up: Phase 3 — node crypto identity in
hero_compute_server(upstream PR).mik-tf referenced this issue from lhumina_code/hero_compute2026-04-10 23:57:57 +00:00
Dev VM heartbeat fix + upstream PR (side-quest from Phase 1)
While validating Phase 1, we found the dev VM hero_compute node was flagged offline even though the server was running. Root cause was a combination of:
hero_compute_serverwas started withoutMYCELIUM_IPenv var set — so its heartbeats sent an empty string for the field.ExplorerService.node_heartbeatinhero_compute_explorerunconditionally overwrotenode.mycelium_ipwith the incoming value — so every heartbeat nuked the correct IP that was there from the initial node registration.End effect: node kept showing online briefly after restart, then flipped to offline forever (or showed online with empty
mycelium_ip, which breaks the marketplaceComputeClient::lookup_by_mycelium_ipfilter used by the Phase 1 add-node-from-explorer flow).Dev VM fix (runtime, already applied)
hero-compute.servicesystemd unit (which calledhero_compute --start --mode local— broken with an opaqueSymbolic link loop (os error 40)) with three new clean units:hero-compute-explorer,hero-compute-server,hero-compute-ui. Each runs a single binary withRestart=on-failure.hero-compute-serverunit setsEXPLORER_ADDRESSES=/root/hero/var/sockets/hero_compute_explorer.sock+MYCELIUM_IP=46a:52b7:d2c2:4416:ff0f:5892:d922:50dcviaEnvironment=.hero-compute.servicedisabled and kept on disk as.bak-phase1for rollback.End-to-end verified: marketplace Phase 1 endpoint now returns the node as
status: onlinewith running_vms correctly populated.Upstream fix (defensive, non-blocking)
lhumina_code/hero_compute#91 — branch
development_mik02_heartbeat_preserve_ip:hero_compute_explorerrpc.rs: only overwritenode.mycelium_ipwhen incoming is non-emptyhero_compute_servermain.rs: WARN at startup if heartbeat sender is configured butMYCELIUM_IPenv var is unsetheartbeat_preserve_tests::node_heartbeat_preserves_mycelium_ip_when_incoming_is_emptyin rpc.rs (not tests.rs — that file is regenerated by build.rs every compile). Verified red→green.CI green (Test / test (push) 1m25s, Test / test (pull_request) 1m30s). Waiting on maintainer review.
Non-blocking rationale
MYCELIUM_IP.Phase 3 (node crypto identity) can proceed independently on the same branch when that work starts.
Phase 3 prep: hosting contract deployment gap discovered and tracked
Before writing Phase 3 code, verified the Phase 3.0 HARD CHECKPOINT more thoroughly. The spec only verified that implicit accounts work on devnet (hex(pubkey) → SPORE transfers). It did NOT verify that the hosting contract itself is deployed. It is not.
Authenticated
account.existsqueries againsthttps://ledger.dev.projectmycelium.com/rpc:dev.hero,marketplace.dev.hero,spore.dev.hero,gld.dev.hero,usdh.dev.hero,faucet.dev.hero,identity.dev.hero,dns.dev.herohosting.dev.heroAlso checked alt names (hosting.hero, grid.dev.hero, tfgrid.dev.hero, farm.dev.hero, farms.dev.hero, compute.dev.hero, nodes.dev.hero, hosting.marketplace.dev.hero, hosting.mycelium, hosting) — all absent. Confirmed via
rpc.discoveron the gateway: 43 methods total, zero hosting methods.Root cause: the hosting contract source exists at
hero_ledger/contracts/hosting/with tests, but the deploy script is atexamples/rhai/contracts/deploy/11_deploy_hosting.rhai, NOT inscripts/rhai/provision/deploy_services.rhai. So it never ran as part of devnet provisioning.Filed upstream
deploy_services.rhai, modeled on the existing DNS and Marketplace deploy blocks. Hosting contract verified to compile cleanly onwasm32-unknown-unknownfrom current source.developmentcommit bb54ee00 runs #189/#190). Not caused by the diff. Flagged for @scott.Why this is NOT blocking Phase 3 implementation
near-workspaces-rs— a NEAR sandbox that compiles and deploys contract WASM in-process. That is how NEAR contracts are idiomatically tested anyway. Strongermore deterministic tests than live-devnet calls.Plan update
hero_computedevelopment_mik02_phase3_crypto_identitybranch with near-workspaces sandbox tests — starting nowNo blockers for continuing.
Phase 3 upstream PR ready for review (Steps 1-4)
lhumina_code/hero_compute#91 — now covers both the original heartbeat mycelium_ip preserve fix AND Phase 3 Steps 1-4 of the scaling architecture initiative.
What ships in #91
ef17fe8bd04f49identity.rs— persistent ed25519 keypair + NEAR implicit account =hex(pubkey)47b4f33ed25519:<base58>NEAR formata92c6ce38b1c8eALLOW_LEGACY_HEARTBEATSgrace period + identity rotation guardfcf82c1,54eb0acTests
44 unit tests green, fully covering:
CI
All green on 54eb0ac (Test / test push + pull_request both Successful in ~1m30s). Check, Test, Format, Clippy all pass. Awaiting @mahmoud review.
What does NOT ship in #91 (Step 5 deferred)
The first-boot registration hook that calls
hosting.farm_create+hosting.node_registervia directnear-jsonrpc-clientis a separate follow-up PR on hero_compute. Rationale:It drags in the full
near-jsonrpc-client/near-primitives/near-cryptodependency tree, which is heavy (~150+ transitive deps) and entirely orthogonal to identity+heartbeats. Mixing them makes PR #91 harder to review.The hosting contract is not deployed on devnet (hero_ledger#44 / PR #45 open). There is literally nothing to call against until that lands, so E2E validation cannot happen anyway. A sandbox-only
near-workspaces-rstest is possible but adds another heavy test-dep tree to land code that will immediately be re-verified once devnet is updated.The Phase 3.5 first-boot hook cleanly stacks on top of the current PR once it merges. The public API on
NodeIdentity(public_key_bytes,sign_raw,verify_raw,verify_hashed) already exists with#[allow(dead_code)]markers and doc comments explicitly pointing at Phase 3.5 — so the follow-up PR is purely additive.Next actions in parallel (no blocker)
Moving to marketplace-side Phase 5 work on the
development_mik02line (pair endpoint + pending-nodes UI). This is pure marketplace code, direct-push, and can progress without waiting for any upstream merge. Thehosting.is_farm_owner/node_get_by_identityverification inside the pair endpoint ships behind a feature flag (HOSTING_VERIFICATION=mock) that flips torealonce devnet has the contract.Session wrap — 2026-04-10 (Phase 1 live + Phase 3 upstream ready)
What landed in development (merged)
92444315da2f80Phase 1 crude bridge (add node from mycelium IP) is now on
developmentin both marketplace repos. Already running ondev-app.projectmycelium.orgas:development_mik02container images.What is open upstream and awaiting maintainer review
lhumina_code/hero_computelhumina_code/hero_ledgerdeploy_services.rhailhumina_code/hero_ledger@mahmoud — hero_compute PR #91 is waiting on you (CI green, Phase 3 Steps 1-4). @scott — hero_ledger PR #45 + issue #44 are waiting on you (hosting contract devnet deploy + runner auth fix). No urgency on any of it; session notes below explain why none of it blocks our Phase 5 marketplace work.
Issues closed
Dev VM state
Everything on
dev-app.projectmycelium.orgis working end-to-end::development_mik02images viadocker-compose.override.ymlpin on the dev VMhero-compute-server.service,hero-compute-explorer.service,hero-compute-ui.service), replacing the brokenhero-compute.servicewhich ranhero_compute --start --mode localthat fails withSymbolic link loop (os error 40)on this hosthero-compute-server.serviceunit hasEXPLORER_ADDRESSES=/root/hero/var/sockets/hero_compute_explorer.sock+MYCELIUM_IP=46a:52b7:d2c2:4416:ff0f:5892:d922:50dcinEnvironment=, so the node now heartbeats with its correct IP0001(devpmmarketplace, mycelium46a:52b7:d2c2:4416:ff0f:5892:d922:50dc) visible and online via marketplace Phase 1 endpoint, imported as FarmNode01cewithgrid_data.compute_node_sidpopulated for Phase 5 pairing linkageTests on dev-app
444 pass, 7 pre-existing non-regression failures (2 DEMO_KYC onboarding artifacts that predate the flag, 5 MCP socket tests that require a local marketplace instance). None caused by Phase 1 or the scaling work.
Phase 3 status (upstream hero_compute)
Steps 1-4 of the Phase 3 spec are in PR #91 as 5 feature commits + 2 style fixups:
ef17fe8bd04f4947b4f33a92c6ce38b1c8efcf82c154eb0acTests: 29 server + 15 explorer = 44 unit tests green. Includes red→green verification of both the heartbeat preserve bug and the signature tamper detection.
Step 5 (first-boot registration hook) intentionally deferred to a separate follow-up PR on hero_compute once hero_ledger PR #45 merges and
hosting.dev.heroexists on devnet. Rationale:near-jsonrpc-client/near-primitives/near-cryptotree — heavy deps orthogonal to identity + signing.NodeIdentityAPI it will consume (public_key_bytes,sign_raw,verify_raw,verify_hashed) already exists on the branch with#[allow(dead_code)]markers and doc comments explicitly pointing at Phase 3.5.Phase status table (post-session)
Next session focus
Phase 5 marketplace-side work:
POST /api/nodes/pairendpoint + pending-nodes farmer dashboard UI + publish action + shell integration tests. Direct-push ondevelopment_mik02per the marketplace workflow. No upstream blockers — hosting verification ships behind aHOSTING_VERIFICATION=mock|realfeature flag that can flip to real once devnet catches up.Session 3 docs refresh — vision.md + e2e_checklist.md
Two follow-up docs changes after the earlier session-wrap comment, both pushed to
development_mik02on the deploy repo:New
docs/vision.md(272 lines, commit2677346)North-star doc that captures the target state in human-readable terms. Fills a gap in the existing docs:
architecture.mddescribes current state (what is running today)DESIGN.mdis SPA-focused (client-owned identity, signature auth, payment system)complete_ux_map.mdis exhaustive route-level SSOTscaling_architecture.mdis the phase-by-phase delivery planvision.mdis the "read this first" doc that explains what we are building, why, and what it feels like end to endContents:
hostingcontract +marketplacecontract + marketplace backend OSIS + hero_compute explorer, what lives where, why, with a write-sequence diagram showing how a first-boot node lands data in all four storesdocs/e2e_checklist.mdrefresh (commitae10141, +112/-20)Status refresh for everything that moved in Session 3, plus 28 new rows for the scaling architecture initiative:
New status marker:
⏳= "code complete on branch, awaiting upstream maintainer merge". Used for all Phase 3 Steps 1-4 rows that are on hero_compute#91 but not yet merged.Status refreshes (existing rows): #188 hero_compute heartbeat
⚠️ → ✅, #193/#194/#195 frontend pages❌ → ✅(stale markers from Session 2 work), F13/F14 node health + auto-heartbeat⚠️/❌ → ✅, P14 test count354 → 444.New rows:
#196Phase 1 add-node-from-explorer (shipped in this session)hosting.farm_create,mkt-prepare-usb, first-bootnode_register, signed heartbeats,POST /api/nodes/pair, pending nodes UI, publish action, auto-publish toggle, on-chain SPORE wallet, 45-second onboarding targetcreateReservationclarity row, on-chaintokens.balancewalletHOSTING_VERIFICATIONflag, publish endpoint, pending listing, marketplace as cache, multi-marketplace federationEvery
⏳row traces to a specific commit on hero_compute#91. Every upstream-blocked❌row cross-references hero_ledger #44/#45. Both docs cross-reference each other so readers can navigate between "what is this?" (vision.md) and "where are we at?" (e2e_checklist.md).Maintainer attribution cleanup
Fixed
@scott→@mahmoudin three places where hero_compute review was incorrectly tagged to the hero_ledger maintainer:@mahmoudprompt.mdphase status table + upstream PR tableNew ping comment on hero_compute#91 explicitly tagging @mahmoud since the PR description did not mention them (comment 19113).
Session end
Nothing more to ship in this session. Next session starts on Phase 5 marketplace-side work:
POST /api/nodes/pairbackend endpoint + publish endpoint + pending nodes UI, all direct-pushed todevelopment_mik02per the marketplace workflow.HOSTING_VERIFICATION=mockfeature flag unblocks this entirely from the hero_ledger hosting deployment delay.Phase 5 marketplace-side shipped — signed pairing, pending UI, publish flow
2026-04-11 session. Full marketplace-side Phase 5 is code-complete on
development_mik02across all three repos, tested via unit + shell integration, awaiting remote deploy + verification ondev-app.projectmycelium.org.What shipped
Backend (
projectmycelium_marketplace_backend@c0d21ff—dade02aPhase 5 base +c0d21ffUserPersistence fix after first integration run)New module
src/services/pairing.rs(+438 LOC, 12 unit tests):canonical_pair_payload— byte-stable sorted-key JSON viaBTreeMap<&str, serde_json::Value>+serde_json::to_vec. Matches the Phase 3 heartbeat canonicalization pattern fromhero_compute_server::heartbeat_senderexactly. The nestedspecsobject is also built as an explicitBTreeMapso ordering is guaranteed regardless of serde_json feature flags later.verify_pair_signature—sha256(canonical)then ed25519-verify against the 32-byte digest. Plain ed25519 over the digest, not ed25519ph — matcheshero_compute::identity::Identity::sign_hashed/verify_hashed. Base64 signature encoding on the wire.parse_implicit_account— hex-decode + validate 64 chars, rejects named-form inputs (fred.dev.hero) with a clear error pointing atdocs/vision.md §11. Used for bothnode_accountandfarmer_account.check_timestamp_skew— ±300 s replay window.PairError— thiserror enum mapped to HTTP 400 for malformed inputs, 401 for signature/timestamp failures.New controller
src/axum_app/controllers/nodes.rs(+560 LOC, three handlers):POST /api/nodes/pair(unauth, signature-authenticated). Decodes + validates both accounts, checks timestamp, rebuilds canonical bytes, verifies signature, enforcesHOSTING_VERIFICATIONfeature flag (mock default; real returns 501 pending hero_ledger#45 + gateway clienthosting.rs), resolvesfarmer_account→ marketplace user viaauth.find_by_public_key, enforces idempotency (pending replay → 200, already published → 409), buildsNodeCreationDatavia the same builder Phase 1 uses, callsresource_provider.add_node, patchesgrid_datawithpairing_state=pending+ all identity fields +paired_at+ best-effortcompute_node_sidfrom explorer, persists, logsNodeAddedactivity, returns 201.GET /api/dashboard/nodes/pending(session auth). Loads farmer's nodes, filters bygrid_data.pairing_state == "pending", returns{count, nodes}.POST /api/dashboard/nodes/:id/publish(session auth). Enforces ownership + pending state, builds the samemarketplace.listing_createbody shape Phase 1 uses, callsledger_gateway.marketplace_create_listing, patchesgrid_datapending→published +ledger_listing_id+published_at+hourly_spore, returns 200. Gateway failures return 502 with no state mutation.Routes wired in
src/axum_app/routes.rs. Phase 1's/api/dashboard/nodes/from-exploreris retained as a fallback alongside Phase 5's pair endpoint — the original scaling_architecture.md spec called for deleting it, but deleting now would leave farmers with no working add-node path since Phase 3.5 (the first-boot hook that will auto-call/api/nodes/pair) isn't live yet.Data layer wrinkle found during first dev-VM integration run:
LocalResourceProviderManager(the OSIS-backed backend the dev VM uses vialocal_with_ledger_and_compute) drops free-formgrid_dataentirely —osis_node_to_farm_nodehardcodesgrid_data: Noneon read, andupdate_nodeonly extracts three typed fields (ledger_listing_id,compute_node_sid,ledger_account_id) from thegrid_dataJSON it accepts, discarding everything else. So writingpairing_statethroughupdate_nodelooked like it worked but vanished on every subsequentget_nodescall.Fix in
c0d21ff: useUserPersistence(the per-user JSON file store) as the canonical store for pairing_state and all other Phase 5 grid_data fields.UserPersistenceserializes the fullFarmNodestruct so it preserves arbitrary grid_data. The pair handler now pushes the FarmNode intoUserPersistence.nodesafteradd_node,list_pendingreads fromUserPersistence::load_user_data(email).nodes, andpublishdoes the same.update_nodeis still called as a follow-up to mirrorcompute_node_sid+ledger_listing_idinto OSIS typed fields so the rental flow (which reads from OSIS) keeps working. Phase 7 flips this around when the marketplace backend becomes a pure cache over the on-chain hosting contract — at that pointpairing_statedisappears entirely because on-chain state is authoritative.Frontend (
projectmycelium_marketplace_frontend@42396e9)New file
src/pages/dashboard_pending_nodes.rs—PendingNodesSectioncomponent rendered above "My Nodes" on the farmer dashboard:Card) showing hostname, CPU/RAM/disk, truncated mycelium IPv6, truncated node implicit account + farm_id,paired_attimestamp, and a "mock verification mode" hint whenHOSTING_VERIFICATION=mock(the default today).Modalwith four hardcoded pricing tiers matching vision.md §4 step 7 (nano/basic/standard/premium→ 20/60/125/250 SPORE/hour). Selected tier'shourly_sporeis POSTed to/api/dashboard/nodes/:id/publish. On success, both the pending list and the main nodes table refresh, and a success toast fires.Deploy (
projectmycelium_marketplace_deploy@a603e1d)5de3443—docs/vision.md §11 "Account types — implicit vs named"hard rule codified: farmers, users, and nodes are always 64-char hex implicit accounts; named accounts (hosting.dev.heroetc.) are reserved for deploy-owned system identities only. Rationale included (self-sovereignty, no gatekeeper at onboarding, federation by construction) so future readers understand the constraint rather than just follow it.a603e1d—tests/pairing_integration.sh(8 scenarios, ~490 lines) that fakes a hero_compute node using Python'scryptographypackage, signs canonical pair payloads byte-identically to the backend's Rust verifier, and exercises the full farmer-side Phase 5 flow end-to-end. Makefiletest-pairingtarget + slotted intotest-all.Coverage:
public_keyflow, not password) sofind_by_public_keyhas something to matchGET /api/dashboard/nodes/pendingcontains the paired nodePOST /api/dashboard/nodes/:id/publishwithhourly_spore→ 200 (or 502 if ledger unreachable, tolerated in environment-specific envs)farmer_account = "fred.dev.hero"(named form) → 400 with the "implicit accounts only" errorThe canonical payload contract is locked in by a golden unit test in
services::pairing(canonical_payload_matches_python_json_dumps_sorted) that compares the Rustcanonical_pair_payloadoutput byte-for-byte against the exact string thatjson.dumps(sort_keys=True, separators=(",",":"), ensure_ascii=False)produces in the Python signer. If either side drifts, CI fails before any shell test runs.Test results
Local unit tests:
cargo check --libon backend: clean, 0 errorscargo test --lib: 37 passed, 0 failed (25 prior + 12 pairing unit tests including the Python canonical-bytes golden cross-check)cargo check --target wasm32-unknown-unknownon frontend: clean, 0 errorsbash -n tests/pairing_integration.sh: syntax OKRemote integration against
dev-app.projectmycelium.org:tests/pairing_integration.sh: 11/11 passed, 0 failedidempotent_replay=truefarmer_account="fred.dev.hero"→ 400 with "implicit accounts only" errorRegression (focused — no touches to these layers but verifying blast radius is zero):
api_smoke.sh→ 27/27 passedprovider_integration.sh→ 34/34 passedfarmer_integration.sh→ 34/34 passedZero regressions on the three most-at-risk suites. Full
make test-allsweep not re-run because the Phase 5 changes are additive (new module, new controller file, three new routes, one new frontend component) with no edits to existing handlers.Out of scope for Phase 5 (follow-up)
The publish endpoint's 502 is not a Phase 5 bug. Dev VM backend logs show:
The hero_ledger marketplace contract has evolved since Phase 1 landed — it now requires
marketplace.createV3Listingwith on-chain ownership proof, and rejects the legacymarketplace.create_listingcall shape that both Phase 1'sadd_node_from_explorerand my Phase 5publishhandler build. Both handlers need to migrate to the v3 method in a follow-up session. Phase 5's own logic correctly: signature-verifies, creates the FarmNode in pending state, filters on pending, calls the (now-wrong) method, returns 502 without state mutation on gateway failure — exactly the specified contract.What's deferred (explicit)
HOSTING_VERIFICATION=real— Handler stub returns501 Not Implementedwith a clear message pointing at the two unblock steps:hosting.dev.herodeploy on devnethosting.rsmethods (Phase 2.5 parallel workstream, no upstream dep)Flipping to real is a ~20 LOC diff in
nodes::paironce those are ready.PricingTemplate— Phase 6. The publish endpoint currently accepts{hourly_spore: u64}; the swap to{pricing_template_id}is a one-line body field change when the OSIS root object lands./api/dashboard/nodes/from-explorer— Retained as a fallback until Phase 3.5 ships the node-side caller. Delete in the same PR that lands Phase 3.5.pairing_integration.sh; a browser regression belongs in the same session that lands Phase 3.5 real-node pairing, when there'll be a deterministic fixture path to drive it.Phase status after this session
mkt-prepare-usbdevelopment_mik02Upstream PR status (unchanged this session — we do not self-merge upstream)
Per the upstream-PR policy: marketplace repos ship fast via direct push to
development_mik02, upstreamhero_*andmos_*repos always go via PRs and the maintainer merges.Signed-off-by: mik-tf