From b55ee4705c33e2d6b7cea13229519ff51916f0df Mon Sep 17 00:00:00 2001 From: "Hongming Wang (CTO)" Date: Wed, 3 Jun 2026 22:46:42 -0700 Subject: [PATCH] fix(e2e): satisfy MODEL_REQUIRED in peer-visibility staging gate (#2212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `E2E Peer Visibility (literal MCP list_peers)` gate has been red on main because tests/e2e/test_peer_visibility_mcp_staging.sh created both the parent and the per-runtime sibling workspaces with a runtime + secrets but NO `model` field. Staging now enforces the workspace-create contract: there is no platform-side default model for a runtime (feedback_workspace_model_required_no_platform_default — the MODEL_REQUIRED gate). The create was therefore rejected with MODEL_REQUIRED before the peer-visibility assertion could run. Fix: supply the required `model` on every create via a small pv_platform_model_for_runtime helper that returns a PLATFORM-MANAGED id (Molecule owns billing — no tenant key needed; this gate only needs the workspace to boot + list peers). Ids are validated against the controlplane providers SSOT (internal/providers/providers.yaml runtimes..providers [platform].models): - claude-code (parent + claude-code sibling) → anthropic/claude-sonnet-4-6 - hermes / openclaw siblings → moonshot/kimi-k2.6 E2E_MODEL_SLUG still overrides for operator-dispatched runs, mirroring lib/model_slug.sh. Contract enforcement is preserved; we supply the field rather than removing the gate. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/e2e/test_peer_visibility_mcp_staging.sh | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/e2e/test_peer_visibility_mcp_staging.sh b/tests/e2e/test_peer_visibility_mcp_staging.sh index caa91faf1..090e56e25 100755 --- a/tests/e2e/test_peer_visibility_mcp_staging.sh +++ b/tests/e2e/test_peer_visibility_mcp_staging.sh @@ -234,9 +234,30 @@ elif [ -n "${E2E_OPENAI_API_KEY:-}" ]; then SECRETS_JSON=$(python3 -c "import json,os;k=os.environ['E2E_OPENAI_API_KEY'];print(json.dumps({'OPENAI_API_KEY':k,'OPENAI_BASE_URL':'https://api.openai.com/v1','MODEL_PROVIDER':'openai:gpt-4o','HERMES_INFERENCE_PROVIDER':'custom','HERMES_CUSTOM_BASE_URL':'https://api.openai.com/v1','HERMES_CUSTOM_API_KEY':k,'HERMES_CUSTOM_API_MODE':'chat_completions'}))") fi +# Workspace-create now enforces the MODEL_REQUIRED contract: there is NO +# platform-side default model for a runtime (feedback_workspace_model_required_ +# no_platform_default). Every create MUST carry an explicit `model`, or the CP +# rejects it with MODEL_REQUIRED before this gate's peer-visibility assertion +# can run. We pick a PLATFORM-MANAGED id (Molecule owns billing — no tenant key +# needed; this gate only needs the workspace to boot + list peers, not heavy +# LLM work), validated against the controlplane providers SSOT +# (internal/providers/providers.yaml runtimes..providers[platform].models): +# claude-code → anthropic/claude-sonnet-4-6 (platform claude model) +# hermes/openclaw → moonshot/kimi-k2.6 (their only platform family) +# E2E_MODEL_SLUG overrides for operator-dispatched runs. +pv_platform_model_for_runtime() { + if [ -n "${E2E_MODEL_SLUG:-}" ]; then printf '%s' "$E2E_MODEL_SLUG"; return 0; fi + case "$1" in + claude-code) printf 'anthropic/claude-sonnet-4-6' ;; + hermes|openclaw) printf 'moonshot/kimi-k2.6' ;; + *) printf 'moonshot/kimi-k2.6' ;; + esac +} + log "4/6 provisioning parent (claude-code) + one sibling per runtime under test..." +PARENT_MODEL=$(pv_platform_model_for_runtime claude-code) P_RESP=$(tenant_call POST /workspaces \ - -d "{\"name\":\"pv-parent\",\"runtime\":\"claude-code\",\"tier\":3,\"secrets\":$SECRETS_JSON}") + -d "{\"name\":\"pv-parent\",\"runtime\":\"claude-code\",\"model\":\"$PARENT_MODEL\",\"tier\":3,\"secrets\":$SECRETS_JSON}") PARENT_ID=$(echo "$P_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null) [ -n "$PARENT_ID" ] || fail "parent create failed: $(echo "$P_RESP" | head -c 300)" log " PARENT_ID=$PARENT_ID" @@ -245,8 +266,9 @@ log " PARENT_ID=$PARENT_ID" declare -A WS_IDS WS_TOKENS ALL_WS_IDS="$PARENT_ID" for rt in $PV_RUNTIMES; do + RT_MODEL=$(pv_platform_model_for_runtime "$rt") R=$(tenant_call POST /workspaces \ - -d "{\"name\":\"pv-$rt\",\"runtime\":\"$rt\",\"tier\":2,\"parent_id\":\"$PARENT_ID\",\"secrets\":$SECRETS_JSON}") + -d "{\"name\":\"pv-$rt\",\"runtime\":\"$rt\",\"model\":\"$RT_MODEL\",\"tier\":2,\"parent_id\":\"$PARENT_ID\",\"secrets\":$SECRETS_JSON}") WID=$(echo "$R" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null) WTOK=$(echo "$R" | extract_auth_token) [ -n "$WID" ] || fail "$rt workspace create failed: $(printf '%s' "$R" | head -c 300)" -- 2.52.0