{"record":{"id":"d68ae3a14ed02968","repo":"koala73/worldmonitor","slug":"recordwavesent-tier-moved-underneath-us-expect","errorCode":null,"errorMessage":"[_recordWaveSent] tier moved underneath us: expected ${args.expectedCurrentTier}, found ${row.currentTier}. Refusing to overwrite.","messagePattern":"\\[_recordWaveSent\\] tier moved underneath us: expected (.+?), found (.+?)\\. Refusing to overwrite\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"convex/broadcast/rampRunner.ts","lineNumber":786,"sourceCode":" * record a successful wave-send. Validates that the lease still belongs to\n * this runId AND clears all pending-progress markers.\n */\nexport const _recordWaveSent = internalMutation({\n  args: {\n    runId: v.string(),\n    expectedCurrentTier: v.number(),\n    newTier: v.number(),\n    waveLabel: v.string(),\n    broadcastId: v.string(),\n    segmentId: v.string(),\n    assigned: v.number(),\n    sentAt: v.number(),\n  },\n  handler: async (ctx, args) => {\n    const row = await loadConfig(ctx);\n    if (!row) throw new Error(\"[_recordWaveSent] no ramp configured\");\n    if (row.currentTier !== args.expectedCurrentTier) {\n      throw new Error(\n        `[_recordWaveSent] tier moved underneath us: expected ${args.expectedCurrentTier}, found ${row.currentTier}. Refusing to overwrite.`,\n      );\n    }\n    if (row.pendingRunId !== args.runId) {\n      // The lease changed under us — operator force-released it, or\n      // recoverFromPartialFailure cleared it. We must NOT advance the tier;\n      // bubble to Convex auto-Sentry so ops can investigate.\n      throw new Error(\n        `[_recordWaveSent] lease lost: expected runId=${args.runId}, found ${row.pendingRunId ?? \"<cleared>\"}. Refusing to advance tier — investigate what cleared the lease.`,\n      );\n    }\n    await ctx.db.patch(row._id, {\n      currentTier: args.newTier,\n      lastWaveLabel: args.waveLabel,\n      lastWaveBroadcastId: args.broadcastId,\n      lastWaveSegmentId: args.segmentId,\n      lastWaveAssigned: args.assigned,\n      lastWaveSentAt: args.sentAt,","sourceCodeStart":768,"sourceCodeEnd":804,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/convex/broadcast/rampRunner.ts#L768-L804","documentation":"Optimistic-concurrency guard in _recordWaveSent: the config row's currentTier no longer matches the expectedCurrentTier the action captured when it started. Another writer advanced or reset the tier while this wave was in flight, and overwriting would skip or double-count a wave; the mutation refuses to proceed.","triggerScenarios":"Thrown at convex/broadcast/rampRunner.ts:784 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Re-read the config row to see the actual currentTier and who advanced it (logs, operator actions, a competing run)","Reconcile the wave that was sent via recoverFromPartialFailure instead of forcing the tier write"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}