fix(release): unblock beta validation workflows (#116708)

* fix(release): repair beta validation workflow state

* fix(qa): dispatch yielded fanout runs without task tracking

* fix(test): honor GPT-Live shard opt-in
This commit is contained in:
Vincent Koc
2026-07-31 15:47:11 +08:00
committed by GitHub
parent 640b4ac599
commit 37b1a71654
8 changed files with 83 additions and 4 deletions
+1 -1
View File
@@ -352,7 +352,7 @@ jobs:
}
attempt_started_at="$(jq -er '.run_started_at | fromdateiso8601' <<< "$attempt_json")"
if [[ "$ARTIFACT_RUN_ID" == "$GITHUB_RUN_ID" ]]; then
jq -e '(.status == "queued" or .status == "in_progress") and .conclusion == null' \
jq -e '(.status == "pending" or .status == "queued" or .status == "in_progress") and .conclusion == null' \
<<< "$attempt_json" >/dev/null || {
echo "Current-run Package Telegram artifact is not from the active workflow attempt." >&2
exit 1
@@ -1665,6 +1665,10 @@ jobs:
expected_sha: ${{ needs.resolve_target.outputs.revision }}
run_matrix: true
fail_fast: ${{ fromJSON(needs.resolve_target.outputs.fail_fast) }}
secrets:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
qa_live_buzz_release_checks:
name: Run QA Lab live Buzz lane
@@ -1679,6 +1683,10 @@ jobs:
expected_sha: ${{ needs.resolve_target.outputs.revision }}
run_buzz: true
buzz_scenario: channel-canary,channel-mention-gating
secrets:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
# The dispatched child owns Telegram evidence/status artifacts; this blocking job
# carries its exact conclusion into the parent summary without copying secrets or artifacts.
@@ -58,6 +58,16 @@ on:
required: false
default: false
type: boolean
secrets:
OPENAI_API_KEY:
description: OpenAI API key used by live QA scenarios
required: false
OPENCLAW_QA_CONVEX_SITE_URL:
description: Convex credential broker URL
required: false
OPENCLAW_QA_CONVEX_SECRET_CI:
description: Convex CI credential
required: false
workflow_dispatch:
inputs:
ref:
@@ -79,6 +79,7 @@ describe("qa scenario catalog channel contracts", () => {
expect(flow).toContain('"call":"startAgentRun"');
expect(flow).not.toContain('"call":"runAgentPrompt"');
expect(flow).toContain('"taskTracking":false');
expect(flow).toContain('"saveAs":"parentOutbound"');
expect(flow).toContain("messages.slice(parentOutboundStartIndex)");
expect(flow).not.toContain("waitForAgentHistoryReply");
@@ -105,6 +105,7 @@ flow:
ref: sessionKey
message:
ref: prompt
taskTracking: false
timeoutMs:
expr: liveTurnTimeoutMs(env, 30000)
- call: waitForCondition
+5
View File
@@ -29,6 +29,11 @@ const OPTIONAL_LIVE_SHARD_FILE_ENVS = new Map([
["src/agents/subagent-announce.live.test.ts", ["OPENCLAW_LIVE_SUBAGENT_E2E"]],
["src/agents/tools/image-tool.ollama.live.test.ts", ["OPENCLAW_LIVE_OLLAMA_IMAGE"]],
["src/agents/tools/image-tool.providers.live.test.ts", ["OPENCLAW_LIVE_IMAGE_TOOL_TEST"]],
[
"extensions/openai/realtime-quicksilver-gateway-bridge.live.test.ts",
["OPENCLAW_LIVE_GPT_LIVE"],
],
["extensions/openai/realtime-quicksilver.live.test.ts", ["OPENCLAW_LIVE_GPT_LIVE"]],
["src/skills/workshop/experience-review.live.test.ts", ["OPENCLAW_LIVE_SKILL_EXPERIENCE_REVIEW"]],
["src/system-agent/rescue-channel.live.test.ts", ["OPENCLAW_LIVE_SYSTEM_AGENT_RESCUE_CHANNEL"]],
["src/gateway/android-node.capabilities.live.test.ts", ["OPENCLAW_LIVE_ANDROID_NODE"]],
@@ -245,7 +245,7 @@ function runNpmTelegramInputValidation(overrides: Record<string, string>) {
function runNpmTelegramArtifactValidation(params: {
currentRunId: string;
producerRunId: string;
producerStatus: "completed" | "in_progress" | "queued";
producerStatus: "completed" | "in_progress" | "pending" | "queued";
producerConclusion: "success" | null;
}) {
const job = workflowJob(NPM_TELEGRAM_WORKFLOW, "run_package_telegram_e2e");
@@ -2583,7 +2583,11 @@ describe("package artifact reuse", () => {
const releaseJob = workflowJob(RELEASE_CHECKS_WORKFLOW, "qa_live_release_checks");
expect(releaseJob.uses).toBe("./.github/workflows/qa-live-transports-convex.yml");
expect(releaseJob.secrets).toBeUndefined();
expect(releaseJob.secrets).toEqual({
OPENAI_API_KEY: "${{ secrets.OPENAI_API_KEY }}",
OPENCLAW_QA_CONVEX_SECRET_CI: "${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}",
OPENCLAW_QA_CONVEX_SITE_URL: "${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}",
});
expect(releaseJob.permissions).toEqual({ contents: "read", "pull-requests": "read" });
expect(releaseJob.if).toContain('contains(fromJSON(\'["all","qa","qa-live"]\')');
expect(releaseJob.with).toMatchObject({
@@ -2650,7 +2654,11 @@ describe("package artifact reuse", () => {
const releaseJob = workflowJob(RELEASE_CHECKS_WORKFLOW, "qa_live_buzz_release_checks");
expect(releaseJob.uses).toBe("./.github/workflows/qa-live-transports-convex.yml");
expect(releaseJob.secrets).toBeUndefined();
expect(releaseJob.secrets).toEqual({
OPENAI_API_KEY: "${{ secrets.OPENAI_API_KEY }}",
OPENCLAW_QA_CONVEX_SECRET_CI: "${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}",
OPENCLAW_QA_CONVEX_SITE_URL: "${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}",
});
expect(releaseJob.permissions).toEqual({ contents: "read", "pull-requests": "read" });
expect(releaseJob.if).toContain('contains(fromJSON(\'["all","qa","qa-live"]\')');
expect(releaseJob.if).toContain("needs.resolve_target.outputs.qa_live_buzz_enabled == 'true'");
@@ -3212,6 +3220,7 @@ describe("package artifact reuse", () => {
'--arg digest "sha256:${ARTIFACT_DIGEST}"',
"actions/runs/${ARTIFACT_RUN_ID}/attempts/${ARTIFACT_RUN_ATTEMPT}",
'if [[ "$ARTIFACT_RUN_ID" == "$GITHUB_RUN_ID" ]]',
'.status == "pending"',
'.status == "queued" or .status == "in_progress"',
".conclusion == null",
"Package Telegram artifact predates the active producer run attempt.",
@@ -3269,6 +3278,17 @@ describe("package artifact reuse", () => {
expect(result.status, result.stderr).toBe(0);
});
it("accepts active artifacts while GitHub reports the workflow as pending", () => {
const result = runNpmTelegramArtifactValidation({
currentRunId: "123",
producerConclusion: null,
producerRunId: "123",
producerStatus: "pending",
});
expect(result.status, result.stderr).toBe(0);
});
it("rejects queued artifacts after GitHub assigns a conclusion", () => {
const result = runNpmTelegramArtifactValidation({
currentRunId: "123",
+34
View File
@@ -420,6 +420,40 @@ describe("scripts/test-live-shard", () => {
});
});
it("allows GPT-Live files to be skipped until their shared opt-in is enabled", () => {
const quicksilverFiles = [
"extensions/openai/realtime-quicksilver-gateway-bridge.live.test.ts",
"extensions/openai/realtime-quicksilver.live.test.ts",
];
const payload = {
numPassedTests: 1,
numTotalTests: 3,
testResults: [
{
name: path.join(process.cwd(), "extensions/openai/openai.live.test.ts"),
assertionResults: [{ status: "passed" }],
},
...quicksilverFiles.map((file) => ({
name: path.join(process.cwd(), file),
assertionResults: [{ status: "skipped" }],
})),
],
};
const expectedFiles = ["extensions/openai/openai.live.test.ts", ...quicksilverFiles];
expect(validateLiveShardReportPayload(payload, expectedFiles, process.cwd(), {})).toEqual({
ok: true,
});
expect(
validateLiveShardReportPayload(payload, expectedFiles, process.cwd(), {
OPENCLAW_LIVE_GPT_LIVE: "1",
}),
).toEqual({
ok: false,
reason: `Vitest report selected live test files had no passing assertions: ${quicksilverFiles.join(", ")}`,
});
});
it("does not count disabled opt-in sentinel assertions as live shard proof", () => {
const payload = {
numPassedTests: 1,