fix(tasks): make multi-region-failover exercise failover, and cut the prompt to the incident (0.80 → 0.50) - #239
Draft
jessie1111101 wants to merge 2 commits into
Draft
Conversation
The task never tested disaster recovery. Its GRADING NOTE said "failover and direct primary recovery are equally acceptable", and nothing stopped an agent from simply recreating the deleted node pool in the impaired region. Across six historical runs, gemini-3.1-pro did exactly that on every successful run: the global LB, the standby cluster and the Cloud SQL replica were never touched, so the scenario the stack provisions was never exercised. Two changes, both confined to the prompt and expected_output. Prompt: state the capacity constraint. The provider has declared a capacity incident in the affected region, so recovery must not depend on getting nodes back there. This makes failover the only available path, which is what the stack was built for. Also ask the agent to summarise the post-mortem in its final response -- incident-report.md lands outside the captured artifacts, so a criterion graded purely on the file is not gradeable. expected_output: replace 4 compound criteria with 10 atomic ones. The old criterion 2 bundled replication health, the URL map, node-pool scaling and GitOps reconciliation into a single bullet, so an agent doing one of the four scored the same as one doing all four. ChecklistScore counts checks that pass, so compound criteria silently collapse the scale. Splitting them also fixed an observed false positive: the judge passed a combined "standby workloads AND Cloud SQL replication" item on the workload half alone, while the agent made zero gcloud sql calls. Validated on GKE, openclaw + gemini-3.1-pro, three full runs. The agent now takes the failover path for the first time: it re-points the URL map at the west backend service, reconciles app-config/app-secret from the GitOps repo, leaves the impaired region alone, and the global endpoint goes 502 -> 200. The last two runs are byte-identical in task.yaml and both score 8/10 = 0.80 with the same two genuine misses -- no Cloud SQL replication check before the cutover, and no capacity added to the standby before sending it production traffic. Previously this run would have scored 1.0. Note for reviewers: this task is judge-only by construction. Every leaf verifier reads through kubectl, and the graded outcome here is a GCE URL map, a Cloud SQL pair and a file on disk, so a verification_spec can express only 2 of the 10 criteria -- and neither of the two the agent actually fails.
jessie1111101
marked this pull request as draft
August 10, 2026 04:11
… the runbook
The 828-char prompt handed the agent the namespace, the GitOps repo path, the
"recovery must not depend on getting nodes back in that region" rewording of
the constraint, and the exact post-mortem filename. It scored 0.80. The task
was measuring whether an agent can follow instructions, not whether it can
run an incident.
Prompt is now 373 chars — the service, the project, the symptom, the capacity
premise, and "investigate, restore, write a post-mortem". Everything the agent
has to work out (which region, which entry point, where the GitOps repo lives,
what the write path does) it now works out.
Two rubric fixes fall out of the cut, both cases of grading text the prompt no
longer contains:
* The post-mortem criterion named "incident-report.md". The short prompt
does not specify a filename, so the item now accepts any filename and says
so explicitly. Two runs had been failing on the name alone.
* The GitOps criterion named "~/app-repo-{{GKE_CLUSTER_NAME}}.git". That
placeholder is not interpolated into the prompt, so the agent was being
shown a literal token and graded on a path it could not have known. The
item now matches the repo the agent finds on disk.
One criterion is added: the write path. "app-config" points at a Cloud SQL
primary in the impaired region and a read-only replica in the standby, so
after a failover writes either cross back into the impaired region or have
nowhere to go. Both resolutions pass — promoting the replica, or stating the
primary is still reachable and recording the cross-region dependency as a
risk. Only silence fails. This is the single largest thing the old rubric let
an agent skip while scoring 0.80.
Every criterion is now grounded in text the prompt actually contains.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
multi-region-failoverprovisions two GKE clusters, a global HTTP LB and a cross-region Cloud SQL pair — and then never tests any of it.The GRADING NOTE said "failover and direct primary recovery are equally acceptable", and nothing prevented an agent from just recreating the node pool the stack deleted. Across six historical runs, gemini-3.1-pro did exactly that on every successful run. The URL map, the standby cluster and the Cloud SQL replica were never touched. The scenario was scenery.
The rubric compounded it. The original criterion 2 bundled replication health, the URL-map flip, node-pool scaling and GitOps reconciliation into one bullet.
ChecklistScoreis a count of passing checks, so an agent doing one of those four scored identically to one doing all four.Fixing those two things (first commit) got the agent onto the failover path and the score down to 0.80. That is where this PR originally stopped, and it was still too high — because the prompt had become a runbook.
Change
Prompt and
expected_outputonly. No stack or verification changes.Prompt: 828 → 373 characters. The long version handed over the Kubernetes namespace, the GitOps repo path, a rewording of the capacity constraint into an explicit instruction ("your recovery must not depend on getting nodes back in that region"), and the exact post-mortem filename. What remains is the service, the project, the symptom, the capacity premise, and "investigate, restore the service, and write a post-mortem."
Which region is impaired, what the user-facing entry point is, where the GitOps repo lives, and what the write path does are now things the agent has to work out.
expected_output: 10 → 11 atomic criteria. The added one is the write path —app-confignames a Cloud SQL primary (SQL_PRIMARY) in the impaired region and a read-only replica (SQL_REPLICA) in the standby, so after a failover writes either cross back into the impaired region or have nowhere to go. Either resolution passes: promote the replica, or state that the primary is still reachable because the incident affects compute only and record the cross-region write dependency as a follow-up. Only saying nothing fails. This is the largest thing the 0.80 runs skipped.Two criteria were also relaxed, because they graded text the shortened prompt no longer contains:
incident-report.md. The short prompt does not specify a filename, so any filename now satisfies it.~/app-repo-{{GKE_CLUSTER_NAME}}.git. That placeholder is not interpolated into the prompt — the agent is shown the literal token — so it was being graded on a path it could not have known. The item now matches the repo it finds on disk.Validation
GKE, openclaw + gemini-3.1-pro-preview, one cluster pair per run, full lifecycle (infra → agent → judge → teardown), every run
status: success.This commit is a9/a10: 0.5455 and 0.4545, mean 0.50. Down from 0.80, on a prompt 56% shorter.
The two misses are consistent across both runs and both genuine: no Cloud SQL replication check before the cutover, and no capacity added to the standby before sending it production traffic. Verified against the trajectory — zero
gcloud sqlcalls, zeroresize/node-poolscalls.Why not a6/a7/a8
a6 cut the prompt further, to 257 characters, by dropping the capacity premise. That looked like the best result until the transcripts were read: both a7 and a8 failed the criterion "Agent honours the stated capacity constraint" by recreating the East node pool — a constraint their prompt no longer stated. Same class of bug as the
incident-report.mdfilename item. a9 restores the one-sentence premise (still a 56% cut from a3) so that every criterion is grounded in prompt text. The capacity criterion passes in both a9 and a10.Run-to-run variance is large, and reviewers should know it
a7 and a8 are byte-identical inputs and scored 0.6364 and 0.3636 — a 0.27 spread. a9/a10, also byte-identical, scored 0.5455 and 0.4545 — 0.09.
A single run of this task is not a reliable number. The pair is reported rather than the better of the two, and no claim here rests on a difference smaller than the observed spread. What is stable across all eight arms is the direction: shorter prompt, lower score.
Note for reviewers
This task is judge-only by construction. All three leaf verifiers (
pod_healthy,scaling_complete,resource_property) read the world throughkubectl. The graded outcome here is a GCE URL map, a Cloud SQL pair and a file on disk. Averification_speccan express roughly 2 of the 11 criteria — and neither of the two the agent actually fails — so converting would score these runs 1.0 again.VerificationCoverageisNoneandOutcomeScoreisChecklistScoreverbatim. Worth tracking separately as a verifier-reach gap.