A user clicks “Generate patch,” the request times out, and the UI offers Try Another Provider. If that button creates a second job, the first provider can still finish later. Now one intention has two patches and perhaps two side effects.
The official July 25 timeline is a good failure fixture. OpenAI says the initial incident began at 09:17:49 UTC, entered mitigation monitoring at 10:02:52, and resolved at 11:08:36. Its next incident began at 11:35:24. During research, that incident was identified with elevated errors and mitigation in progress, and official overall status was Partial System Degradation. The records do not support conclusions about root cause, global extent, exact affected population, or final recovery of the second incident.
The fix belongs in the API and database, not in button debounce.
One intention, multiple attempts
This unexecuted TypeScript interface separates the durable job from provider attempts:
type JobState = 'accepted' | 'running' | 'needs_review' | 'completed' | 'cancelled';
type AttemptState = 'starting' | 'unknown' | 'failed' | 'succeeded' | 'superseded';
interface Job {
id: string;
ownerId: string;
idempotencyKey: string;
inputDigest: string;
state: JobState;
winningAttemptId?: string;
version: number;
}
interface Attempt {
id: string;
jobId: string;
provider: string;
state: AttemptState;
remoteId?: string;
outputDigest?: string;
}
POST /jobs requires an Idempotency-Key. Put a unique constraint on (owner_id, idempotency_key) and return the existing job when both key and input digest match. Reject reuse with different input.
POST /jobs/:id/attempts is an authorized state transition, not a fresh job. It should refuse while an earlier attempt is starting or unknown, unless a reviewer records a supersession reason. The worker claims the job version with compare-and-swap before making any externally visible commit.
UPDATE jobs
SET winning_attempt_id = :attempt, state = 'completed', version = version + 1
WHERE id = :job
AND winning_attempt_id IS NULL
AND version = :expected_version;
Zero updated rows means another attempt already won or the state changed. Keep the losing output for bounded diagnostics if policy allows, but never apply it.
Cross-layer failure checks
These are proposed tests, not executed results:
- Double-click
POST /jobsand expect one job identifier. - Reuse the key with changed input and expect a conflict.
- Inject a timeout after provider submission; expect
unknown, notfailed. - Request fallback while unknown; expect review-required.
- Complete two attempts in reverse order; expect one winner.
- Reload the browser; derive controls from server state, not memory.
Authorization must check job ownership on inspection, retry, cancellation, and output fetch. Persistence must retain attempt IDs long enough to reconcile delayed callbacks. Rollback means disabling new fallback attempts without deleting the ledger.
Provider diversity introduces semantic risk. Different models can satisfy the same TypeScript shape while disagreeing in intent, tool use, or patch behavior. Run provider-specific acceptance fixtures before permitting automatic switching; schema validation alone is insufficient.
A vertical-slice evaluation path
The overseas MonkeyCode Try Online service currently presents “Start free.” The project README describes managed server-side cloud environments with build, test, and preview plus integrated models. That makes it a candidate for a disposable vertical-slice evaluation, described accurately as free to start. Model/server quotas, regions, and uptime or SLA details can change and should be confirmed in the console.
The official MonkeyCode source repository uses AGPL-3.0. On reviewed main commit 18baaf54937a65a7d47f1f9d83dd808777aa6cea, the README lists built-in management of development environments, models, tasks, and requirements. I would inspect the source as a self-hosting and exit option, then compare one low-authority task with the hosted flow. Open source does not make provider dependencies disappear, and I did not test hosted MonkeyCode reliability.
The relevant recommendation for a full-stack team is to evaluate task identity and persistence at every layer. Do not adopt any fallback path that turns one user action into unrelated jobs merely because its interface offers multiple models.
Disclosure: I'm a MonkeyCode user sharing my own experience, not affiliated with the project.
AI assistance disclosure: This article was drafted with AI assistance and reviewed against the cited primary sources.
Top comments (0)