~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
436 lines · 34.9 KB Raw History

Port and singleton audit: N market networks on one host (hat-8)

Read-only audit, 2026-10-11. Scope: every fixed TCP/UDP port, fixed path, fixed name, mutable image tag and other host-global singleton that stops two or more task trees from running the kcp market network (socialweb-computer-kcp/deploy/market-network, deploy/denokcp, internal/marketnetwork) at the same time on hat-8, each with its own fake PLC, relay, ingress proxy, PDSes, several bidders and requesters and no real accounts. Everything else (other tests, CLIs, dev scripts) is in section 5.

Related: plan 0008 M1-MARKET-NETWORK-PARALLEL (todo, depends on 0006 M1-PORT-LEASE-INSTANCE) already names the goal and its tests (TestNoNetworkPortIsALiteral, TestTwoNetworkRecordsLeaseDisjointPorts, TestTwoNetworksOnOneHostEachRentAGuestThroughTheRFPFlow); dev-run-mode.md 4.5/4.8 and kcp-spike.md 1 cover the kcp port-0 read-back. This file is the concrete inventory those items need.

Legend: Override today = can a caller already change it without editing code. Impact = what breaks when two market networks run at once.

0. Answer in one screen

What blocks market network #2 today, in order:

  1. Service ports 2583-2589 are literals in seven DenoPod manifests and in every consumer of them (accept.sh checks, requester args, bidder args, PDS_CRAWLERS, dispatcher-tls env). Market network #2's pods fail to bind and the provider restarts them forever (restartPolicy: Always).
  2. The provider learns a pod's address only by parsing --port/PORT out of the manifest (kcp-libs/factory/servicenames/servicenames.go:166-197). Port 0 cannot work until the resolver reads the bound port back. This is the one code change everything else waits on.
  3. The one-network-per-host refusal in internal/marketnetwork/live_test.go:18,112-120 (probe-binds 2583-2589 and skips/fails if any is held). This is the "one-network-per-host lock"; there is no lock file in today's tree.
  4. Every service writes ./port-bound-to into its source checkout (port-file default in each CLI's cli-args-env; DenoPod cwd = SERVICE_CWD = the repo dir). Both PDSes of one market network already share hono-pds/port-bound-to; N market networks all share it. This is the exact mechanism port 0 needs, pointed at a shared path (the stray ?? port-bound-to at the org root is this).
  5. Bidder state under $HOME/.cache/pdr-market/ (pds-state-path Deno KV, oauth session, key path): the market network's bidder does not override it, so every bidder of every market network opens one KV file.
  6. m3 live test binds the docker bridge gateway on 2583/2587 (live_m3_test.go:96-98,465-467) and socats to fixed 2583/2587/2588/2589 inside its container.
  7. kcp/kine/openbao ports are probed-then-bound (accept.sh:78-91, python bind/close) - works today because accept.sh already randomises them, but it is the org's banned listen-close-rebind race.
  8. Mutable runner image tag localhost/socialweb-firecracker-runner:local; its build writes binaries into the shared source tree (hono-compute-provider/deno.json:67).
  9. FC work root vs the 107-byte unix socket limit: a TASK_STATE_DIR-keyed work root (~/.local/state/swc-tasks/<task>/market-network/guests/fc-.../fc.sock) is 110+ bytes for ordinary task names.
  10. Single bidder pod / single bidder key: "several bidders per market network" needs templated bidder-<n> pods with their own port, key and state path.

Already per-market-network or harmless (do not spend time here): kcp workspace names and DenoPod names (each market network has its own kcp), *.localhost / relay.localhost names (ports separate market networks), guest container names (random), the 172.30.0.0 guest range (lives inside each guest's own container netns), ACCEPT_ROOT, KCACHE, GUEST_TLS_DIR and key files under accept.sh, the requester (port 0, result file per root), the atproto-market container harness (port 0 throughout).

1. Per-market-network parameters (the target shape)

One market network = one MARKET_NETWORK_ID (8 chars [a-z0-9], e.g. first 8 hex of sha256(task name + n)). Everything the market network owns hangs off it:

ParameterValueWhy
TASK_STATE_DIR$XDG_STATE_HOME/swc-tasks/<task>per task tree
MARKET_NETWORK_DIR (= today's ACCEPT_ROOT)$TASK_STATE_DIR/market-networks/$MARKET_NETWORK_IDkcp root, kine db, openbao dir, runs dir, keys, guest TLS, logs, market network record
FC_WORK_ROOT/var/tmp/swc-$MARKET_NETWORK_ID (symlinked from $MARKET_NETWORK_DIR/guests)must stay short: fc-<12>-<8>/fc.sock adds 32 bytes; 107-byte limit. Not $XDG_RUNTIME_DIR (tmpfs; guest disks live in the work dir)
market network record$MARKET_NETWORK_DIR/market-network.json (atomic rename)every bound port, kubeconfig path, FC work root, runner image digest, HOST_IP, bidder DIDs; the only thing accept.sh checks, the requester and the Go tests read
all service ports0, bound port reported via createServe portFile -> <runDir>/port-bound-to -> DenoPod status -> market network recordno leases needed for these
kcp secure port0 + --experimental-bind-free-port, read back from $MARKET_NETWORK_DIR/kcp/admin.kubeconfig / /proc LISTEN socket (kcp-spike.md 1)
kine / openbao127.0.0.1:0, read back from the pid's single LISTEN socket in /proc (same technique), or lease from the per-user lease file (0006 M1-PORT-LEASE-INSTANCE)unverified that kine/bao log the bound port
docker label--label swc.market-network=$MARKET_NETWORK_ID on guest containerssweep by label, not by name or work-root listing
runner imagecontent-hash tag localhost/socialweb-firecracker-runner:sha-<12> pinned in market-network.jsonrebuilds by one task never change another market network's guests
slotflock /var/tmp/socialweb-market-network-slots/<i>.lock, i < SWC_MARKET_NETWORK_SLOTSsection 6

2. The market network's own singletons, in detail (socialweb-computer-kcp unless named)

Ranked by what stops two market networks first.

B1. Fixed service ports in the DenoPod manifests - BLOCKER

file:linewhat
deploy/market-network/20-global-plc.yaml:13,15plc --port 2587, PORT 2587
30-relay-relay.yaml:13,15relay --port 2584
35-relay-dispatcher.yaml:16,19dispatcher (hono-did-key-ingress-proxy) --port 2588, --plc-directory-url https://127.0.0.1:2587
36-relay-dispatcher-tls.yaml:15-17,29DISPATCHER_PORT 2588, TLS_PORT 2589, Deno.serve({hostname: "0.0.0.0", port})
40-alice-pds.yaml:16,18alice PDS --port 2583, PDS_CRAWLERS https://127.0.0.1:2584
60-bob-pds.yaml:16,18bob PDS --port 2585, PDS_CRAWLERS https://127.0.0.1:2584
70-bidder.yaml:24,34bidder --serve-port 2586, --plc-directory-url https://127.0.0.1:2587, --ingress-proxy-host relay.localhost:2588, --guest-tls-port 2589, PORT/SERVE_PORT 2586
  • Override today: no (literals; apply.sh's sed does not touch them).
  • Impact: market network #2's pods all fail to bind; restartPolicy: Always loops; market network #2's verifier/requester may silently talk to market network #1's services on the same ports (wrong-market-network traffic, not just failure).
  • Fix: --port 0 / PORT "0" / --serve-port 0, TLS_PORT 0; dependents name the service by its FQDN (https://plc.default.global.svc.kcp.local, https://relay.default.relay.svc.kcp.local) the way PDS_PLC_DIRECTORY_URL already does, never 127.0.0.1:<n>. Needs B2 first. The bidder's --ingress-proxy-host and --guest-tls-port are guest-facing (go into cloud-init user_data), so the dispatcher and dispatcher-tls ports must be known before the bidder pod is rendered: apply.sh already applies 35/36 before 70; add "wait for status.address, then render 70".
  • 36-relay-dispatcher-tls binds 0.0.0.0 on purpose (guests reach it via HOST_IP). With port 0 per market network that stays correct; note it exposes the market network on the LAN.

B2. Provider derives a pod's address from its manifest, not its socket - BLOCKER (kcp-libs, deno-kcp)

  • kcp-libs/factory/servicenames/servicenames.go:166-197 AdvertisedAddress(argsJSON, envJSON) reads --port/PORT and --hostname/HOSTNAME; used at :109 (DNS table for every other pod) and :149 (self). deno-kcp/internal/provider/service_dns.go feeds it via services.Env(... SERVICE_ARGS, SERVICE_ENV ...).
  • With port 0 the table would say 127.0.0.1:0.
  • Fix: the pod reports its bound port (B3: <runDir>/port-bound-to, written by createServe onListen); the provider's runner reads it on observe and records status.address on the DenoPod; AdvertisedAddress prefers status.address and falls back to args. The DNS table is delivered in env (KCP_DNS_TABLE) at process start, so a pod started before its dependency bound would carry a stale table: deliver the table as a file in the run dir (KCP_DNS_TABLE_FILE) that the shim re-reads on a lookup miss, or keep strict apply ordering. Probes use status.address.

B3. port-file defaults to ./port-bound-to in the shared source checkout - BLOCKER for port 0

file:linedefault
hono-pds/cli-args-env.json:57port-file ./port-bound-to (and port 2583 at :5)
atproto-relay/hono-atproto-relay/cli-args-env.json:31same (port 2584 at :5)
atproto-market/hono-plc/cli-args-env.json:27same (port 2587 at :5)
did-key-ingress-proxy/hono-did-key-ingress-proxy/cli-args-env.json:87same (port 8080 at :17)
atproto-market/hono-bidder/cli-args-env.ts:267-272same (serve-port default 0, good)
typescript-helpers/lib/serve/mod.ts:131-136createServe writes it whenever portFile is set
  • The pod script runs the service with cwd: SERVICE_CWD (e.g. 40-alice-pds.yaml:15,67), the repo dir. Alice and bob PDS write the same hono-pds/port-bound-to in ONE market network; all market networks share it.
  • Override today: yes, PORT_FILE env.
  • Fix: the pod script sets childEnv.PORT_FILE = \${runDir}/port-bound-to`(it already computesrunDir, 40-alice-pds.yaml:35). Consider changing the CLI default to ""` (write nothing unless asked) so dev runs stop littering checkouts.

B4. accept.sh host-side consumers of fixed ports - BLOCKER

  • accept.sh:417-422 bob PDS check --resolve pds.default.bob.svc.kcp.local:2585; :432-436 bidder check http://127.0.0.1:2586; :506-515 requester --plc-directory-url https://127.0.0.1:2587, --ingress-proxy-host relay.localhost:2588, --guest-diagnose-url https://relay.localhost:2589/....
  • apply.sh:297-303 prints the same literals (cosmetic).
  • Override: no.
  • Fix: read each from kubectl get denopod <n> -o jsonpath={.status.address} (B2) into market-network.json, and read market-network.json. HOST_IP (accept.sh:469) is host-wide and fine to share.

B5. The one-network-per-host refusal - BLOCKER (by design)

  • internal/marketnetwork/live_test.go:18 testNetworkPorts = {2583..2589}; :112-120 probe-binds each and livegate.Requires "cannot share them with a second market network".
  • Fix: delete with B1; replace with the market network slot (section 6) plus TestTwoNetworkRecordsLeaseDisjointPorts. live_test.go:76-80 work root os.MkdirTemp("/var/tmp", "mtb-") is already unique; switch to /var/tmp/swc-$MARKET_NETWORK_ID only to share the naming.

B6. m3 live test host-global binds - BLOCKER for parallel m3 runs

  • internal/marketnetwork/live_m3_test.go:96-98 forwardLoopback(gateway, 2583|2587) -> :467 net.Listen("tcp", "<docker0 gw>:2583") on the host. Two m3 runs collide (same docker bridge gateway).
  • :38 m3OwnerPDS = https://127.0.0.1:2583; :582 INGRESS_PROXY_HOST=relay.localhost:2588; :593-601 socat inside the container to gw:2583/2588/2589/2587.
  • :39-41 /var/lib/socialweb, 127.0.0.1:6443 are inside the container's own netns/volume: fine.
  • :110-112 container m3live-<hex>, volume m3live-state-<hex>: fine.
  • Fix: forward gw:0 -> market network port, pass the forwarded ports into the container env/socat args from market-network.json. Image comes from SOCIALWEB_M3_CONTROL_PLANE_IMAGE; default build tag is fixed (S-12).

B7. kcp / kine defaults and the probe-then-bind race - HIGH

  • deploy/denokcp/start-kcp.sh:4-6 ROOT=$PWD/.kcp, KINE_ENDPOINT=http://127.0.0.1:23791, KCP_SECURE_PORT=6443; :54 kine --listen-address; :71 kcp --secure-port. Override: yes (env). accept.sh passes fresh values; a bare apply.sh run uses 6443/23791 and $REPO/.kcp-demo.
  • deploy/denokcp/stop-kcp.sh:19 default ROOT=$REPO/.kcp-demo differs from start-kcp's $PWD/.kcp: a stop without ROOT targets a different market network's root.
  • accept.sh:78-91 free_port (python bind 0, read, close) for kcp, kine, openbao: listen-close-rebind race (org NEVER rule). The kernel's ephemeral range on hat-8 is 32768-60999, so any outbound connect from another market network can take the port in between. Rare, but N market networks x many connects makes it real.
  • deploy/run-kcp-instance.sh:8,23 refuses KCP_SECURE_PORT=0 ("kcp cannot switch --secure-port off with 0") - contradicts kcp-spike.md 1 (--secure-port=0 --experimental-bind-free-port works, bound port in admin.kubeconfig 0.3-1.8 s after exec). Resolve before relying on either.
  • Fix: kcp port 0 + read-back (kcp-spike); kine/openbao port 0 + /proc/<pid> LISTEN read-back, or a lease from the per-user lease file keyed by (MARKET_NETWORK_ID, purpose). Record all in market-network.json.
  • Vendored twin: deno-kcp/deploy/start-kcp.sh:4-6 (same defaults), demo.sh:26-27 (16444/23792), demo-deno-runtime.sh:14-15 (16443/23791 - same kine port as start-kcp's default).

B8. OpenBao - MEDIUM

  • deploy/denokcp/start-openbao.sh:15-16 DIR=$REPO/.kcp-openbao, ADDR=127.0.0.1:8200; apply.sh:135 default 8200. accept.sh overrides both (OPENBAO_DIR under ACCEPT_ROOT, sniffed port).
  • bao server -dev may also bind a cluster listener at listen port + 1 (Vault dev behaviour; unverified for this openbao build). With random ports that is an occasional collision.
  • Fix: port from market network record; pass an explicit cluster address or verify none is bound.

B9. apply.sh state defaults under the checkout - MEDIUM

  • apply.sh:24 KCACHE=mktemp (fine); :27 KUBECONFIG=$REPO/.kcp-demo/admin.kubeconfig; :29-31 key files $REPO/.kcp-demo/*.hex; :78 GUEST_TLS_DIR=$REPO/.kcp-demo/guest-tls.
  • accept.sh:287-297 overrides every one into ACCEPT_ROOT, so market networks via accept.sh are fine; two market networks driven by bare apply.sh from one checkout share keys, kubeconfig and the guest CA.
  • Fix: default all of them to $MARKET_NETWORK_DIR and refuse to run without MARKET_NETWORK_ID.

B10. Org-root path rewrite - MEDIUM

  • Manifests hardcode /home/johnandersen777/src/publicdomainrelay-kcp/... in SERVICE_ENTRY / SERVICE_CWD (e.g. 40-alice-pds.yaml:14-15, 70-bidder.yaml:15); apply.sh:171 sed rewrites it to $ORG_ROOT; apply.sh:18 / accept.sh:26 default ORG_ROOT=$REPO/...
  • Two tasks sharing one org root run the same code (fine) but share every repo-relative write (B3). A task working in a git worktree of socialweb-computer-kcp only (e.g. under .claude/worktrees) gets a wrong $REPO/..; marketnetwork live_test.go:63-73 then refuses (siblings must be real dirs).
  • Fix: ORG_ROOT required in the market network record; a task tree that changes sibling repos needs its own org root checkout (or worktrees of each sibling under one per-task org root).

B11. Bidder state in $HOME/.cache/pdr-market - HIGH (atproto-market)

  • atproto-market/hono-bidder/cli-args-env.ts:53 oauth-session-path, :239 private-key-hex-path, :245 pds-state-path (Deno KV sqlite) all default to $HOME/.cache/pdr-market/bidder-*.
  • The pod passes the host HOME through (70-bidder.yaml childEnv) and no --pds-state-path. The key is overridden by REPO_PRIVATE_KEY_HEX (cli-args-env.ts:21), the session is unused under --skip-qr, but every bidder in every market network opens the same bidder-pds KV.
  • Fix: --pds-state-path <runDir>/bidder-pds (or $MARKET_NETWORK_DIR/bidders/<n>/pds) in the manifest; same for the session path. Same pattern in atproto-market/request-vm-ssh/cli-args-env.ts:26,63,212 (not used by the market network's market-requester).

B12. One bidder per market network - HIGH for the "several bidders" goal

  • 70-bidder.yaml:4 pod bidder in workspace bob; apply.sh:31 one BIDDER_KEY_FILE; accept.sh:465 takes the first did:plc from the bidder log.
  • Fix: render bidder-<n> pods (n = 1..MARKET_NETWORK_BIDDERS) each with port 0, its own key file $MARKET_NETWORK_DIR/bidders/<n>/key.hex, its own pds-state-path, and the same market network FC work root (guest names are random). market-network.json lists all bidder DIDs; the requester gets --bidder-dids from it. Several requesters per market network already work: market-requester binds port 0 (market-requester/mod.ts:111) and takes --result-file per run.

B13. FC work root and the socket-length limit - HIGH

  • apply.sh:53-71 and live_test.go:84-87 refuse a work root whose fc-000000000000-00000000/fc.sock exceeds 107 bytes. /home/johnandersen777/.local/state/swc-tasks/ is 45 bytes; a 24-char task name + /market-networks/<8>/guests/ + 32 = 115+. A TASK_STATE_DIR-keyed work root fails this check.
  • bob-bidder.sh:45 and the TS live tests' documented /var/lib/socialweb/guests are one shared root.
  • Fix: FC_WORK_ROOT=/var/tmp/swc-$MARKET_NETWORK_ID (22 + 32 = 54 bytes), symlink into $MARKET_NETWORK_DIR. Never share a work root between market networks: accept.sh:141-155 stop_own_guests kills every container named after a directory in it. Add --label swc.market-network=$MARKET_NETWORK_ID to guest containers (hono-compute-provider/lib/microvm-firecracker/mod.ts:228-231) and sweep by label.

B14. Runner image tag - MEDIUM

  • localhost/socialweb-firecracker-runner:local (bob-bidder.sh:44, scripts/deploy-firecracker-bidder.sh:194, socialweb-computer-k8s/test/live_market_node_test.ts:21 docs; tests take SOCIALWEB_FIRECRACKER_RUNNER_IMAGE).
  • hono-compute-provider/deno.json:67 build:firecracker-runner writes socialweb-nodeboot and firecracker into hono-firecracker-standalone/ in the source tree, then tags ${RUNNER_IMAGE:-atcr.io/.../socialweb-firecracker-runner:latest}. Two concurrent builds race on the build context; a rebuild retags under a running market network so its next guest boots a different runner.
  • Fix: build into $TASK_STATE_DIR/build/runner, tag localhost/socialweb-firecracker-runner:sha-<12> (hash of Dockerfile + nodeboot + firecracker), record the tag/digest in market-network.json; the market network passes that tag, never :local.

B15. Deno KV default paths - LOW today, latent

  • hono-pds/main.ts:33 DenoKvStorage.create() (no path) and atproto-relay/lib/hono-factory-atproto-relay-xrpc/mod.ts:47 Deno.openKv() (no path): KV location is DENO_DIR/location_data/<hash(main module)>. Today it is per run because the runner sets DENO_DIR=<runDir>/.deno (kcp-libs/impl/execrunner/pod.go:198-205, appended to os.Environ() at supervisor.go:138) and the pod script's Deno.Command inherits it. If anyone sets DENO_DIR in the pod env (to share the module cache, a natural speed fix) alice+bob PDS and every market network's PDS/relay share one KV.
  • Fix: add a kv-path option to hono-pds and the relay (cli-args-env, default "" = today) and set it to <runDir>/kv.sqlite3 in the manifests; or add --location=http://<pod>.<ws>.<MARKET_NETWORK_ID>.market-network/ to SERVICE_DENO_FLAGS.

B16. Names that are already per market network - no action

  • Workspaces global relay alice bob (00-workspaces.yaml; apply.sh:33, accept.sh:65) and DenoPod names plc relay dispatcher dispatcher-tls pds verifier bidder are per kcp, and each market network runs its own kcp. Only if market networks ever share one kcp (dev-run-mode N2): root:market-network-$MARKET_NETWORK_ID:{global,...}.
  • *.svc.kcp.local FQDNs resolve through each provider's own shim table: per market network.
  • relay.localhost, *.relay.localhost, pds.default.*.svc.kcp.local on the host: names are not a host resource; loopback resolution plus the per-market-network port separates market networks. Guests map relay.localhost to HOST_IP via --guest-host-aliases (accept.sh:511). Each market network signs its own relay.localhost leaf with its own CA (apply.sh:79-94 under GUEST_TLS_DIR). Keep.
  • Firecracker DEFAULT_RANGE_BASE = "172.30.0.0" (hono-compute-provider/lib/compute-provider-firecracker/mod.ts:110, scripts/deploy-firecracker-bidder.sh:195), per-bidder nextIndex (:570,648): each guest runs in its own runner container (no --network, default bridge, microvm-firecracker/mod.ts:228-231,298) with pasta and the tap inside that container's netns, so two bidders handing out 172.30.0.1 do not meet. GUEST_SSH_BIND = "0.0.0.0" (:114) is inside the container netns too. Keep; only matters if a host-netns runner mode is ever added.
  • Guest container names fc-<shortId(requester)>-<uuid8> (compute-provider-firecracker/mod.ts:645): unique.

3. Ranked blocker list (two live RFP-flow market networks at once)

#BlockerFixPlan hook
1B2 servicenames reads ports from manifest argsstatus.address from <runDir>/port-bound-to; table file re-read0008 M1-MARKET-NETWORK-PARALLEL
2B1 manifests 2583-2589port 0 + FQDNs; render bidder after dispatcher ports knownsame
3B3 port-file in source cwdPORT_FILE=<runDir>/port-bound-to in pod scriptsame
4B4 accept.sh literalsread market-network.json / denopod statussame
5B5 one-network-per-host refusaldelete; market network slot flocksame
6B11 bidder KV under ~/.cache--pds-state-path per biddernew
7B13 FC work root length/sharing/var/tmp/swc-$MARKET_NETWORK_ID, docker labelsame
8B12 single bidderbidder-<n> templatingnew
9B7 kcp/kine/bao sniffed ports, stop-kcp ROOT mismatchport 0 + /proc or lease read-back0006 M2-KCP-PORT0, M1-PORT-LEASE-INSTANCE
10B14 runner image :local + in-tree buildcontent-hash tag in market-network.jsonnew
11B6 m3 gateway binds 2583/2587gw:0 forwards from market-network.json0008 M1-MARKET-NETWORK-PARALLEL
12B9/B10 apply.sh defaults, ORG_ROOT$MARKET_NETWORK_DIR defaults; ORG_ROOT requiredsame

4. How port 0 flows end to end (the minimal change set)

  1. Pod script (each manifest): childEnv.PORT_FILE = runDir + "/port-bound-to"; args --port 0.
  2. Service: unchanged - createServe({ portFile }) already writes the bound port on listen (typescript-helpers/lib/serve/mod.ts:131-136). hono-pds, relay, plc, ingress proxy and bidder all pass portFile through (hono-pds/main.ts:128, hono-atproto-relay/mod.ts:68, hono-plc/mod.ts:30, hono-did-key-ingress-proxy/mod.ts:80, hono-bidder/mod.ts:629). dispatcher-tls is inline in its manifest: write the file from its onListen (36-relay-dispatcher-tls.yaml:31-32).
  3. Runner (kcp-libs execrunner Pod observe): read <runDir>/port-bound-to, report it; provider writes status.address.
  4. servicenames: prefer status.address; publish the table as a run-dir file the shim re-reads.
  5. apply.sh: after each pod is Ready, read status.address into market-network.json; render 70-bidder with the dispatcher (relay.localhost:<p>) and TLS port from market-network.json.
  6. accept.sh / Go tests / requester: read market-network.json only. TestNoNetworkPortIsALiteral enforces it.

5. Secondary findings by repo (not on the market network path)

socialweb-computer-kcp

idfile:linewhatoverrideimpactfix
S-1internal/liveports/liveports.go:67/var/tmp/socialweb-liveports flock dir; blocks 30500-32400, 61000-63839, probe 64000-64255n/aintentional host-global coordination; Slots cap parallel proofs (MountProof 4, SchemaUpgrade 4, others 8). All blocks sit outside the ephemeral range 32768-60999 except 30500-32400 (below it): goodkeep; it is the model for the market network slot
S-2internal/clusterprovider/steps_test.go:401, internal/openbao/openbao_test.go:23,313, internal/vaultcert/vaultcert_test.go:43, internal/materialiser/materialiser_test.go, cmd/socialweb-vault/apply_live_test.go:39, internal/clusterprovider/nodesecrets_test.go:58, links_live_test.go:90listen :0, read, close, rebind (freePort)n/arare races under N taskspass the listener or use port 0 in the child and read back
S-3internal/clusterprovider/live_kcp_test.go:28CLUSTERPROVIDER_LIVE_HOST default https://127.0.0.1:6443envpoints every task at the host's shared kcprequire the env; no default
S-4internal/kcpclient/live_apiserver_test.go:25-29, mount_child_live_test.go:17-20, internal/tenantclient/live_renewal_test.go:32-37, cmd/socialweb-gateway/mintconfig_live_test.go:22-25, internal/clusterprovider/live_tenant_test.go:29-33live tests against an externally supplied kcp/tenant via SOCIALWEB_LIVE_*envtwo tasks given the same target mutate the same workspacesper-task env file under TASK_STATE_DIR
S-5internal/hostsvc/live_linux_test.go:97unit prefix socialweb-test-<rand>-n/asafenone
S-6deploy/run-container.sh:5-7,17-19image socialweb-k8s:local, volume socialweb-computer-kcp-state, name socialweb, -p 127.0.0.1:8443/6443/8788, docker rm -f $NAME firstenv (name, volume, image); ports nosecond run kills the first containername/volume swc-$MARKET_NETWORK_ID, -p 127.0.0.1::<port> + docker port read-back
S-7deploy/control-plane-container/build.sh:7-10,104-105, validate.sh:5, scripts/deploy.sh:11tags socialweb-control-plane:local, -nodeimage:local, socialweb-k8s:local; BINARIES=/var/tmp/socialweb-control-plane-binaries; KCP_IMAGE_DIR=/home/johnandersen777/kcp-imageenvconcurrent builds overwrite the binaries dir and retagcontent-hash tags; binaries dir under TASK_STATE_DIR
S-8deploy/container-entrypoint.sh:8,21,24,28,233/var/lib/socialweb, 8200, 6443, 8080envinside the container: safenone
S-9cmd/socialweb-nodeimage/buildlock_linux.go:17<stage>.lock flock on the shared image storen/aserialises builds correctlykeep; content-addressed store is safe to share
S-10internal/portallocator/portallocator.go:145-148,227; internal/subnetallocator/subnetallocator.go:19,245lease key ignores instance; pool 10.100.0.0/16; one lease file per pathpathtwo instances with two lease files lease the same port/subnet0006 M1-PORT-LEASE-INSTANCE (one per-user file, key by instance)
S-11socialweb-computer-k8s/test/live_market_node_test.ts:261-275pickPort() random 20000-59999 + portIsFree probenooverlaps the portallocator carve 20000-29999, liveports blocks and the ephemeral rangeport 0 for k3s, or take a liveports block
S-12socialweb-computer-k8s/hono-socialweb-computer-k8s/cli-args-env.json:5,17http-port 8788, state-dir .socialweb-computer-k8s (cwd-relative)flag/envtests that start it with defaults collidetests pass 0 + a temp state dir
S-13scripts/deploy-firecracker-bidder.sh:194-195runner :local, RANGE_BASE 172.30.0.0, /var/lib/socialweb-computer-bidder/<handle>envremote production deploy, not a market networknone for market networks
S-14cmd/socialweb-computer-kcp-check-host/config.go:193/dev/kvmn/ahost-global by naturesection 6
S-15Go unit tests with literal ports/paths (internal/clusterstack/clusterstack_test.go:32-55, internal/clusterprovider/steps_test.go:32-50, steps_openbao_test.go:41,166-172, externalsecrets_test.go:88, nodesecrets_test.go:174, kcp/pkg/proxy etc.)spec values, never boundn/asafenone

Vendored upstream trees (kcp/, kata-containers/, cluster-api/, streamplace/, third_party/) were excluded.

deno-kcp

idfile:linewhatfix
D-1deploy/start-kcp.sh:4-6, stop-kcp.sh:19, start-openbao.sh:15-16, install-provider.sh:56443 / 23791 / 8200, $PWD/.kcp, $REPO/.kcp-demo, $REPO/.kcp-openbaosame as B7/B8
D-2deploy/demo.sh:26-27, demo-deno-runtime.sh:14-1516444/23792 and 16443/23791 against one shared $REPO/.kcp-demoper-run root + port 0
D-3deploy/market-network/*.yaml, apply.sh:25-27,84,180-185older copy of the market network: 2583/2584/2587, 8200, .kcp-demo keysretire or regenerate from socialweb-computer-kcp's market network
D-4internal/provider/live_helpers_test.go:68, test/integration/fixture_test.go:151,358-373freePort sniff for kine/kcpport 0 + read-back
D-5cmd/deno-kcp-provider/main.go:79RUNS_DIR default runs (cwd-relative)accept.sh sets it per market network; make it required
D-6deploy/examples/policy-workflow-run.yaml:9, demo.sh:76engine 127.0.0.1:8080port from the engine's port file

kcp-libs

idfile:linewhatfix
K-1factory/servicenames/servicenames.go:166-197 (+:109,:149)address from manifest argsB2
K-2impl/execrunner/pod.go:198-205per-run DENO_DIR (isolates KV by accident, and re-downloads modules per run)keep isolation explicit (B15) before sharing a module cache

atproto-market

idfile:linewhatfix
A-1hono-bidder/cli-args-env.ts:53,239,245,267-272~/.cache/pdr-market/bidder-*, ./port-bound-toB11, B3
A-2request-vm-ssh/cli-args-env.ts:26,63,212; mod.ts:169; lib/atproto-helpers/oauth-qr-session.ts:20~/.cache/pdr-market/requester-*per-task --*-path
A-3hono-plc/cli-args-env.json:5,27port 2587, ./port-bound-toB1/B3
A-4test/bidder_container_integration_test.ts:55-70,182-200port 0 + onListen for dispatcher, TLS and fake PLC; random container namessafe - the model for the market network
A-5test/integration_test.ts (gateway_, registry_discovery, bidder_ssh_relay, ...)all Deno.serve with port: 0safe
A-6test/bidder_firecracker_integration_test.ts:79-84SOCIALWEB_FIRECRACKER_WORK_ROOT (docs: /var/lib/socialweb/guests)per-task short work root (B13)

hono-compute-provider

idfile:linewhatfix
H-1deno.json:67runner build writes into source tree, tag :latestB14
H-2lib/compute-provider-local/mod.ts:197-198,255-293,321-324image tag container-runner-<distro>:latest built-if-absent / force-rebuilt; container name randomcontent-hash tag; concurrent --force rebuilds race
H-3lib/compute-provider-local/mod.ts:125-126,301; lib/qemu-standalone/mod.ts:23-24shared ~/.cache/pdr-local, ~/.cache/simple-qemu (systemctl shim, qemu downloads)write-to-temp + rename; or per-task cache for writes
H-4test/oidc_workload_identity_integration_test.ts:25-31listen 0, close, rebind (ssh + issuer)port 0 in the child
H-5lib/compute-provider-firecracker/mod.ts:110,114,570172.30.0.0, 0.0.0.0, per-process indexsafe (B16)
H-6test/defect3/6, oidc_onnetwork_reporter_test.ts127.0.0.1:9977/9978 issuer strings, never boundsafe

hono-pds, atproto-relay, did-key-ingress-proxy, typescript-helpers

idfile:linewhatfix
P-1hono-pds/main.ts:33default KV pathB15
P-2atproto-relay/lib/hono-factory-atproto-relay-xrpc/mod.ts:47default KV pathB15
P-3hono-pds, hono-atproto-relay, hono-did-key-ingress-proxy cli-args-env.jsonports 2583/2584/8080, ./port-bound-toB1/B3
P-4hono-pds/test/oauth_client_fetch_ssrf_test.ts:6, docs-compliance.test.ts:152-193127.0.0.1:2583 as request URL/issuer strings; server on port 0safe
T-1typescript-helpers/lib/serve/mod.ts:114-147createServe port 0 + onListen + portFilethe fix mechanism

Other org repos

idfile:linewhatfix
O-1socialweb-computer-ssh/hono-socialweb-computer-ssh/cli-args-env.jsonssh 2222, http 8787, state-dir cwd-relative, ./port-bound-to0 + per-task dir in tests
O-2did-key-associator/hono-backend/cli-args-env.jsonport 5557, ./port-bound-tosame
O-3policy-engine/hono-policy-engine/cli-args-env.jsonport 8080, ./port-bound-tosame
O-4digitalocean-bidder/lib/digitalocean-oauth/test/mod_test.ts:22localhost:9999 redirect string; servers port 0safe

Org-root dev scripts

idfile:linewhatfix
R-1alice-request.sh:4, bob-bidder.sh:26ORG_ROOT hardcoded${ORG_ROOT:-...}
R-2alice-request.sh:7, bob-bidder.sh:32OAuth session ~/.cache/pdr-market/{alice-request,bob-bidder}-oauth-session.jsonreal-account scripts: one person, one session; never run from parallel tasks
R-3bob-bidder.sh:44-45runner :local, FC_WORK_ROOT=/var/lib/socialweb/guestsB13/B14
R-4bob-bidder.sh:31,83SERVE_PORT=0 (good) but port-file lands in atproto-market/port-bound-toPORT_FILE per run

6. Host-global resources that cannot be per task, and a slot limit

hat-8 readings (2026-10-11): 16 CPUs, 46 GiB RAM (39 GiB available), 960 GiB free on /, ip_local_port_range 32768 60999, fs.inotify.max_user_instances 128, /dev/kvm mode 0666 (group kvm), 40 liveports lock files present.

Shared and not partitionable:

  • /dev/kvm and CPU: no exclusive use, but contention slows guest boot past VM_READY timeouts.
  • RAM: guests default mem_mib 2048 (socialweb-nodeboot/main.go:57); a market network's control processes (kcp, kine, bao, provider, ~7 deno services, requester) are about 2-3 GiB (estimate; measure).
  • Disk: guest disks in work roots, nodeimage store (content-addressed, flocked), docker image store.
  • dockerd and the default bridge (one gateway, ~65k addresses), pasta, /dev/net/tun.
  • Kernel ephemeral port range (all port-0 binds draw from it; leases must stay outside it).
  • inotify instances (128 per user): kcp/k3s/kine and file watchers; N market networks may hit it - measure.
  • Shared caches: ~/.cache/deno, Go build/mod cache (safe, internally locked), ~/.kube/cache (keyed by server host:port; benign).
  • /var/tmp/socialweb-liveports (coordination point, keep).

Slot limit (simple, reuses the liveports pattern):

  • SWC_MARKET_NETWORK_SLOTS (default 4 on hat-8). A market network takes flock(LOCK_EX|LOCK_NB) on /var/tmp/socialweb-market-network-slots/<i>.lock for i in 0..SLOTS-1 (start at pid % SLOTS, as liveports.TakeForProcess does), holds it for its lifetime, writes MARKET_NETWORK_ID + pid into it for diagnosis, and refuses or waits when none is free. In Go: a liveports.Block{What: "the market network", Slots: 4, Width: 0}; in shell: exec 9>"$lock"; flock -n 9.
  • Memory gate before taking a slot: refuse when MemAvailable < 3 GiB + MARKET_NETWORK_GUESTS x 2.5 GiB (2 GiB guest + VMM/pasta/runner overhead), as plan 0008 M1-MARKET-NETWORK-PARALLEL's risk note already asks. With 2 guests per market network that is 8 GiB/market network: 4 market networks = 32 GiB of 39 available.
  • Guest cap per market network: the bidder's --policy / a max-concurrent-guests option, so one market network cannot take every slot's memory.