@@ -267,3 +267,93 @@ func TestHooksRunAfterLocalOnlyEnable(t *testing.T) {
267267 t .Fatal ("commit has no Entire-Checkpoint trailer — hooks silently no-op'd with only settings.local.json" )
268268 }
269269}
270+
271+ // TestEnableReenablesProjectScopeAfterProjectDisable is a full-flow
272+ // reproduction of a re-enable regression: after `entire disable --project`,
273+ // running `entire enable --checkpoint-remote ...` with no --project/--local
274+ // reported success but wrote the enabled flag to .entire/settings.local.json,
275+ // leaving the project .entire/settings.json the user disabled still
276+ // enabled=false.
277+ //
278+ // Because settings.local.json (enabled:true) overrides settings.json in the
279+ // merged view that both `entire status` and IsEnabled read, status actually
280+ // reported ENABLED — the effective state was correct and only the committed
281+ // file was stale. That still bites anyone without the local file (a fresh
282+ // clone, a teammate) and leaves the committed source of truth wrong.
283+ //
284+ // This drives the real entire binary end-to-end — enable, disable --project,
285+ // then a setup-flag re-enable — and asserts the PROJECT settings.json (the file
286+ // the user actually disabled) is enabled again.
287+ func TestEnableReenablesProjectScopeAfterProjectDisable (t * testing.T ) {
288+ t .Parallel ()
289+ env := NewTestEnv (t )
290+ defer env .Cleanup ()
291+
292+ env .InitRepo ()
293+
294+ // First-time setup via the real binary; a plain enable writes the project
295+ // .entire/settings.json.
296+ env .RunCLI ("enable" , "--agent" , "claude-code" , "--telemetry=false" )
297+ assertProjectSettingsEnabled (t , env , true )
298+
299+ // Disable at the project scope → settings.json enabled=false.
300+ env .RunCLI ("disable" , "--project" )
301+ assertProjectSettingsEnabled (t , env , false )
302+
303+ // Re-enable with a setup flag but WITHOUT --project/--local. Pre-fix the
304+ // enabled flag landed in settings.local.json, so the project file the user
305+ // disabled stayed enabled=false.
306+ env .RunCLI ("enable" , "--checkpoint-remote" , "github:org/repo" , "--skip-push-sessions" , "--telemetry=false" )
307+
308+ assertProjectSettingsEnabled (t , env , true )
309+
310+ // And no local override may contradict it: settings.local.json must be
311+ // absent or itself enabled:true, so the merged view can't silently flip
312+ // back to disabled by accident of the flow.
313+ assertLocalSettingsAbsentOrEnabled (t , env )
314+ }
315+
316+ // assertLocalSettingsAbsentOrEnabled asserts that .entire/settings.local.json,
317+ // if present, does not carry an enabled:false override that would mask the
318+ // committed project scope.
319+ func assertLocalSettingsAbsentOrEnabled (t * testing.T , env * TestEnv ) {
320+ t .Helper ()
321+ localPath := filepath .Join (env .RepoDir , ".entire" , "settings.local.json" )
322+ data , err := os .ReadFile (localPath )
323+ if os .IsNotExist (err ) {
324+ return
325+ }
326+ if err != nil {
327+ t .Fatalf ("read .entire/settings.local.json: %v" , err )
328+ }
329+ var s struct {
330+ Enabled * bool `json:"enabled"`
331+ }
332+ if err := json .Unmarshal (data , & s ); err != nil {
333+ t .Fatalf ("parse .entire/settings.local.json: %v\n content: %s" , err , data )
334+ }
335+ if s .Enabled != nil && ! * s .Enabled {
336+ t .Fatalf ("settings.local.json carries enabled:false, which would mask the re-enabled project scope\n content: %s" , data )
337+ }
338+ }
339+
340+ // assertProjectSettingsEnabled reads .entire/settings.json (the project scope,
341+ // never settings.local.json) and asserts its enabled flag matches want.
342+ func assertProjectSettingsEnabled (t * testing.T , env * TestEnv , want bool ) {
343+ t .Helper ()
344+ settingsPath := filepath .Join (env .RepoDir , ".entire" , "settings.json" )
345+ data , err := os .ReadFile (settingsPath )
346+ if err != nil {
347+ t .Fatalf ("read .entire/settings.json: %v" , err )
348+ }
349+ var s struct {
350+ Enabled bool `json:"enabled"`
351+ }
352+ if err := json .Unmarshal (data , & s ); err != nil {
353+ t .Fatalf ("parse .entire/settings.json: %v\n content: %s" , err , data )
354+ }
355+ if s .Enabled != want {
356+ t .Fatalf ("project settings.json enabled=%v, want %v — enabled flag written to the wrong scope\n content: %s" ,
357+ s .Enabled , want , data )
358+ }
359+ }
0 commit comments