Skip to content

fix: omit core metadata when reusing W&B sandboxes - #1930

Merged
steipete merged 2 commits into
mainfrom
codex/wandb-run-metadata-next
Sep 6, 2026
Merged

fix: omit core metadata when reusing W&B sandboxes#1930
steipete merged 2 commits into
mainfrom
codex/wandb-run-metadata-next

Conversation

@steipete

@steipete steipete commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Ordinary W&B run --id calls were rejected before ownership lookup or execution because the CLI always injects CRABBOX_LEASE_ID, CRABBOX_RUN_ID, and CRABBOX_SLUG, while the existing-sandbox env guard accepted only implicit CI/NODE_OPTIONS defaults.

The private wandbExistingIDEnvCanBeOmitted helper uses the existing core.IsRunExecutionMetadataEnvName predicate to omit those exact core-owned metadata names before applying the existing env-summary/default-env rules. Metadata-only requests can proceed even when an env summary was requested. Explicitly selected CI, NODE_OPTIONS, custom variables and similarly named nonreserved variables remain rejected. The old implicit uppercase CI/NODE_OPTIONS omission exception remains intact.

This does not add env support to the CoreWeave Exec RPC, forward metadata through command text, or refresh the sandbox's original Start-time environment. The protobuf has no Exec env field. Existing claim/tag authorization, Start/Stop lifecycle, timing finalization, transport/TLS and auth policy are unchanged. The documentation explains that distinction; the small Unreleased entry follows the larger features and existing W&B lifecycle entry without a placeholder PR link.

Complete captured CLI behavior

This unchanged complete capture is placed first so a shortened PR description still includes all reuse, rejection and cleanup evidence. The fixture and method details follow.

Acquire, all eight reuse controls, exact Exec payloads, claim and Stop cleanup
{
  "acquire": {
    "exitCode": 0,
    "output": "provisioning provider=wandb image=ubuntu:24.04 max_lifetime=1800s\nprovisioned sandbox=sb-metadata-audit status=running\nsynthetic-rpc-proof\n"
  },
  "cases": [
    {
      "connectionsAfter": 2,
      "connectionsBefore": 1,
      "name": "metadata-only",
      "newRPC": [
        "/coreweave.sandbox.v1beta2.GatewayService/List",
        "/coreweave.sandbox.v1beta2.GatewayService/Exec"
      ],
      "run": {
        "exitCode": 0,
        "output": "synthetic-rpc-proof\n"
      }
    },
    {
      "connectionsAfter": 3,
      "connectionsBefore": 2,
      "name": "metadata-only-summary",
      "newRPC": [
        "/coreweave.sandbox.v1beta2.GatewayService/List",
        "/coreweave.sandbox.v1beta2.GatewayService/Exec"
      ],
      "run": {
        "exitCode": 0,
        "output": "synthetic-rpc-proof\n"
      }
    },
    {
      "connectionsAfter": 4,
      "connectionsBefore": 3,
      "name": "implicit-defaults",
      "newRPC": [
        "/coreweave.sandbox.v1beta2.GatewayService/List",
        "/coreweave.sandbox.v1beta2.GatewayService/Exec"
      ],
      "run": {
        "exitCode": 0,
        "output": "synthetic-rpc-proof\n"
      }
    },
    {
      "connectionsAfter": 4,
      "connectionsBefore": 4,
      "name": "explicit-ci",
      "newRPC": [],
      "run": {
        "exitCode": 2,
        "output": "provider=wandb cannot forward env vars to an existing sandbox (--id); rerun without --id or omit --allow-env\n"
      }
    },
    {
      "connectionsAfter": 4,
      "connectionsBefore": 4,
      "name": "explicit-node",
      "newRPC": [],
      "run": {
        "exitCode": 2,
        "output": "provider=wandb cannot forward env vars to an existing sandbox (--id); rerun without --id or omit --allow-env\n"
      }
    },
    {
      "connectionsAfter": 4,
      "connectionsBefore": 4,
      "name": "explicit-custom",
      "newRPC": [],
      "run": {
        "exitCode": 2,
        "output": "provider=wandb cannot forward env vars to an existing sandbox (--id); rerun without --id or omit --allow-env\n"
      }
    },
    {
      "connectionsAfter": 4,
      "connectionsBefore": 4,
      "name": "prefix-lookalike",
      "newRPC": [],
      "run": {
        "exitCode": 2,
        "output": "provider=wandb cannot forward env vars to an existing sandbox (--id); rerun without --id or omit --allow-env\n"
      }
    },
    {
      "connectionsAfter": 4,
      "connectionsBefore": 4,
      "name": "suffix-lookalike",
      "newRPC": [],
      "run": {
        "exitCode": 2,
        "output": "provider=wandb cannot forward env vars to an existing sandbox (--id); rerun without --id or omit --allow-env\n"
      }
    }
  ],
  "claimBeforeStop": {
    "claimedAt": "2026-09-06T21:58:10Z",
    "cloudID": "sb-metadata-audit",
    "idleTimeoutSeconds": 1800,
    "lastUsedAt": "2026-09-06T21:58:10Z",
    "leaseID": "sb-metadata-audit",
    "provider": "wandb",
    "providerScope": "endpoint:127.0.0.1%3A43001|entity:synthetic-entity|project:synthetic-project",
    "repoRoot": "",
    "revision": "<synthetic-claim-revision>",
    "slug": "sb-metadata-audit"
  },
  "execRequests": [
    {
      "sandboxId": "sb-metadata-audit",
      "command": [
        "true"
      ]
    },
    {
      "sandboxId": "sb-metadata-audit",
      "command": [
        "true"
      ]
    },
    {
      "sandboxId": "sb-metadata-audit",
      "command": [
        "true"
      ]
    },
    {
      "sandboxId": "sb-metadata-audit",
      "command": [
        "true"
      ]
    }
  ],
  "finalClaimCount": 0,
  "finalRPC": [
    "/coreweave.sandbox.v1beta2.GatewayService/Start",
    "/coreweave.sandbox.v1beta2.GatewayService/Get",
    "/coreweave.sandbox.v1beta2.GatewayService/Exec",
    "/coreweave.sandbox.v1beta2.GatewayService/List",
    "/coreweave.sandbox.v1beta2.GatewayService/Exec",
    "/coreweave.sandbox.v1beta2.GatewayService/List",
    "/coreweave.sandbox.v1beta2.GatewayService/Exec",
    "/coreweave.sandbox.v1beta2.GatewayService/List",
    "/coreweave.sandbox.v1beta2.GatewayService/Exec",
    "/coreweave.sandbox.v1beta2.GatewayService/List",
    "/coreweave.sandbox.v1beta2.GatewayService/Stop"
  ],
  "finalSandboxPresent": false,
  "initialRPC": [
    "/coreweave.sandbox.v1beta2.GatewayService/Start",
    "/coreweave.sandbox.v1beta2.GatewayService/Get",
    "/coreweave.sandbox.v1beta2.GatewayService/Exec"
  ],
  "portClosed": true,
  "scope": "actual unmodified CLI+production constructor using existing loopback plaintext mode; gRPC responses are synthetic, no TLS or hosted/native workload claim",
  "serverStopped": true,
  "startMetadata": {
    "CRABBOX_LEASE_ID": "",
    "CRABBOX_RUN_ID": "run_4e80eace5994",
    "CRABBOX_SLUG": ""
  },
  "stop": {
    "exitCode": 0,
    "output": ""
  }
}

Tests-first evidence

Against base 69e79538dae281148ed3475329bfc6eeaf53b58f, the new 12-case helper table failed its four metadata-positive cases before the fix. Its eight existing default/rejection controls passed. The updated seeded existing-ID backend test also failed before the fix, then passed with metadata included in its request.

The table covers metadata-only, metadata-only plus summary, owner-defined case folding, implicit defaults, metadata plus implicit defaults, explicit CI/NODE_OPTIONS, custom env, prefix/suffix/padded lookalikes, and lowercase ci remaining outside the old default exception. No broad CRABBOX_* prefix exemption was added.

An earlier preserved actual-CLI audit on 4e3df6dfc42a49bd665a92b2e2756b909122c8c3 acquired a real local ownership claim through its protocol fixture, then reproduced this rejection on the same sandbox:

provider=wandb cannot forward env vars to an existing sandbox (--id); rerun without --id or omit --allow-env

That earlier reuse exited 2, opened no new connection, and left the RPC trace unchanged at Start/Get/Exec; explicit CLI Stop then cleaned up. It is historical negative evidence, not the current candidate's receipt.

Fresh candidate checks:

go test -race ./internal/providers/wandb ./internal/providers/shared -count=1
go vet ./internal/providers/wandb ./internal/providers/shared
go test ./internal/cli -run TestIsRunExecutionMetadataEnvName -count=1
node scripts/check-docs-links.mjs
git diff --check

Actual race output:

ok  	github.com/openclaw/crabbox/internal/providers/wandb	2.947s
ok  	github.com/openclaw/crabbox/internal/providers/shared	2.446s

Fresh focused vet and diff checks passed. The canonical core predicate and 246-file documentation checks passed before the private-symbol rename; those files remain byte-identical. The complete revised four-file candidate received a fresh managed Codex review with no actionable P0 findings. That scoped threshold is not a claim of lower-priority review coverage.

Actual built CLI and production constructor

The byte-identical fixture was replayed against a freshly built candidate after the private-helper rename; this receipt and binary are separate from the original proof. The fixture invokes the built candidate CLI by absolute path and uses its unchanged production gRPC constructor with the existing, explicitly supported plaintext loopback-only endpoint mode. The auth headers and responses are synthetic. No TLS/trust setting or production transport was changed. This is CLI/client protocol proof, not TLS, hosted W&B, or native sandbox-workload execution proof; the returned synthetic-rpc-proof text is a fixture response.

The fixture first acquires and keeps a sandbox, creating the normal exact local claim. It then runs these cases against that owned ID:

Reuse case CLI exit New RPCs / connections
Core metadata only 0 List → Exec; one connection
Core metadata only with summary requested 0 List → Exec; one connection
Implicit CI/NODE_OPTIONS defaults 0 List → Exec; one connection
Explicit CI 2 None
Explicit NODE_OPTIONS 2 None
Explicit custom variable 2 None
CRABBOX_RUN_ID_EXTRA lookalike 2 None
PREFIX_CRABBOX_RUN_ID lookalike 2 None

Each successful reuse adds only List/Exec: no Acquire/Start and no automatic Stop. Each rejected case is checked for both zero new RPCs and zero new accepted connections. Finally, the actual CLI Stop adds List/Stop and removes the sandbox/claim. The fixture verifies the server exits and its port is closed; temporary state is owned by Go's t.TempDir cleanup.

The actual Start request contained the three injected metadata names, while all four captured Exec requests (initial command plus three successful reuses) were exactly:

{"sandboxId":"sb-metadata-audit","command":["true"]}

No metadata, CI/NODE_OPTIONS, environment field or shell wrapper was added to Exec. The fixture had one compile-time assertion correction while being written: protobuf command is repeated, so it is compared as a one-element slice. That failed compile is preserved separately and is not provider or runtime evidence.

Capture display substitutions

Only the ephemeral endpoint port in the claim scope and its generated revision are substituted in the complete capture above. Actual exit codes, outputs, RPCs, connection counts and metadata fields are retained. Raw proof remains unchanged and is the input to the receipt hash.

Exact tested inputs

Base: 69e79538dae281148ed3475329bfc6eeaf53b58f plus this four-file diff. These hashes identify the actual tested source/binary/fixture, not a later merge commit. Original negative-audit artifacts remain unchanged.

f4883cfa23d873091a0a3cbc80339ebaae5b3bb562d33f4a272d2e5787a55b85  CHANGELOG.md
f6cd713def804c2066e3a66ef97acc4376956f515ca12aa85ea8dafa0d87e675  docs/providers/wandb.md
8a4c68decde77caf92479bea788a5b19ecfef06e32373d5a8f40a0d9c8e4b9c1  internal/providers/wandb/backend.go
2fd21bfa175519923a98c1e0136bcac731d17d5e133628c576d2e7123ca0c5e7  internal/providers/wandb/backend_test.go
a588050af1b2e616c03b034daf342663bba9102ec359e3abae7685a6826c5def  internal/cli/run_env_profile.go
82c1d1fb49707099088b8256ed956eea682b1dc694e35eb468e311c215df3464  internal/providers/wandb/client.go
58dfc9b689251a9af94af0fd4bd39ae0ce5f0e07552e11f4f8bddb9137c599d5  candidate.patch
9d668e12d4786a520763a9d6a65cc1283c370586806e1a32d5f51673f17c31ee  crabbox
d997c6673293dfccf55ad9fdb0cd7c496f9a60e16491e994b57f6d4bdabec3f2  fixture_test.go
baf6fedbce17876e7831ce2b1773fe085b0bd1cd7b0e808b730ec97e1a9ca70f  native-receipt.json

Runnable fixture

Save the exact Go fixture below outside the repository. From the candidate checkout, build the uninstrumented CLI and add the test file through a Go overlay. Requires Go and Git on a POSIX host. Only synthetic credentials are passed to the child CLI; the fixture creates its own local state and server.

wandb_proof_dir="$(mktemp -d /tmp/crabbox-wandb-metadata.XXXXXX)"
# Save the fixture below as "$wandb_proof_dir/fixture_test.go".
python3 - "$PWD" "$wandb_proof_dir" <<'PY_OVERLAY'
from pathlib import Path
import json, sys
repo, proof = map(lambda p: Path(p).resolve(), sys.argv[1:])
(proof / 'overlay.json').write_text(json.dumps({'Replace': {
    str(repo / 'internal/providers/wandb/native_metadata_fixture_test.go'):
        str(proof / 'fixture_test.go'),
}}))
PY_OVERLAY
go build -trimpath -o "$wandb_proof_dir/crabbox" ./cmd/crabbox
WANDB_AUDIT_CLI="$wandb_proof_dir/crabbox" go test -race \
  -overlay "$wandb_proof_dir/overlay.json" ./internal/providers/wandb \
  -run TestActualCLIMetadataReuseAndRejectionControls -count=1 -v

The CLI_METADATA_RECEIPT line contains the complete capture. Archive the binary/receipt before removing the owned proof directory.

Full fixture_test.go (byte-exact fixture matching the hash above)
package wandb

import (
	"context"
	"encoding/json"
	"fmt"
	sandboxv1 "github.com/openclaw/crabbox/internal/providers/wandb/gen/coreweave/sandbox/v1beta2"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
	"google.golang.org/protobuf/encoding/protojson"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)

type auditCountingListener struct {
	net.Listener
	accepted atomic.Int64
}

func (l *auditCountingListener) Accept() (net.Conn, error) {
	c, e := l.Listener.Accept()
	if e == nil {
		l.accepted.Add(1)
	}
	return c, e
}

type metadataAuditGateway struct {
	sandboxv1.UnimplementedGatewayServiceServer
	mu           sync.Mutex
	rpc          []string
	present      bool
	startEnv     map[string]string
	execRequests []json.RawMessage
}

func (s *metadataAuditGateway) Start(_ context.Context, r *sandboxv1.StartSandboxRequest) (*sandboxv1.StartSandboxResponse, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.present = true
	s.startEnv = r.EnvironmentVariables
	return &sandboxv1.StartSandboxResponse{SandboxId: "sb-metadata-audit"}, nil
}
func (s *metadataAuditGateway) Get(context.Context, *sandboxv1.GetSandboxRequest) (*sandboxv1.GetSandboxResponse, error) {
	return &sandboxv1.GetSandboxResponse{SandboxStatus: sandboxv1.SandboxStatus_SANDBOX_STATUS_RUNNING}, nil
}
func (s *metadataAuditGateway) List(context.Context, *sandboxv1.ListSandboxesRequest) (*sandboxv1.ListSandboxesResponse, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	out := &sandboxv1.ListSandboxesResponse{}
	if s.present {
		out.Sandboxes = []*sandboxv1.SandboxInfo{{SandboxId: "sb-metadata-audit", SandboxStatus: sandboxv1.SandboxStatus_SANDBOX_STATUS_RUNNING}}
	}
	return out, nil
}
func (s *metadataAuditGateway) Exec(_ context.Context, r *sandboxv1.ExecSandboxRequest) (*sandboxv1.ExecSandboxResponse, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	data, err := protojson.Marshal(r)
	if err != nil {
		return nil, err
	}
	s.execRequests = append(s.execRequests, data)
	if (len(r.GetCommand()) != 1 || r.GetCommand()[0] != "true") || len(r.GetArgs()) != 0 {
		return nil, fmt.Errorf("unexpected Exec command")
	}
	return &sandboxv1.ExecSandboxResponse{Result: &sandboxv1.ExecResponse{ExitCode: 0, Stdout: []byte("synthetic-rpc-proof\n")}}, nil
}
func (s *metadataAuditGateway) Stop(context.Context, *sandboxv1.StopSandboxRequest) (*sandboxv1.StopSandboxResponse, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.present = false
	return &sandboxv1.StopSandboxResponse{Success: true}, nil
}
func (s *metadataAuditGateway) snapshot() ([]string, bool, map[string]string) {
	s.mu.Lock()
	defer s.mu.Unlock()
	env := map[string]string{}
	for k, v := range s.startEnv {
		env[k] = v
	}
	return append([]string(nil), s.rpc...), s.present, env
}

func TestActualCLIMetadataReuseAndRejectionControls(t *testing.T) {
	binary := os.Getenv("WANDB_AUDIT_CLI")
	if !filepath.IsAbs(binary) {
		t.Fatal("WANDB_AUDIT_CLI must be an absolute built CLI path")
	}
	raw, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	listener := &auditCountingListener{Listener: raw}
	gateway := &metadataAuditGateway{}
	server := grpc.NewServer(grpc.UnaryInterceptor(func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
		md, _ := metadata.FromIncomingContext(ctx)
		if strings.Join(md.Get("x-wandb-api-key"), "") != "synthetic-fixture-only" || strings.Join(md.Get("x-entity-id"), "") != "synthetic-entity" {
			return nil, fmt.Errorf("wrong fixture auth")
		}
		gateway.mu.Lock()
		gateway.rpc = append(gateway.rpc, info.FullMethod)
		gateway.mu.Unlock()
		return handler(ctx, req)
	}))
	sandboxv1.RegisterGatewayServiceServer(server, gateway)
	done := make(chan struct{})
	go func() { defer close(done); _ = server.Serve(listener) }()
	defer func() {
		server.Stop()
		_ = listener.Close()
		select {
		case <-done:
		case <-time.After(time.Second):
			t.Error("server did not stop")
		}
	}()
	root := t.TempDir()
	repo := filepath.Join(root, "repo")
	if err := os.Mkdir(repo, 0o700); err != nil {
		t.Fatal(err)
	}
	env := []string{"PATH=" + os.Getenv("PATH"), "HOME=" + filepath.Join(root, "home"), "XDG_CONFIG_HOME=" + filepath.Join(root, "config"), "XDG_STATE_HOME=" + filepath.Join(root, "state"), "TMPDIR=" + root, "CRABBOX_WANDB_API_KEY=synthetic-fixture-only", "WANDB_ENTITY_NAME=synthetic-entity", "WANDB_PROJECT=synthetic-project", "CWSANDBOX_BASE_URL=http://" + listener.Addr().String(), "GIT_CONFIG_NOSYSTEM=1", "GIT_CONFIG_GLOBAL=/dev/null"}
	git := exec.Command("git", "init", "-q", repo)
	git.Env = env
	if out, err := git.CombinedOutput(); err != nil {
		t.Fatalf("git init:%v %s", err, out)
	}
	invokeEnv := func(extra []string, args ...string) map[string]any {
		ctx, cancel := context.WithTimeout(t.Context(), 15*time.Second)
		defer cancel()
		cmd := exec.CommandContext(ctx, binary, args...)
		cmd.Dir = repo
		cmd.Env = append(append([]string(nil), env...), extra...)
		out, err := cmd.CombinedOutput()
		code := 0
		if err != nil {
			var ok bool
			var ee *exec.ExitError
			ee, ok = err.(*exec.ExitError)
			if !ok {
				t.Fatalf("invoke:%v", err)
			}
			code = ee.ExitCode()
		}
		return map[string]any{"exitCode": code, "output": string(out)}
	}
	invoke := func(args ...string) map[string]any { return invokeEnv(nil, args...) }
	defer func() {
		_, present, _ := gateway.snapshot()
		if present {
			_ = invoke("stop", "--provider", "wandb", "--id", "sb-metadata-audit")
		}
	}()
	acquire := invoke("run", "--provider", "wandb", "--no-sync", "--keep", "--timing-record", "off", "--", "true")
	if acquire["exitCode"] != 0 {
		t.Fatalf("acquire:%v", acquire)
	}
	before, present, startEnv := gateway.snapshot()
	if !present {
		t.Fatal("fixture not acquired")
	}
	for _, name := range []string{"CRABBOX_LEASE_ID", "CRABBOX_RUN_ID", "CRABBOX_SLUG"} {
		if _, ok := startEnv[name]; !ok {
			t.Errorf("core metadata absent from actual Start request:%s", name)
		}
	}
	var cases []map[string]any
	for _, tc := range []struct {
		name         string
		extra, flags []string
		want         int
	}{
		{name: "metadata-only", want: 0},
		{name: "metadata-only-summary", flags: []string{"--allow-env", "CRABBOX_RUN_ID"}, want: 0},
		{name: "implicit-defaults", extra: []string{"CI=true", "NODE_OPTIONS=--no-warnings"}, want: 0},
		{name: "explicit-ci", extra: []string{"CI=true"}, flags: []string{"--allow-env", "CI"}, want: 2},
		{name: "explicit-node", extra: []string{"NODE_OPTIONS=--no-warnings"}, flags: []string{"--allow-env", "NODE_OPTIONS"}, want: 2},
		{name: "explicit-custom", extra: []string{"CUSTOM=fixture"}, flags: []string{"--allow-env", "CUSTOM"}, want: 2},
		{name: "prefix-lookalike", extra: []string{"CRABBOX_RUN_ID_EXTRA=fixture"}, flags: []string{"--allow-env", "CRABBOX_RUN_ID_EXTRA"}, want: 2},
		{name: "suffix-lookalike", extra: []string{"PREFIX_CRABBOX_RUN_ID=fixture"}, flags: []string{"--allow-env", "PREFIX_CRABBOX_RUN_ID"}, want: 2},
	} {
		rpcBefore, _, _ := gateway.snapshot()
		connectionsBefore := listener.accepted.Load()
		args := []string{"run", "--provider", "wandb", "--no-sync", "--id", "sb-metadata-audit", "--timing-record", "off"}
		args = append(args, tc.flags...)
		args = append(args, "--", "true")
		run := invokeEnv(tc.extra, args...)
		rpcAfter, _, _ := gateway.snapshot()
		connectionsAfter := listener.accepted.Load()
		newRPC := rpcAfter[len(rpcBefore):]
		if run["exitCode"] != tc.want {
			t.Errorf("%s run:%v", tc.name, run)
		}
		if tc.want == 0 {
			if len(newRPC) != 2 || !strings.HasSuffix(newRPC[0], "/List") || !strings.HasSuffix(newRPC[1], "/Exec") {
				t.Errorf("%s unexpected reuse RPCs:%v", tc.name, newRPC)
			}
		} else if len(newRPC) != 0 || connectionsAfter != connectionsBefore || !strings.Contains(run["output"].(string), "cannot forward env vars to an existing sandbox") {
			t.Errorf("%s refusal reached RPC or wrong error:%v %v", tc.name, newRPC, run)
		}
		cases = append(cases, map[string]any{"name": tc.name, "run": run, "newRPC": newRPC, "connectionsBefore": connectionsBefore, "connectionsAfter": connectionsAfter})
	}
	claimsBefore, err := filepath.Glob(filepath.Join(root, "state", "crabbox", "claims", "*.json"))
	if err != nil || len(claimsBefore) != 1 {
		t.Fatalf("owned claim:%v %v", claimsBefore, err)
	}
	var claim map[string]any
	claimBytes, err := os.ReadFile(claimsBefore[0])
	if err != nil {
		t.Fatal(err)
	}
	if err := json.Unmarshal(claimBytes, &claim); err != nil {
		t.Fatal(err)
	}
	gateway.mu.Lock()
	execRequests := append([]json.RawMessage(nil), gateway.execRequests...)
	gateway.mu.Unlock()
	if len(execRequests) != 4 {
		t.Errorf("Exec requests=%d want4", len(execRequests))
	}
	for _, request := range execRequests {
		if strings.Contains(string(request), "CRABBOX_") || strings.Contains(string(request), "NODE_OPTIONS") || strings.Contains(string(request), "environment") {
			t.Errorf("metadata/env appeared in Exec request:%s", request)
		}
	}

	stop := invoke("stop", "--provider", "wandb", "--id", "sb-metadata-audit")
	if stop["exitCode"] != 0 {
		t.Errorf("stop:%v", stop)
	}
	claimsAfter, _ := filepath.Glob(filepath.Join(root, "state", "crabbox", "claims", "*.json"))
	final, present, _ := gateway.snapshot()
	if present || len(claimsAfter) != 0 {
		t.Errorf("cleanup incomplete")
	}
	server.Stop()
	_ = listener.Close()
	select {
	case <-done:
	case <-time.After(time.Second):
		t.Error("server did not stop")
	}
	conn, dialErr := net.DialTimeout("tcp", listener.Addr().String(), time.Second)
	if dialErr == nil {
		conn.Close()
		t.Error("fixture port remained open")
	}
	result := map[string]any{"scope": "actual unmodified CLI+production constructor using existing loopback plaintext mode; gRPC responses are synthetic, no TLS or hosted/native workload claim", "acquire": acquire, "cases": cases, "stop": stop, "startMetadata": startEnv, "initialRPC": before, "execRequests": execRequests, "claimBeforeStop": claim, "finalRPC": final, "finalClaimCount": len(claimsAfter), "finalSandboxPresent": present, "serverStopped": true, "portClosed": dialErr != nil}
	data, _ := json.Marshal(result)
	t.Logf("CLI_METADATA_RECEIPT %s", data)

}

@clawsweeper

clawsweeper Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Sep 6, 2026
@clawsweeper

clawsweeper Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed September 6, 2026, 6:45 PM ET / 22:45 UTC.

ClawSweeper review

What this changes

Allow W&B sandbox reuse to omit Crabbox-owned run metadata while preserving user-environment restrictions, with regression coverage, documentation, and a changelog entry.

Merge readiness

Ready for maintainer review

The fix remains necessary on the inspected main revision, and no actionable patch defect remains. The explicit maintainer-owned changelog disposition resolves the previous review finding.

Priority: P2
Reviewed head: 9f0b2f2762df3643fd8b044a66c304cde4a88ee2

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A focused repair with strong production-client proof, appropriate regression controls, and no remaining actionable findings.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (terminal): The captured built CLI uses the production gRPC constructor against a loopback service and demonstrates metadata reuse reaching List/Exec, explicit user-variable rejection before network activity, unchanged command payloads, and Stop cleanup. This proves the changed client-side guard; it does not claim hosted W&B, TLS, or remote workload execution.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (terminal): The captured built CLI uses the production gRPC constructor against a loopback service and demonstrates metadata reuse reaching List/Exec, explicit user-variable rejection before network activity, unchanged command payloads, and Stop cleanup. This proves the changed client-side guard; it does not claim hosted W&B, TLS, or remote workload execution.
Evidence reviewed 7 items Policy and review continuity: Read the complete root AGENTS.md; no applicable nested policy or maintainer-notes directory was found. The supplied disposition at #1930 (comment) explicitly retains the changelog entry as maintainer-owned work, so the earlier removal finding and rank-up move no longer apply.
Main still rejects injected metadata: The inspected main implementation accepts only implicit CI/NODE_OPTIONS, whereas the CLI injects three reserved metadata names into every run request. The related merged #1929 repairs finalization, not this guard. Direct v0.50.0 source inspection could not complete because a required object was unavailable; no shipped-fix claim is made.
Existing metadata contract: The shared predicate recognizes exactly the three reserved names using case folding; metadata injection removes user-provided versions before inserting core values. CLI run construction passes this effective environment and the explicit-selection summary flag to the provider.
Findings None None.
Security None None.

How this fits together

Crabbox’s CLI injects run metadata before sending requests to the W&B provider adapter. For existing sandboxes, the adapter validates environment compatibility and ownership before executing commands through the provider’s gRPC client.

flowchart TD
  A[CLI command and selected environment] --> B[Inject core run metadata]
  B --> C[W&B reuse environment guard]
  C -->|Unsupported user variables| D[Reject request]
  C -->|Metadata may be omitted| E[Verify sandbox ownership]
  E --> F[Execute command through gRPC]
  F --> G[Return outcome and retain sandbox]
Loading

Before merge

None.

Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Code delta Production +9/-9; tests +30/-1 The repair replaces the existing guard without net production growth and adds focused regression coverage.

Technical review

Best possible solution:

Keep environment omission inside the W&B adapter, using the shared exact-name predicate while retaining ownership enforcement and explicit user-variable rejection.

Do we have a high-confidence way to reproduce the issue?

Yes, from source: ordinary W&B run --id requests receive reserved metadata that main’s guard rejects before ownership lookup. This review did not execute the failure.

Is this the best way to solve the issue?

Yes. Reusing the existing exact-name predicate is a focused repair that preserves the provider’s inability to forward environment values during Exec.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against 69e79538dae2.

Labels

Label justifications:

  • P2: Repairs existing-sandbox reuse in one experimental provider with a narrow, source-proven cause.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The captured built CLI uses the production gRPC constructor against a loopback service and demonstrates metadata reuse reaching List/Exec, explicit user-variable rejection before network activity, unchanged command payloads, and Stop cleanup. This proves the changed client-side guard; it does not claim hosted W&B, TLS, or remote workload execution.
  • proof: sufficient: Contributor real behavior proof is sufficient. The captured built CLI uses the production gRPC constructor against a loopback service and demonstrates metadata reuse reaching List/Exec, explicit user-variable rejection before network activity, unchanged command payloads, and Stop cleanup. This proves the changed client-side guard; it does not claim hosted W&B, TLS, or remote workload execution.

Evidence

What I checked:

  • Policy and review continuity: Read the complete root AGENTS.md; no applicable nested policy or maintainer-notes directory was found. The supplied disposition at fix: omit core metadata when reusing W&B sandboxes #1930 (comment) explicitly retains the changelog entry as maintainer-owned work, so the earlier removal finding and rank-up move no longer apply. (AGENTS.md:41, 9f0b2f2762df)
  • Main still rejects injected metadata: The inspected main implementation accepts only implicit CI/NODE_OPTIONS, whereas the CLI injects three reserved metadata names into every run request. The related merged fix: finalize W&B runs with shared failure outcomes #1929 repairs finalization, not this guard. Direct v0.50.0 source inspection could not complete because a required object was unavailable; no shipped-fix claim is made. (internal/providers/wandb/backend.go:491, 69e79538dae2)
  • Existing metadata contract: The shared predicate recognizes exactly the three reserved names using case folding; metadata injection removes user-provided versions before inserting core values. CLI run construction passes this effective environment and the explicit-selection summary flag to the provider. (internal/cli/run_env_profile.go:76, 9f0b2f2762df)
  • Narrow guard and unchanged execution boundary: The introduced helper skips reserved metadata before applying the existing defaults rule. Ownership scope, inventory checks, and claim verification still precede Exec; the client constructs the command request without forwarding environment values or wrapping command text. (internal/providers/wandb/backend.go:491, 9f0b2f2762df)
  • Behavior proof and source identity: Supplied body snapshot SHA-256 d6d44849f317848e97cce5d17db50a88c2ccfa20c34f838e0e1821fe2a832fb5 includes actual CLI exit codes and production-client loopback RPC traces: three successful reuse controls, five rejections with no new connections/RPCs, unchanged Exec payloads, and explicit Stop cleanup. Production, test, and provider-document hashes match the checkout; the changelog hash differs after the link-only update. The supplied excerpts and disposition establish the scoped result; omitted body ranges were not independently recovered because the GitHub read failed. No embedded fixture was executed. (9f0b2f2762df)
  • Regression coverage: The introduced 12-case table covers reserved metadata, summaries, case folding, implicit defaults, explicit selections, and lookalikes. The existing-ID backend test now includes injected metadata and checks reuse without acquisition or automatic Stop. Reported focused race and vet results are supplemental; tests were not rerun during this read-only review. (internal/providers/wandb/backend_test.go:1105, 9f0b2f2762df)

Likely related people:

  • steipete: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)
  • Vincent Koc: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (2 earlier review cycles)
  • reviewed 2026-09-06T22:13:24.295Z sha 52f80f3 :: needs changes before merge. :: [P3] [P3] Leave the changelog entry to the landing maintainer
  • reviewed 2026-09-06T22:27:44.388Z sha 9f0b2f2 :: blocked before merge. :: [P3] Leave the changelog entry to the landing maintainer

@steipete

steipete commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Maintainer disposition for the review of 9f0b2f2: the changelog finding and removal step are not accepted. This is a maintainer-owned repair, and the repository requires maintainers/agents to record user-visible fixes under Unreleased. The entry remains with its PR link.

The full executed fixture and complete CLI receipt were inspected, including exact source/fixture hashes and raw-to-displayed capture equality (only the ephemeral port and claim revision are substituted). The unchanged complete capture is now first in the body, so its acquire, eight reuse controls, exact Exec payloads, actual Stop and cleanup result all fit in the initial description prefix. No source, tests, fixture or observed outcomes changed for presentation.

The accepted proof scope remains explicit: the actual built CLI and production constructor used the existing loopback-only plaintext mode with synthetic gRPC responses. It establishes metadata gating, unchanged Exec payload shape and normal claim/Stop routing; it does not establish hosted W&B, TLS or real remote workload execution. Independent managed source/link reviews passed at P0. The bot's existing BLOCKED verdict is preserved rather than relabelled as approval; ordinary required CI and merge protections still apply.

@steipete
steipete merged commit 5344e73 into main Sep 6, 2026
26 checks passed
@steipete
steipete deleted the codex/wandb-run-metadata-next branch September 6, 2026 22:54
@steipete

steipete commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Landed in 5344e73 through the normal protected merge. All five required workflows passed on reviewed head 9f0b2f2.

The telemetry change in #1931 landed between preflight and merge. The actual merged tree was checked against its actual parent plus the reviewed head, then the exact merged CLI was rebuilt and replayed through the unchanged published fixture. Acquire, three allowed reuse cases, five zero-RPC rejection cases, and actual Stop cleanup all passed; all four Exec payloads remained metadata-free. All 2,228 source hashes were verified after replay.

Post-merge go test -race -count=1 ./internal/providers/wandb ./internal/providers/shared passed (3.121s / 3.583s). This is production CLI/client proof using supported loopback plaintext and synthetic gRPC responses, not hosted W&B, TLS or remote workload proof. Main was pulled fast-forward and verified clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant