6c588d6233e4
refuse a folder remote that is not there instead of creating a stand-in at an unmounted disk's path (3.0.45)
- time
- 2026-09-24 15:23 UTC · 2 weeks ago
- machine
- koh2
- agent
- claude-opus-5-5
- session
- koh 3 reliability campaign
- parent
- 15b6b8d6c6d5
↓ koh-6c588d62.tar.gzatlas at this save
files changed4 files
VERSION+1 −1src/cli/cmd_offer.v+7 −0tests/cli_test.v+31 −0v.mod+1 −1src/cli/cmd_offer.v+7 −0
@@ -3,6 +3,7 @@33 module cli44 55 import json6+import os67 import src.machine78 import src.remote89 import src.storage@@ -41,6 +42,12 @@4142 pub fn this_machine_backend() !remote.Backend {4243 settings := machine.load_remote()!4344 if settings.kind == machine.kind_folder {45+ // Only `koh remote` creates the folder. Missing later, it is usually a46+ // disk or share that is not mounted, and a stand-in folder would take47+ // saves the other machine never sees.48+ if !os.is_dir(settings.path) {49+ return error('the remote folder ${settings.path} is not there — is its disk mounted? ("koh remote" changes it)')50+ }4451 return remote.new_folder(settings.path)!4552 }4653 credentials := machine.load_credentials()!tests/cli_test.v+31 −0
@@ -747,6 +747,37 @@747747 assert text_clone.out.contains('[${id}] came in flagged — broke the build')748748 }749749 750+// A folder remote on a disk or share that is not mounted is simply not there.751+// Creating it would put the saves in a stand-in folder the other machine never752+// sees; the offer must say what is wrong instead.753+fn test_an_unmounted_folder_remote_is_not_recreated() {754+ syncroot := temp_repo('unmounted')755+ home := temp_repo('unmounted-home')756+ defer {757+ os.rmdir_all(syncroot) or {}758+ os.rmdir_all(home) or {}759+ }760+ mount := os.join_path(syncroot, 'nas')761+ remote := os.join_path(mount, 'koh')762+ a := os.join_path(syncroot, 'proj')763+ os.mkdir_all(a) or { panic(err) }764+ init_repo(a)765+ assert run_home(a, home, 'remote', 'folder', remote).code == 0766+ write(a, 'a.txt', 'one\n')767+ assert run_home(a, home, 'save', 'first').code == 0768+ os.rename(mount, os.join_path(syncroot, 'nas-unplugged')) or { panic(err) }769+ os.mkdir(mount) or { panic(err) }770+ offered := run_home(a, home, 'offer')771+ assert offered.code == 1772+ assert offered.err.contains('mounted')773+ assert !os.exists(remote)774+ write(a, 'a.txt', 'two\n')775+ saved := run_home(a, home, 'save', 'second')776+ assert saved.code == 0777+ assert saved.out.contains('mounted')778+ assert !os.exists(remote)779+}780+750781 fn test_man_and_koh2_handoff() {751782 dir := temp_repo('man')752783 home := temp_repo('man-home')v.mod+1 −1
@@ -1,6 +1,6 @@11 Module {22 name: 'koh3'3- version: '3.0.44'3+ version: '3.0.45'44 description: 'One SQLite file per repo, one line of history.'55 license: 'MIT'66 }