fix: eliminate EMPTY_DIR_OID/empty-file collision with explicit kind discriminator (muse#101,#102,#103,#104)
Root cause (muse#104): EMPTY_DIR_OID = blob_id(b"") is both the sentinel marking a tracked empty directory AND the legitimate content hash of a genuinely empty file -- every call site that inferred file-vs-directory from object_id == EMPTY_DIR_OID was ambiguous by construction.
Fix: add an explicit kind: "file" | "dir" field to StagedEntry, bump stage schema to v4 with a one-time best-effort migration for pre-v4 entries (infer from whether the path is an on-disk directory). All ~19 call sites across plugin.py, code_stage.py, status.py, mv.py, diff.py updated to check kind instead of object_id equality. Final grep audit: zero remaining object_id-equality-as-file-vs-dir comparisons anywhere.
muse#102 (empty file silently dropped from manifest): fixed by the kind discriminator alone -- an empty file now stays kind="file" and is never shunted into the directories bucket.
muse#103 (stuck directory sentinel, directory still on disk): code_stage.py's deleted_committed_dirs detection now also fires when a committed empty dir's path is still present but fully excluded by .museignore, not just when physically absent -- muse code add . auto-detects and stages the removal.
muse#101 (false 'deleted' status, path in both manifest and directories): bisected the real historical corruption source in ~/ecosystem/presentations/build-with-muse -- introducing commit 903cc80e ('Add Episode 03 script') transitioned a placeholder directory to a real file in the same commit that carries forward HEAD's committed empty dirs; the stale directory entry was never dropped. The already-shipped subtraction fix in plugin.py::snapshot() (0.2.1rc8) prevents this for new commits; this commit adds a locked-in regression test (TestManifestDirectoriesMutualExclusion) plus the kind-based fix that makes the underlying ambiguity structurally impossible going forward.
New consolidated reproduction suite: tests/test_empty_dir_sentinel_invariants.py (9 tests, one class per symptom). Full targeted regression run: 618 + 398 = 1016 tests across code_add, directories_feature, status, mv, diff, resolve, commit, merge_engine, cherry_pick, merge, pull, rebase suites -- zero regressions.
Semantic Changes
55 symbols
Files Changed
+1
~8
1207 in snapshot
0 comments
muse hub commit comment sha256:47e5542341c5a936597b3974abf274d75185c50c3b89917c21d8face06fa6691 --body "your comment"
No comments yet. Be the first to start the discussion.