{"record":{"id":"ff6693cc5d633f20","repo":"Yeachan-Heo/oh-my-codex","slug":"native-hook-transaction-rollback-preserved-artif","errorCode":null,"errorMessage":"Native hook transaction rollback preserved ${artifact.path} for manual recovery because ${artifact.label} no longer matches the transaction-owned version.","messagePattern":"Native hook transaction rollback preserved (.+?) for manual recovery because (.+?) no longer matches the transaction-owned version\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/setup.ts","lineNumber":1793,"sourceCode":"\t\tif (!validation.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Native hook transaction wrote invalid hooks.json: ${validation.error.message}`,\n\t\t\t);\n\t\t}\n\t}\n\tif (artifact.kind === \"config\") TOML.parse(content);\n}\n\nasync function restoreNativeHookTransactionArtifact(\n\tapplied: AppliedNativeHookTransactionArtifact,\n\tancestorPrecondition: NativeHookTransactionAncestorPrecondition,\n\ttracker: RegularFileDurabilityTracker,\n\tassertRollbackState: () => Promise<void>,\n): Promise<void> {\n\tconst { artifact } = applied;\n\tconst current = await captureNativeHookTransactionArtifact(artifact.path, artifact.label);\n\tif (!nativeHookTransactionSnapshotsEqual(current, applied.appliedSnapshot)) {\n\t\tthrow new Error(\n\t\t\t`Native hook transaction rollback preserved ${artifact.path} for manual recovery because ${artifact.label} no longer matches the transaction-owned version.`,\n\t\t);\n\t}\n\tif (artifact.before.bytes === null) {\n\t\tinjectNativeHookTransactionFailure(\"before_rollback\", artifact);\n\t\tinjectNativeHookTransactionFailure(\"before_rollback_remove\", artifact);\n\t\tawait assertNativeHookTransactionArtifactSnapshot(\n\t\t\tartifact.path,\n\t\t\tartifact.label,\n\t\t\tapplied.appliedSnapshot,\n\t\t\t\"rollback\",\n\t\t);\n\t\tawait assertNativeHookTransactionAncestorPrecondition(ancestorPrecondition);\n\t\tawait assertRollbackState();\n\t\tinjectNativeHookTransactionFailure(\"after_final_restore_validation\", artifact);\n\t\tconst claimPath = nativeHookTransactionClaimPath(artifact.path);\n\n\t\tawait rename(artifact.path, claimPath);","sourceCodeStart":1775,"sourceCodeEnd":1811,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/setup.ts#L1775-L1811","documentation":"During rollback of a native hook transaction, setup re-captures the artifact on disk and compares it to the snapshot taken when the change was applied. If they differ, the file was modified by something else after the transaction applied it, so rollback refuses to overwrite it and preserves it for manual recovery.","triggerScenarios":"Rolling back a transaction after another process (editor, second setup run, user edit) modified hooks.json or config.toml between apply and rollback.","commonSituations":"Concurrent setup invocations, a hook-editing tool or editor autosave racing the transaction, or delayed fault-injection in tests.","solutions":["Diff the preserved file against the expected transaction-owned version and reconcile edits manually","Ensure only one setup/transaction process runs at a time (lock file)","Re-run setup after manual reconciliation so it starts from a known state","Remove test fault-injection points that mutate files mid-transaction"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const snapshot = await captureNativeHookTransactionArtifact(path, label);\nif (!nativeHookTransactionSnapshotsEqual(snapshot, expected)) {\n  console.warn(`${path} changed externally; aborting before apply`);\n}","typeGuard":null,"tryCatchPattern":"try { await tx.rollback(); } catch (e) { if (e instanceof Error && e.message.includes(\"no longer matches the transaction-owned version\")) { /* diff preserved file vs expected, reconcile manually */ } else throw e; }","preventionTips":["Run only one setup/transaction at a time","Use a lock file around hook-mutating operations","Treat mid-transaction edits as conflicts: reconcile then re-run"],"tags":["transaction","rollback","concurrency","file-integrity"],"backgroundTag":"transaction-rollback-failed","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}