workspace: the root CLAUDE.md becomes a symlink; check 5 learns two shapes (R-230(b))
gates / gates (push) Successful in 7s
gates / gates (push) Successful in 7s
Two files kept identical by hand and one check is a divergence class policed forever; one file reachable by two paths cannot diverge at all. install_workspace.py now links by default, MIGRATES an existing regular file (backing it up first and SAYING SO if it differed -- that difference is the last chance to notice an unsynced edit), and keeps --copy for a clone that wants the old shape. Check 5 asserts a different thing per shape: for a link, that it points at the versioned copy and resolves to a real file; for two files, byte-identity as before. A dangling link is worse than a diverged copy -- the instructions load NOTHING and there is no content left to notice is wrong -- so that case is red-proofed. NOT yet proven to LOAD: that needs a fresh session and a hook line, which is Phase 7. If it does not load, this reverts to the copy.
This commit is contained in:
@@ -219,19 +219,58 @@ def check_temporary(path, failures, tally):
|
||||
|
||||
|
||||
def check_workspace_copy(workspace_root, failures, tally):
|
||||
"""Check 5 — the live workspace CLAUDE.md agrees with its versioned copy.
|
||||
|
||||
TWO LEGAL SHAPES, and the check asserts a different thing in each:
|
||||
|
||||
LINK (this workspace since 2026-08-06) — the live file IS the versioned file. Divergence is
|
||||
not possible, so there is nothing to compare; what can still break is the LINK, so that
|
||||
is what is asserted: it points at the versioned copy and resolves to a real file. A
|
||||
dangling link is worse than a diverged copy — the workspace instructions stop loading
|
||||
entirely, and nothing else would say so.
|
||||
COPY (any other clone) — two real files, asserted byte-identical as before.
|
||||
|
||||
The link shape is not forced on anyone: a clone that has two files is checked as two files.
|
||||
"""
|
||||
live = os.path.join(workspace_root, "CLAUDE.md")
|
||||
copy = os.path.join(workspace_root, WORKSPACE_COPY)
|
||||
|
||||
if os.path.islink(live):
|
||||
target = os.readlink(live)
|
||||
resolved = os.path.realpath(live)
|
||||
expected = os.path.realpath(copy)
|
||||
ok_target = resolved == expected
|
||||
ok_real = os.path.isfile(resolved)
|
||||
tally.append(
|
||||
" workspace file : SYMLINK -> %s (%s)"
|
||||
% (target, "resolves to the versioned copy" if ok_target and ok_real else "BROKEN")
|
||||
)
|
||||
if not ok_real:
|
||||
failures.append(
|
||||
"%s is a symlink to %s, which does not resolve to a real file. A dangling link "
|
||||
"means the workspace instructions load NOTHING — worse than two files that "
|
||||
"disagree, because there is no content to notice is wrong." % (live, target)
|
||||
)
|
||||
elif not ok_target:
|
||||
failures.append(
|
||||
"%s is a symlink, but it resolves to %s instead of the versioned copy %s. The "
|
||||
"whole point of the link is that there is exactly one file; pointing it elsewhere "
|
||||
"reintroduces the divergence it removed." % (live, resolved, expected)
|
||||
)
|
||||
return
|
||||
|
||||
if not os.path.exists(live) or not os.path.exists(copy):
|
||||
tally.append(" workspace copy : n/a (not this workspace)")
|
||||
return
|
||||
with io_open(live) as a, io_open(copy) as b:
|
||||
same = a.read() == b.read()
|
||||
tally.append(" workspace copy identical : %s" % ("yes" if same else "NO"))
|
||||
tally.append(" workspace copy identical : %s (two-file shape)" % ("yes" if same else "NO"))
|
||||
if not same:
|
||||
failures.append(
|
||||
"%s and %s have diverged. The live workspace file sits in a directory that is not a "
|
||||
"git repo, so the copy is its only version-controlled record — nothing but this "
|
||||
"check enforces that they agree. Copy the live file over the versioned one."
|
||||
"check enforces that they agree. Copy the live file over the versioned one, or make "
|
||||
"the live file a symlink to it (see scripts/install_workspace.py --link)."
|
||||
% (live, copy)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user