@@ -231,4 +231,117 @@ describe("mergeAndPush — rebase-based delivery", () => {
231231 git ( repoDir , [ "checkout" , "main" ] )
232232 expect ( readFile ( resolve ( repoDir , "package-lock.json" ) ) ) . toContain ( '"version": "2.0.0"' )
233233 } )
234+
235+ test ( "blocks merge when feature branch has pre-committed conflict markers" , async ( ) => {
236+ // Simulate an agent that accidentally committed conflict markers
237+ git ( repoDir , [ "checkout" , "-b" , "feature/TEST-6" ] )
238+ mkdirSync ( resolve ( repoDir , "src" , "store" ) , { recursive : true } )
239+ writeFileSync (
240+ resolve ( repoDir , "src/store/auth.ts" ) ,
241+ [
242+ "<<<<<<< HEAD" ,
243+ 'import { authClient } from "./auth-client"' ,
244+ "=======" ,
245+ 'import { betterAuth } from "better-auth"' ,
246+ ">>>>>>> 2c83c4e" ,
247+ "" ,
248+ "export const store = {}" ,
249+ ] . join ( "\n" ) + "\n" ,
250+ )
251+ git ( repoDir , [ "add" , "." ] )
252+ git ( repoDir , [ "commit" , "-m" , "feat(web,api): integrate better-auth for authentication" ] )
253+
254+ const workspace = {
255+ id : "t" ,
256+ key : "TEST-6" ,
257+ path : resolve ( repoDir , "TEST-6" ) ,
258+ issueId : "t" ,
259+ branch : "feature/TEST-6" ,
260+ status : "running" as const ,
261+ createdAt : new Date ( ) . toISOString ( ) ,
262+ }
263+ const result = await manager . mergeAndPush ( workspace )
264+
265+ expect ( result . ok ) . toBe ( false )
266+ expect ( result . error ) . toContain ( "conflict marker" )
267+
268+ // Verify origin/main was NOT corrupted
269+ const remoteMain = git ( bareDir , [ "log" , "--oneline" , "main" ] )
270+ expect ( remoteMain ) . not . toContain ( "better-auth" )
271+ } )
272+
273+ test ( "blocks merge when feature branch has conflict markers in package.json" , async ( ) => {
274+ // Pre-committed conflict markers in a high-risk file
275+ git ( repoDir , [ "checkout" , "-b" , "feature/TEST-7" ] )
276+ writeFileSync (
277+ resolve ( repoDir , "package.json" ) ,
278+ [
279+ "{" ,
280+ ' "name": "demo",' ,
281+ "<<<<<<< HEAD" ,
282+ ' "dependencies": { "left-pad": "1.0.0" }' ,
283+ "=======" ,
284+ ' "dependencies": { "right-pad": "2.0.0" }' ,
285+ ">>>>>>>" ,
286+ "}" ,
287+ ] . join ( "\n" ) + "\n" ,
288+ )
289+ git ( repoDir , [ "add" , "." ] )
290+ git ( repoDir , [ "commit" , "-m" , "feat: add dependencies" ] )
291+
292+ const workspace = {
293+ id : "t" ,
294+ key : "TEST-7" ,
295+ path : resolve ( repoDir , "TEST-7" ) ,
296+ issueId : "t" ,
297+ branch : "feature/TEST-7" ,
298+ status : "running" as const ,
299+ createdAt : new Date ( ) . toISOString ( ) ,
300+ }
301+ const result = await manager . mergeAndPush ( workspace )
302+
303+ expect ( result . ok ) . toBe ( false )
304+ expect ( result . error ) . toContain ( "conflict marker" )
305+
306+ // Verify origin/main is untouched — still has original initial commit only
307+ const remoteLog = git ( bareDir , [ "log" , "--oneline" , "main" ] )
308+ expect ( remoteLog ) . not . toContain ( "add dependencies" )
309+
310+ // Verify local main is also clean
311+ git ( repoDir , [ "checkout" , "main" ] )
312+ const localLog = git ( repoDir , [ "log" , "--oneline" ] )
313+ expect ( localLog ) . not . toContain ( "add dependencies" )
314+ } )
315+
316+ test ( "origin/main is never pushed when pre-rebase validation fails" , async ( ) => {
317+ // Record the remote main HEAD before the merge attempt
318+ const remoteHeadBefore = git ( bareDir , [ "rev-parse" , "main" ] )
319+
320+ // Feature branch with conflict markers in multiple files
321+ git ( repoDir , [ "checkout" , "-b" , "feature/TEST-8" ] )
322+ writeFileSync (
323+ resolve ( repoDir , "middleware.ts" ) ,
324+ "<<<<<<< HEAD\nexport default {}\n=======\nexport default { auth: true }\n>>>>>>>\n" ,
325+ )
326+ writeFileSync ( resolve ( repoDir , "clean-file.ts" ) , "export const clean = true\n" )
327+ git ( repoDir , [ "add" , "." ] )
328+ git ( repoDir , [ "commit" , "-m" , "feat: add middleware" ] )
329+
330+ const workspace = {
331+ id : "t" ,
332+ key : "TEST-8" ,
333+ path : resolve ( repoDir , "TEST-8" ) ,
334+ issueId : "t" ,
335+ branch : "feature/TEST-8" ,
336+ status : "running" as const ,
337+ createdAt : new Date ( ) . toISOString ( ) ,
338+ }
339+ const result = await manager . mergeAndPush ( workspace )
340+
341+ expect ( result . ok ) . toBe ( false )
342+
343+ // The critical guarantee: origin/main HEAD has not moved
344+ const remoteHeadAfter = git ( bareDir , [ "rev-parse" , "main" ] )
345+ expect ( remoteHeadAfter ) . toBe ( remoteHeadBefore )
346+ } )
234347} )
0 commit comments