@@ -262,6 +262,44 @@ function persistRepairCloseout({ activeRoot, metaDir, identity, sessionKey, repa
262262 return read . state
263263}
264264
265+ function createGitLineageFixture ( fixtureRoot ) {
266+ const repoRoot = path . join ( fixtureRoot , 'git-lineage' )
267+ fs . mkdirSync ( repoRoot , { recursive : true } )
268+ execFileSync ( 'git' , [ 'init' , '--quiet' ] , {
269+ cwd : repoRoot ,
270+ windowsHide : true
271+ } )
272+ const heads = [ ]
273+ for ( let index = 0 ; index < 3 ; index += 1 ) {
274+ const timestamp = `2020-01-01T00:00:0${ index } Z`
275+ execFileSync ( 'git' , [
276+ '-c' , 'user.name=DevCodex Test' ,
277+ '-c' , 'user.email=devcodex-test@example.invalid' ,
278+ '-c' , 'commit.gpgSign=false' ,
279+ 'commit' , '--allow-empty' , '--quiet' , '--no-gpg-sign' , '-m' , `lineage-${ index } `
280+ ] , {
281+ cwd : repoRoot ,
282+ windowsHide : true ,
283+ env : {
284+ ...process . env ,
285+ GIT_AUTHOR_DATE : timestamp ,
286+ GIT_COMMITTER_DATE : timestamp
287+ }
288+ } )
289+ heads . push ( execFileSync ( 'git' , [ 'rev-parse' , 'HEAD' ] , {
290+ cwd : repoRoot ,
291+ encoding : 'utf8' ,
292+ windowsHide : true
293+ } ) . trim ( ) )
294+ }
295+ return {
296+ repoRoot,
297+ ancestorHead : heads [ 0 ] ,
298+ previousHead : heads [ 1 ] ,
299+ currentHead : heads [ 2 ]
300+ }
301+ }
302+
265303function main ( ) {
266304 const fixtureRoot = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'devcodex-validation-budget-control-' ) )
267305 const activeRoot = path . join ( fixtureRoot , '.devcodex' , 'devcodex' )
@@ -604,21 +642,12 @@ function main() {
604642 sessionKey : rolloverSession ,
605643 control : rolloverControl
606644 } )
607- const currentHead = execFileSync ( 'git' , [ 'rev-parse' , 'HEAD' ] , {
608- cwd : REPO_ROOT ,
609- encoding : 'utf8' ,
610- windowsHide : true
611- } ) . trim ( )
612- const previousHead = execFileSync ( 'git' , [ 'rev-parse' , 'HEAD^' ] , {
613- cwd : REPO_ROOT ,
614- encoding : 'utf8' ,
615- windowsHide : true
616- } ) . trim ( )
617- const ancestorHead = execFileSync ( 'git' , [ 'rev-parse' , 'HEAD^^' ] , {
618- cwd : REPO_ROOT ,
619- encoding : 'utf8' ,
620- windowsHide : true
621- } ) . trim ( )
645+ const {
646+ repoRoot : rolloverGitRoot ,
647+ currentHead,
648+ previousHead,
649+ ancestorHead
650+ } = createGitLineageFixture ( fixtureRoot )
622651 const rolloverRootPlan = fixturePlan ( rolloverTaskId , contextEpoch , 'root-rollover-parent' )
623652 const rolloverRootCandidate = { ...fixtureCandidate ( 'root-rollover-parent' ) , head : ancestorHead }
624653 const rolloverContext = authorityContext ( {
@@ -633,7 +662,8 @@ function main() {
633662 candidate : rolloverRootCandidate ,
634663 authorityContext : rolloverContext ,
635664 activeRoot,
636- execute : true
665+ execute : true ,
666+ gitRepoRoot : rolloverGitRoot
637667 } )
638668 const rolloverStore = createValidationEvidenceStore ( {
639669 activeRoot,
@@ -679,7 +709,8 @@ function main() {
679709 candidate : rolloverNextCandidate ,
680710 authorityContext : rolloverNextContext ,
681711 activeRoot,
682- execute
712+ execute,
713+ gitRepoRoot : rolloverGitRoot
683714 } ) , 'VALIDATION_CONTINUATION_SCOPE_WIDENED' )
684715 }
685716 const rolloverPreview = resolveAiBudgetAuthority ( {
@@ -688,7 +719,8 @@ function main() {
688719 candidate : rolloverNextCandidate ,
689720 authorityContext : rolloverNextContext ,
690721 activeRoot,
691- execute : false
722+ execute : false ,
723+ gitRepoRoot : rolloverGitRoot
692724 } )
693725 assert . strictEqual ( rolloverPreview . decision , 'auto-root-rollover-plan-only' )
694726 const rolloverExecution = resolveAiBudgetAuthority ( {
@@ -697,7 +729,8 @@ function main() {
697729 candidate : rolloverNextCandidate ,
698730 authorityContext : rolloverNextContext ,
699731 activeRoot,
700- execute : true
732+ execute : true ,
733+ gitRepoRoot : rolloverGitRoot
701734 } )
702735 assert . strictEqual ( rolloverExecution . decision , 'auto-root-rollover-authorized' )
703736 assert . strictEqual ( rolloverExecution . authority . parentRootReceiptDigest , rolloverRoot . authority . receiptDigest )
@@ -738,7 +771,8 @@ function main() {
738771 candidate : completedRolloverCandidate ,
739772 authorityContext : completedRolloverContext ,
740773 activeRoot,
741- execute : false
774+ execute : false ,
775+ gitRepoRoot : rolloverGitRoot
742776 } )
743777 assert . strictEqual ( completedRolloverPreview . decision , 'auto-root-rollover-plan-only' )
744778 const completedRolloverExecution = resolveAiBudgetAuthority ( {
@@ -747,7 +781,8 @@ function main() {
747781 candidate : completedRolloverCandidate ,
748782 authorityContext : completedRolloverContext ,
749783 activeRoot,
750- execute : true
784+ execute : true ,
785+ gitRepoRoot : rolloverGitRoot
751786 } )
752787 assert . strictEqual ( completedRolloverExecution . decision , 'auto-root-rollover-authorized' )
753788 assert . strictEqual ( completedRolloverExecution . authority . parentRootReceiptDigest ,
@@ -1054,7 +1089,11 @@ function main() {
10541089 currentPending . bindingDigest , 'failed pending CAS must preserve the unique current binding' )
10551090 process . stdout . write ( 'test-validation-budget-control: ok\n' )
10561091 } finally {
1057- fs . rmSync ( fixtureRoot , { recursive : true , force : true } )
1092+ if ( process . env . DEVCODEX_KEEP_TEST_ARTIFACTS === '1' ) {
1093+ process . stderr . write ( `[test-validation-budget-control] retained ${ fixtureRoot } \n` )
1094+ } else {
1095+ fs . rmSync ( fixtureRoot , { recursive : true , force : true } )
1096+ }
10581097 }
10591098}
10601099
0 commit comments