@@ -9,10 +9,10 @@ use std::path::{Path, PathBuf};
99use anyhow:: { anyhow, bail, Context , Result } ;
1010use serde_json:: { json, Map , Value } ;
1111
12- use crate :: services:: checkout;
1312use crate :: services:: hooks:: {
1413 normalize_opencode_model_id, prefixed_diff_trace_session_id, OPENCODE_TOOL_NAME ,
1514} ;
15+ use crate :: services:: mutation_trace:: runtime:: resolve_git_dir;
1616use crate :: services:: observability:: traits:: Logger ;
1717
1818use boundary_lock:: { AdapterBoundaryLock , DEFAULT_BOUNDARY_LOCK_TIMEOUT } ;
@@ -339,7 +339,7 @@ pub(crate) fn run_opencode_mutation_scope_from_payload(
339339 stdin_payload : & str ,
340340 logger : Option < & dyn Logger > ,
341341) -> Result < String > {
342- let resolve_git_dir_fn = |cwd : & str | checkout :: resolve_git_dir ( Path :: new ( cwd) ) ;
342+ let resolve_git_dir_fn = |cwd : & str | resolve_git_dir ( Path :: new ( cwd) ) ;
343343 let seam_fn = |repository_root : & Path , payload : & str , logger : Option < & dyn Logger > | {
344344 super :: mutation_scope:: run_mutation_scope_from_payload ( repository_root, payload, logger)
345345 } ;
@@ -358,7 +358,7 @@ pub(crate) fn run_opencode_mutation_scope_from_payload_at_state_root(
358358 stdin_payload : & str ,
359359 logger : Option < & dyn Logger > ,
360360) -> Result < String > {
361- let resolve_git_dir_fn = |cwd : & str | checkout :: resolve_git_dir ( Path :: new ( cwd) ) ;
361+ let resolve_git_dir_fn = |cwd : & str | resolve_git_dir ( Path :: new ( cwd) ) ;
362362 let seam_fn = |repository_root : & Path , payload : & str , logger : Option < & dyn Logger > | {
363363 super :: mutation_scope:: run_mutation_scope_from_payload_at_state_root (
364364 repository_root,
@@ -2126,7 +2126,7 @@ mod runtime_seam_tests {
21262126 use crate :: services:: agent_trace_storage:: {
21272127 resolve_agent_trace_storage_at_state_root, AgentTraceStorageContext ,
21282128 } ;
2129- use crate :: services:: checkout :: resolve_git_dir;
2129+ use crate :: services:: mutation_trace :: runtime :: resolve_git_dir;
21302130
21312131 use super :: state:: read_state;
21322132 use super :: * ;
@@ -2145,7 +2145,7 @@ mod runtime_seam_tests {
21452145 }
21462146
21472147 struct OpenCodeRepo {
2148- _temp : tempfile:: TempDir ,
2148+ temp : tempfile:: TempDir ,
21492149 root : PathBuf ,
21502150 state_root : PathBuf ,
21512151 }
@@ -2182,7 +2182,7 @@ mod runtime_seam_tests {
21822182 . expect ( "state-root storage should initialize the repository DB" ) ;
21832183
21842184 Self {
2185- _temp : temp,
2185+ temp,
21862186 root,
21872187 state_root,
21882188 }
@@ -2353,6 +2353,70 @@ mod runtime_seam_tests {
23532353 ) ;
23542354 }
23552355
2356+ #[ test]
2357+ fn linked_worktree_uses_its_worktree_specific_git_dir_for_mutation_scope_state ( ) {
2358+ let repo = OpenCodeRepo :: new ( "linked-worktree" ) ;
2359+ let linked_root = repo. temp . path ( ) . join ( "linked" ) ;
2360+ git (
2361+ & repo. root ,
2362+ & [
2363+ "worktree" ,
2364+ "add" ,
2365+ "--quiet" ,
2366+ linked_root
2367+ . to_str ( )
2368+ . expect ( "linked worktree path should be UTF-8" ) ,
2369+ ] ,
2370+ ) ;
2371+
2372+ let main_git_dir = resolve_git_dir ( & repo. root ) . expect ( "main git dir should resolve" ) ;
2373+ let linked_git_dir = resolve_git_dir ( & linked_root) . expect ( "linked git dir should resolve" ) ;
2374+ assert_ne ! (
2375+ main_git_dir, linked_git_dir,
2376+ "linked worktrees must use distinct Git state locations" ,
2377+ ) ;
2378+
2379+ let before = json ! ( {
2380+ "hook_event_name" : "ToolExecuteBefore" ,
2381+ "session_id" : "ses_linked" ,
2382+ "call_id" : "call_linked" ,
2383+ "cwd" : linked_root,
2384+ "tool_name" : "write" ,
2385+ "model" : "opencode/big-pickle" ,
2386+ } )
2387+ . to_string ( ) ;
2388+ run_opencode_mutation_scope_from_payload_at_state_root ( & repo. state_root , & before, None )
2389+ . expect ( "linked-worktree Start" ) ;
2390+
2391+ let scope_id = read_state ( & linked_git_dir)
2392+ . expect ( "linked adapter state should be readable" )
2393+ . attempts [ 0 ]
2394+ . scope_id
2395+ . clone ( ) ;
2396+ fs:: write ( linked_root. join ( "file.txt" ) , "one\n linked\n " )
2397+ . expect ( "linked worktree file should be writable" ) ;
2398+
2399+ let after = json ! ( {
2400+ "hook_event_name" : "ToolExecuteAfter" ,
2401+ "session_id" : "ses_linked" ,
2402+ "call_id" : "call_linked" ,
2403+ "cwd" : linked_root,
2404+ "tool_name" : "write" ,
2405+ } )
2406+ . to_string ( ) ;
2407+ run_opencode_mutation_scope_from_payload_at_state_root ( & repo. state_root , & after, None )
2408+ . expect ( "linked-worktree Close" ) ;
2409+
2410+ assert ! ( read_state( & linked_git_dir)
2411+ . expect( "linked adapter state should be readable" )
2412+ . attempts
2413+ . is_empty( ) ) ;
2414+ assert_eq ! (
2415+ repo. scope_status( & scope_id) ,
2416+ Some ( ( "opencode" . to_string( ) , "closed" . to_string( ) ) ) ,
2417+ ) ;
2418+ }
2419+
23562420 #[ test]
23572421 fn a_tool_error_abandons_the_scope_through_the_real_runtime ( ) {
23582422 let repo = OpenCodeRepo :: new ( "tool-error-abandon" ) ;
0 commit comments