Wanderland

PKB on CoreWeave via the Compute Plane

ADV-455 · case task-0e952514-c8e0-4a13-8a52-b85fa8550ecf · status: design, nothing deployed

Deploy the Protein Knowledge Base (PKB) Docker workflow on CoreWeave by running it as a driver on the existing compute plane — Nextflow schedules, advaita-service-wisp routes, Kueue queues, foxfire records — rather than hand-orchestrating Jenkins jobs. Full platform model: advaita-nextflow-router-data-model.

Summary

PKB's acquire → governed-build → promote pipeline becomes a Nextflow workflow registered as a wisp job_type. Each phase is a task pod; the pod carries a securityContext (the container contract), volume mounts, and an egress-class label that a standing NetworkPolicy selects. The build steps that are traditional CI/CD (building the PKB image) shell out to Wanderland, which already emits signed traces. Both trace streams — Nextflow's (via nf-foxfire) and Wanderland's — land in foxfire.

We prove the whole shape as a mock in vivarta-examples first (that is where example projects live), on the Foxfire+Wanderland base image, then fill in Grant's real PKB container when the repo lands.

Architecture map

Layer Role Repo
Nextflow driver one-shot k8s Job per run; expands the workflow into task pods driver image (nf-driver-base + workflows)
wisp POST /submit → classify → size from history → launch driver gated by Kueue. Registration = one config/templates.yml entry, no code wisp
Kueue driver Job → drivers cohort; task pods → workers-<immediacy>-<compute> wisp/k8s/kueue
foxfire signed (EC-P256) plan / placement / trace ledgers joined on run_id foxfire
synth reference driver project to copy synth

How PKB maps

The trace question — Wanderland Crossing vs foxfire envelope

Goal: send Wanderland's per-boundary traces to foxfire so CI/CD steps done in Wanderland are captured next to the Nextflow trace. The two are the same envelope family at two hardening levels — not byte-identical.

Wanderland Crossing (wanderland-core/lib/wanderland/crossing.rb) — one per boundary execution: boundary, from_addr, to_addr, type_addr, trace, result, requirements, capabilities, at, duration_ms, signature. Signs canonical (the whole record minus signature/duration, sorted-key JSON) under from_addr via Activities::PKI (EC P-256). trace = the merkle causal link (previous crossing's signature). Sink today = per-run SQLite .db files under a trace root (boundaries/trace/trace_stores.rb), read by trace_query/trace_runs/trace_replay.

foxfire envelope (foxfire/docs/event-envelope.md, boundaries/ingest_signed.rb): key_id, to, from, type, payload(JSON string), trace_hash, signature. Signs signable = key_id\nto\nfrom\ntype\ntrace_hash — addresses + a content hash of the payload, not the payload bytes. foxfire's ingest boundary literally include Wanderland::Boundary, and its signing "matches Wanderland::Activities::PKI."

Same: four-address model, type-classified, signed, one EC-P256 PKI, and foxfire's receiver IS a Wanderland boundary. The instinct that "foxfire input is the same schema as the engine" is right at the envelope level.

Different, and why:

foxfire's envelope is the cross-runtime, cross-process hardening of the same crossing. The engine's crossing never leaves the process, so it signs the canonical record and chains by signature; foxfire's must survive a JVM→Ruby hop and key rotation, so it adds key_id + payload-hash + string-payload.

The hole to fill (two ends):

The mock (in vivarta-examples)

Prove the shape end-to-end before Grant's container exists:

Steps

Blocked / standing

Wiring the emitter — an injection, not top-level machinery

Graeme's call, and it's right: don't add a bespoke trace sink to Core. Build the Wanderland→foxfire step as a boundary and compile it into the chain via the injection registry, declared in the site vivarta.yml. It fires every slot, the way enforce_denials does.

Doc-vs-code note. wanderland-core-interceptors (Draft, 2026-04-09) describes this as an "interceptor" with before/after hooks on Boundary.execute + run_levels. The code implements it as injections, not interceptorswanderland-core/lib/wanderland/injection.rb (InjectionRegistry) + the register_injections boot boundary, applied at route-compile; no Interceptor module exists. Use the injection mechanism (what the primer documents and what enforce_denials / trace_emit already use). Position vocabulary: first / last / interleave / {before: name} / {after: name}.

The emitter:

trace_emit already exists as a core injection (position last) recording the crossing; foxfire_emit is its externalizing sibling. No engine change beyond adding the boundary + the config line. The env gate is just "is the injection present + the :http adapter's foxfire URL set." Open sub-item: extend trace_emit to take an endpoint vs add foxfire_emit beside it — the latter keeps Core untouched (preferred). This supersedes the earlier "external trace sink in wanderland-core" framing in the trace-question section above.