@@ -3184,6 +3184,15 @@ fn run_command(command: Commands) {
31843184 } => {
31853185 let root = get_lattice_root ( ) ;
31863186
3187+ // Check if .lattice/ has staged changes (index-aware for pre-commit, #31)
3188+ let lattice_staged = std:: process:: Command :: new ( "git" )
3189+ . args ( [ "diff" , "--cached" , "--quiet" , "--" , ".lattice/" ] )
3190+ . current_dir ( & root)
3191+ . output ( )
3192+ . ok ( )
3193+ . map ( |o| !o. status . success ( ) ) // exit 1 = staged changes exist
3194+ . unwrap_or ( false ) ;
3195+
31873196 // 1. Freshness: single git call for lattice commit hash + timestamp
31883197 let lattice_git = std:: process:: Command :: new ( "git" )
31893198 . args ( [ "log" , "-1" , "--format=%H %ct" , "--" , ".lattice/" ] )
@@ -3223,9 +3232,14 @@ fn run_command(command: Commands) {
32233232 . parse :: < i64 > ( )
32243233 . ok ( )
32253234 } ) ;
3226- let freshness_gap_hours = match ( lattice_ts, code_ts) {
3227- ( Some ( l) , Some ( c) ) if c > l => ( c - l) as u64 / 3600 ,
3228- _ => 0 ,
3235+ // If .lattice/ has staged changes, this commit IS the catch-up (#31)
3236+ let freshness_gap_hours = if lattice_staged {
3237+ 0
3238+ } else {
3239+ match ( lattice_ts, code_ts) {
3240+ ( Some ( l) , Some ( c) ) if c > l => ( c - l) as u64 / 3600 ,
3241+ _ => 0 ,
3242+ }
32293243 } ;
32303244
32313245 // 2. Load graph once — derive all metrics from the index
@@ -3264,27 +3278,41 @@ fn run_command(command: Commands) {
32643278 . flat_map ( |files| files. iter ( ) . map ( |f| f. path . clone ( ) ) )
32653279 . collect ( ) ;
32663280
3267- let ( tracked_files_changed, total_files_changed) = if !lattice_commit. is_empty ( ) {
3268- let output = std:: process:: Command :: new ( "git" )
3269- . args ( [
3270- "diff" ,
3271- "--name-only" ,
3272- & lattice_commit,
3273- "--" ,
3274- "." ,
3275- ":!.lattice/" ,
3276- ] )
3277- . current_dir ( & root)
3278- . output ( )
3279- . ok ( )
3280- . map ( |o| String :: from_utf8_lossy ( & o. stdout ) . to_string ( ) )
3281- . unwrap_or_default ( ) ;
3282- let changed: Vec < & str > = output. lines ( ) . filter ( |l| !l. is_empty ( ) ) . collect ( ) ;
3283- let tracked = changed. iter ( ) . filter ( |f| bound_files. contains ( * * f) ) . count ( ) ;
3284- ( tracked, changed. len ( ) )
3285- } else {
3286- ( 0 , 0 )
3287- } ;
3281+ // If lattice is staged, this commit resolves the diff coupling (#31)
3282+ let ( tracked_files_changed, total_files_changed, affected_file_names) =
3283+ if lattice_staged {
3284+ ( 0 , 0 , Vec :: new ( ) )
3285+ } else if !lattice_commit. is_empty ( ) {
3286+ let output = std:: process:: Command :: new ( "git" )
3287+ . args ( [
3288+ "diff" ,
3289+ "--name-only" ,
3290+ & lattice_commit,
3291+ "--" ,
3292+ "." ,
3293+ ":!.lattice/" ,
3294+ ] )
3295+ . current_dir ( & root)
3296+ . output ( )
3297+ . ok ( )
3298+ . map ( |o| String :: from_utf8_lossy ( & o. stdout ) . to_string ( ) )
3299+ . unwrap_or_default ( ) ;
3300+ let changed: Vec < String > = output
3301+ . lines ( )
3302+ . filter ( |l| !l. is_empty ( ) )
3303+ . map ( |s| s. to_string ( ) )
3304+ . collect ( ) ;
3305+ let affected: Vec < String > = changed
3306+ . iter ( )
3307+ . filter ( |f| bound_files. contains ( f. as_str ( ) ) )
3308+ . cloned ( )
3309+ . collect ( ) ;
3310+ let tracked = affected. len ( ) ;
3311+ let total = changed. len ( ) ;
3312+ ( tracked, total, affected)
3313+ } else {
3314+ ( 0 , 0 , Vec :: new ( ) )
3315+ } ;
32883316
32893317 // 4. Lint (strict mode only)
32903318 let lint_issues = if strict {
@@ -3331,7 +3359,9 @@ fn run_command(command: Commands) {
33313359 "total_files_changed" : total_files_changed,
33323360 "tracked_files_changed" : tracked_files_changed,
33333361 "bound_files_count" : bound_files. len( ) ,
3362+ "affected_files" : affected_file_names,
33343363 } ,
3364+ "lattice_staged" : lattice_staged,
33353365 } ) ;
33363366 if strict {
33373367 result[ "lint" ] = json ! ( { "issues" : lint_issues } ) ;
@@ -3346,7 +3376,9 @@ fn run_command(command: Commands) {
33463376 println ! ( "{} {}\n " , "HEALTH:" . bold( ) , verdict_colored) ;
33473377
33483378 println ! ( " {}" , "Freshness:" . bold( ) ) ;
3349- if freshness_gap_hours > 0 {
3379+ if lattice_staged {
3380+ println ! ( " {}" , "Lattice update staged — credited" . green( ) ) ;
3381+ } else if freshness_gap_hours > 0 {
33503382 println ! (
33513383 " Lattice is {}h behind code changes" ,
33523384 freshness_gap_hours
@@ -3362,16 +3394,26 @@ fn run_command(command: Commands) {
33623394 println ! ( ) ;
33633395
33643396 println ! ( " {}" , "Code Impact:" . bold( ) ) ;
3365- println ! (
3366- " {} files changed since last lattice update" ,
3367- total_files_changed
3368- ) ;
3369- if !bound_files. is_empty ( ) {
3397+ if lattice_staged {
3398+ println ! (
3399+ " {}" ,
3400+ "Lattice update staged — diff coupling cleared" . green( )
3401+ ) ;
3402+ } else {
33703403 println ! (
3371- " {} of {} lattice-tracked files affected" ,
3372- tracked_files_changed,
3373- bound_files. len( )
3404+ " {} files changed since last lattice update" ,
3405+ total_files_changed
33743406 ) ;
3407+ if !bound_files. is_empty ( ) {
3408+ println ! (
3409+ " {} of {} lattice-tracked files affected" ,
3410+ tracked_files_changed,
3411+ bound_files. len( )
3412+ ) ;
3413+ }
3414+ for f in & affected_file_names {
3415+ println ! ( " {}" , f. yellow( ) ) ;
3416+ }
33753417 }
33763418
33773419 if strict {
@@ -3488,6 +3530,37 @@ fn run_command(command: Commands) {
34883530 format,
34893531 } => {
34903532 let root = get_lattice_root ( ) ;
3533+
3534+ // Index-aware: if .lattice/ has staged changes, credit this commit (#31)
3535+ let lattice_staged = std:: process:: Command :: new ( "git" )
3536+ . args ( [ "diff" , "--cached" , "--quiet" , "--" , ".lattice/" ] )
3537+ . current_dir ( & root)
3538+ . output ( )
3539+ . ok ( )
3540+ . map ( |o| !o. status . success ( ) )
3541+ . unwrap_or ( false ) ;
3542+
3543+ if lattice_staged {
3544+ if is_json ( & format) {
3545+ println ! (
3546+ "{}" ,
3547+ serde_json:: to_string_pretty( & json!( {
3548+ "stale" : false ,
3549+ "lattice_staged" : true ,
3550+ "gap_hours" : 0 ,
3551+ "threshold_hours" : threshold,
3552+ } ) )
3553+ . unwrap( )
3554+ ) ;
3555+ } else {
3556+ println ! (
3557+ "{}" ,
3558+ "Fresh: lattice update staged — credited for this commit" . green( )
3559+ ) ;
3560+ }
3561+ return ;
3562+ }
3563+
34913564 // Get the most recent commit timestamp touching .lattice/ files
34923565 let lattice_ts = std:: process:: Command :: new ( "git" )
34933566 . args ( [ "log" , "-1" , "--format=%ct" , "--" , ".lattice/" ] )
0 commit comments