{"record":{"id":"26f7fe4a3dcccc43","repo":"affaan-m/ECC","slug":"refusing-to-write-operation-destinationpath-de","errorCode":null,"errorMessage":"Refusing to write ${operation.destinationPath}: destination changed after Kimi preflight.","messagePattern":"Refusing to write (.+?): destination changed after Kimi preflight\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/multi-harness-setup.js","lineNumber":341,"sourceCode":"  const expectedStateFingerprint = preview.ownershipSnapshot.stateFingerprint;\n  let operationIndex = 0;\n  const assertStateUnchanged = () => (\n    assertInstallStateUnchanged(preview.plan, expectedStateFingerprint)\n  );\n\n  return require('./install-executor').applyInstallPlan(preview.plan, {\n    beforeOperationWrite({ operation }) {\n      assertStateUnchanged();\n      const expected = preview.operations[operationIndex];\n      const currentClassification = classifyManagedOperation(operation, ownedDestinations);\n      const destination = canonicalPath(operation.destinationPath);\n      if (\n        !expected\n        || expected.kind !== operation.kind\n        || canonicalPath(expected.destinationPath) !== destination\n        || expected.classification !== currentClassification\n      ) {\n        throw new Error(\n          `Refusing to write ${operation.destinationPath}: destination changed after Kimi preflight.`\n        );\n      }\n      ownedDestinations.add(destination);\n      operationIndex += 1;\n    },\n    beforeInstallStateWrite: assertStateUnchanged,\n  });\n}\n\nfunction defaultDependencies(options = {}) {\n  return {\n    previewClaude: request => require('../setup').reconcileClaudePlugin(\n      { dryRun: true, hooks: request.claudeHooks, scope: request.claudeScope }\n    ),\n    previewCodex: () => require('./codex-plugin-setup').reconcileCodexPlugin({ dryRun: true }),\n    createManagedPlan: request => require('./install/runtime').createInstallPlanFromRequest(\n      require('./install/request').normalizeInstallRequest({","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/multi-harness-setup.js#L323-L359","documentation":"Thrown by applyPreflightedManagedPlan's beforeOperationWrite hook when the operation being written differs from what preflight authorized. The hook re-classifies the operation (classifyManagedOperation) and compares kind, canonical destination, and classification against the expected entry from preview.operations at the same index. A mismatch means the destination or its ownership state changed between preflight and apply — a TOCTOU condition the installer refuses to silently accept.","triggerScenarios":"Fires when expected is undefined, expected.kind !== operation.kind, the canonical destinations differ, or expected.classification !== currentClassification. Occurs when a file was created/deleted/edited between preflightManaged and applyInstallPlan, when operations are reordered or dropped, when ownership changed (e.g., a file became owned or stopped being owned), or when the plan object was mutated between preflight and apply.","commonSituations":"User creates/removes a destination file during the preview->apply window; another ECC process writes files in the same project; the plan array was filtered or reordered before apply; the install-state changed classification (e.g., a file went from absent 'create' to present 'json-merge'); sync tools modifying files mid-install.","solutions":["Re-run preflightManaged immediately before apply so the preview reflects the current filesystem, then apply without delay.","Do not mutate plan.operations or plan.harnesses between preview and apply.","Stop concurrent processes that touch destination paths during install.","If the classification changed because a file now exists, decide intentionally: remove the file (back to 'create') or let ECC own it, then re-preflight."],"exampleFix":"// before: file appears between preflight and apply, classification drifts\nconst preview = preflightManagedPlan(plan); // op classified 'create' (file absent)\nfs.writeFileSync(destPath, '{}');         // file now exists -> re-classify 'json-merge'\napplyPreflightedManagedPlan({ preview });  // throws [294]\n\n// after: preflight again right before apply\nconst preview = preflightManagedPlan(plan);\n// no intervening filesystem mutation\napplyPreflightedManagedPlan({ preview });","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nfunction assertNoDestinationDrift(preview) {\n  for (const expected of preview.operations) {\n    const exists = fs.existsSync(expected.destinationPath);\n    // re-run the same classification logic preflight used; if it differs, apply will throw [294]\n    if (expected.classification === 'create' && exists) {\n      throw new Error(`Destination ${expected.destinationPath} appeared after preflight; re-preflight before apply.`);\n    }\n    if ((expected.classification === 'json-merge' || expected.classification === 'managed-json-update' || expected.classification === 'managed-update') && !exists) {\n      throw new Error(`Destination ${expected.destinationPath} disappeared after preflight; re-preflight before apply.`);\n    }\n  }\n}\nassertNoDestinationDrift(preview.harnesses.find(h=>h.id==='kimi').preview);","typeGuard":"null","tryCatchPattern":"try {\n  await applyMultiHarnessPlan(preview);\n} catch (err) {\n  if (/destination changed after Kimi preflight/.test(err.message)) {\n    // re-run preflight against current fs, then apply immediately\n    const kimi = preview.harnesses.find(h => h.id === 'kimi');\n    kimi.preview = preflightManagedPlan(kimi.preview.plan);\n    await applyMultiHarnessPlan(preview);\n  } else throw err;\n}","preventionTips":["Re-run preflightManagedPlan immediately before apply when any time has passed.","Do not create/delete/edit destination files between preflight and apply.","Do not reorder or filter plan.operations between preview and apply.","Stop other processes that write into the project during install."],"tags":["toctou","preflight","classification","ownership","kimi","apply"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}