BOHICA-LABS / BOHICA-LABS/vsdd-factory

bug(factory-health/architecture): product-branch merge silently DELETES a file the nested .factory worktree is serving — near data-loss, no git warning

Open
#342 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
2
Forks
1
Avg merge
6h 43m
Merged PRs (30d)
29

Description

## Summary

Because `.factory/` is a git worktree **nested inside the main worktree's working directory**, and a factory artifact (`.factory/cycles/v1.0.0-greenfield/implementation/red-gate-log.md`) was tracked on BOTH branches (the leak documented in the companion issue #341), a routine product PR merge that DELETED that path from `develop` caused git to physically `rm` the on-disk file — the very file the nested `factory-artifacts` worktree was actively serving. The factory worktree's working copy vanished with **NO warning**. It survived only because the `factory-artifacts` branch had the file committed; `git checkout -- ` from inside `.factory` restored the live 317-line copy.

## Severity: HIGH (data-loss class)

Recoverable in this instance **only by luck** (the file happened to be committed on `factory-artifacts`). It would be PERMANENT, unrecoverable loss if the factory worktree had **uncommitted** edits to the path — which is the COMMON case, since agents write factory artifacts continuously between commits.

## Environment

vsdd-factory plugin 1.0.0-rc.21, Claude Code, greenfield+wave mode. Layout: `.factory/` is a git worktree on the `factory-artifacts` orphan branch, MOUNTED AS A SUBDIRECTORY of the main product worktree (`/.factory`). Product code on `develop` (gitflow). Repo: private.

## Root cause chain

1. **Precondition (companion issue):** the path was tracked on `develop` AND on `factory-artifacts`, pointing at the same physical file under the main worktree.
2. The cleanup PR ran `git rm --cached` to untrack the path on `develop` → the merge commit records a `delete` of that path.
3. Local `develop` was behind; merging the PR fast-forwarded the MAIN worktree, applying the net tree change including the delete.
4. git's working-tree update for the fast-forward physically removed `.factory/cycles/.../red-gate-log.md` — treating it as an ordinary tracked path in the main worktree, with NO awareness that a nested worktree (`factory-artifacts`) owns/serves that exact path.
5. Result: the factory worktree showed ` D` (deleted in working tree); the live artifact was gone from disk until manually restored.

## Why this is dangerous

- No git warning or refusal — checkout/merge silently clobbered a nested-worktree file.
- `.gitignore` gives ZERO protection here: ignore rules never stop checkout from deleting a path the target commit omits.
- Recoverable ONLY because `factory-artifacts` had it committed. If the factory worktree had ANY uncommitted edits to that file at merge time (the normal state — agents write artifacts continuously between commits), those edits would be PERMANENTLY lost with no reflog/object to recover from.
- This generalizes: ANY path that is both (a) tracked on a product branch and (b) lives under the nested `.factory` worktree is a data-loss landmine on every merge/checkout/rebase that changes that path.

## Evidence

- `git worktree list`: main worktree at repo root `[develop]`; `.factory` worktree `[factory-artifacts]` — nested subdir.
- The cleanup merge included `delete mode 100644 .factory/cycles/v1.0.0-greenfield/implementation/red-gate-log.md` with no nested-worktree warning.
- After merge: `git -C .factory status --porcelain` → ` D cycles/v1.0.0-greenfield/implementation/red-gate-log.md` (working file gone).
- Recovery: `git -C .factory checkout -- cycles/.../red-gate-log.md` → restored 317-line live copy; factory worktree clean.

## Proposed fixes (defense in depth, in order of leverage)

1. **ARCHITECTURAL (root fix): do NOT nest the `.factory` worktree INSIDE the main worktree's working directory.** Mount it as a sibling dir (e.g. `../.factory/`) or under `$GIT_DIR` (e.g. `.git/factory-worktrees/factory-artifacts`). A worktree whose path is not under another worktree's working tree cannot be clobbered by that worktree's checkouts. This is the durable fix and eliminates the entire risk class.
2. **INVARIANT (the companion fix, restated):** never allow ANY `.factory/*` path to be tracked on a product branch. Enforce in `factory-health` (detect + `git rm --cached`) AND a `code-delivery` pre-PR guard. Removing the dual-tracking removes the landmine.
3. **SAFETY CHECK:** before any merge/pull/checkout the orchestrator drives on the product branch, `factory-health` should verify no target-tree path-deletions intersect the nested `.factory` worktree's tracked or modified paths; if they do, STOP and require manual handling.

## Relationship to the companion issue #341

The companion issue documents the leak mechanism and the `git rm --cached` fix. This issue documents the near-data-loss CONSEQUENCE of the same nested-worktree layout. The minimal mitigation here is the companion's fix (prevent the dual-tracking that creates the exposure window), but the robust mitigation is fix #1 above (structural worktree separation), which eliminates this risk class entirely regardless of future leak scenarios.

## Related issues (distinct, cross-referenced)

- **#210** — silent data loss when parallel agents edit/rename the same file. DIFFERENT mechanism (in-process orchestration race, not a git worktree-overlap deletion); same data-loss severity class.
- **#313** — factory-vs-product artifact routing; related theme, opposite problem (artifacts not tracked).
- **#263** — gitlink-mode overreach; same `.factory/` family but about submodule tracking, not nested-worktree checkout destructiveness.

## Acceptance criteria

- [ ] Decision on the architectural fix: mount `.factory` outside the main worktree tree (sibling or under `$GIT_DIR`).
- [ ] `factory-health` gains a pre-merge safety check for target-tree deletions intersecting the nested worktree.
- [ ] Cross-link to companion #341, #210, #313, #263.

---

_Plugin `vsdd-factory 1.0.0-rc.21`, Claude Code. Filed from a private downstream project; no private content included._

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.