{"record":{"id":"a8e9b092c27c04c6","repo":"Yeachan-Heo/oh-my-codex","slug":"canonical-scale-up-rollback-resolved-membership-ve","errorCode":null,"errorMessage":"canonical_scale_up_rollback_resolved_membership_verification_failed","messagePattern":"canonical_scale_up_rollback_resolved_membership_verification_failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/team/scaling.ts","lineNumber":958,"sourceCode":"            baseGeneration: currentConfig.config_generation ?? 0,\n            tasks: taskChanges,\n            config: { oldBytes: currentConfigBytes, newBytes: JSON.stringify(desiredConfig, null, 2) },\n            manifest: { oldBytes: currentManifestBytes, newBytes: desiredManifestBytes },\n            recoverToNewOnFailure: true,\n            retainJournalOnSuccess: true,\n            failRollbackPersistence: hasScaleUpFailureInjection(env, 'rollback-membership-persistence'),\n            failRollbackPersistenceAfter: hasScaleUpFailureInjection(env, 'rollback-membership-config-persistence')\n              ? 'config'\n              : hasScaleUpFailureInjection(env, 'rollback-membership-manifest-persistence')\n                ? 'manifest'\n                : undefined,\n          });\n          const verified = JSON.parse(await readFile(configPath, 'utf8')) as TeamConfig;\n          if (!verified || retainedWorkers.some((worker) => !verified.workers.some((entry) => entry.name === worker.name && entry.pane_id === worker.pane_id))) {\n            throw new Error('canonical_scale_up_rollback_membership_verification_failed');\n          }\n          if (verified.workers.some((worker) => rollbackWorkerNames.has(worker.name) && !unresolvedWorkerNames.has(worker.name))) {\n            throw new Error('canonical_scale_up_rollback_resolved_membership_verification_failed');\n          }\n          await finalizeTeamMembershipTaskTransaction(sanitized, leaderCwd);\n          Object.assign(config, verified);\n        });\n      } catch (rollbackError) {\n        const journalPath = join(teamStateRoot, 'team', sanitized, '.membership-task-transaction.json');\n        const suffix = existsSync(journalPath) ? String(rollbackError) : `no_recoverable_journal:${String(rollbackError)}`;\n        return { ok: false, error: `scale_up_rollback_membership_persistence_failed:${suffix}` };\n      }\n      const cleanupWorkerNames = new Set([\n        ...rollbackWorkers\n          .filter((worker) => typeof worker.pane_id !== 'string' || resolvedPaneIds.has(worker.pane_id))\n          .map((worker) => worker.name),\n        ...(context.workerName && !unresolvedWorkerNames.has(context.workerName) ? [context.workerName] : []),\n      ]);\n      try {\n        for (const taskId of createdTaskIds) {\n          const task = await readTask(sanitized, taskId, leaderCwd);","sourceCodeStart":940,"sourceCodeEnd":976,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/team/scaling.ts#L940-L976","documentation":"Thrown during scale-up rollback verification after the team config was re-read from disk: a worker that was supposed to be rolled back (removed) still appears in the canonical config as resolved (not marked unresolved). It signals the rollback transaction left an inconsistent membership state where a rolled-back worker remains active.","triggerScenarios":"Calling scaleUp, hitting a failure that triggers rollback, and the post-rollback config read finds a rollback worker name present that is not in the unresolved set.","commonSituations":"Concurrent mutation of the team config by another process during scale-up rollback; partially failed membership transaction recovery; stale .membership-task-transaction.json state.","solutions":["Check for concurrent scale operations (other CLI/process mutating the same team state) and serialize them","Inspect team state .membership-task-transaction.json and recover or clear it, then retry scaleUp","Verify team config file integrity under the team state root and re-run scaleUp from a clean config"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await scaleUp(team, count, opts);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('canonical_scale_up_rollback')) {\n    // membership state is suspect: re-read config, ensure no concurrent scalers, then retry once\n    await inspectTeamState(team);\n    return retryOnce(() => scaleUp(team, count, opts));\n  }\n  throw e;\n}","preventionTips":["Run only one scale operation per team at a time","Monitor the membership transaction journal for stuck entries","Abort scale-up quickly on first failure to keep rollback windows small"],"tags":["team","scaling","rollback","membership","consistency"],"backgroundTag":"transaction-rollback-verification-failed","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}