| name | factory-worktree-health |
| description | Validates factory worktree health on pipeline start. Checks .factory/ (all modes) and .factory-project/ (multi-repo only). Verifies remote branch existence, local worktree mount, and sync state. Auto-repairs if possible. Runs on ALL pipeline modes (greenfield, brownfield, feature, resume). Executed by devops-engineer.
|
Factory Worktree Health Check
When This Skill Runs
On every pipeline start, before mode detection or any .factory/ reads.
This is a blocking precondition — no pipeline work proceeds until this passes.
Applies to: greenfield, brownfield, feature mode, and pipeline resume.
Worktrees to Check
| Worktree | Branch | Required When |
|---|
.factory/ | factory-artifacts | Always (all modes) |
.factory-project/ | factory-project-artifacts | Multi-repo only (project.yaml exists) |
Run the health check sequence below for each required worktree.
If project.yaml exists in the repo root, check BOTH worktrees.
If project.yaml does not exist, check only .factory/.
Executor
devops-engineer (requires exec tool for git commands)
Health Check Sequence
Step 0: Workspace Isolation Guard (BLOCKING)
Before ANY git commands, verify you are in the target project — NOT the engine:
CWD=$(pwd)
if [[ "$CWD" == *"dark-factory"* ]]; then
echo "FATAL: Running in dark-factory engine directory ($CWD). Refusing to proceed."
echo "Fix: orchestrator must set cwd to the resolved project path in Agent tool."
exit 1
fi
REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "none")
if [[ "$REMOTE_URL" == *"dark-factory"* ]]; then
echo "FATAL: Git remote ($REMOTE_URL) points to dark-factory engine repo."
echo "Fix: you are in the wrong repository."
exit 1
fi
if [[ -f .factory/.git ]]; then
GITDIR_PATH=$(cat .factory/.git | sed 's/gitdir: //')
if [[ "$GITDIR_PATH" == *"dark-factory"* ]]; then
echo "FATAL: .factory/.git points to dark-factory ($GITDIR_PATH)."
echo "Fix: remove .factory/ and re-run worktree setup."
exit 1
fi
fi
If ANY check fails, report FACTORY_WORKTREE_HEALTH: FAIL with the error and STOP.
Run the following steps for each worktree/branch pair. Use these variables:
| Variable | .factory/ | .factory-project/ |
|---|
WORKTREE_DIR | .factory | .factory-project |
BRANCH_NAME | factory-artifacts | factory-project-artifacts |
Step 1: Check Remote Branch
git ls-remote --heads origin ${BRANCH_NAME}
Step 2: Check Local Worktree
git -C ${WORKTREE_DIR} rev-parse --git-dir 2>/dev/null
- Succeeds (worktree is valid): Proceed to Step 3
- Fails or directory doesn't exist:
- If directory exists as a regular directory (no
.git marker):
mv ${WORKTREE_DIR} ${WORKTREE_DIR}-backup-$(date +%s)
- Mount the worktree:
git worktree add ${WORKTREE_DIR} ${BRANCH_NAME}
- If backup was created and had contents:
cp -r ${WORKTREE_DIR}-backup-*/* ${WORKTREE_DIR}/ 2>/dev/null || true
rm -rf ${WORKTREE_DIR}-backup-*
- Proceed to Step 3
Step 3: Verify Worktree Branch
git -C ${WORKTREE_DIR} branch --show-current
Step 4: Check Sync State
git -C ${WORKTREE_DIR} fetch origin ${BRANCH_NAME} 2>/dev/null
LOCAL=$(git -C ${WORKTREE_DIR} rev-parse HEAD)
REMOTE=$(git -C ${WORKTREE_DIR} rev-parse origin/${BRANCH_NAME} 2>/dev/null || echo "none")
BASE=$(git -C ${WORKTREE_DIR} merge-base HEAD origin/${BRANCH_NAME} 2>/dev/null || echo "none")
Evaluate:
| Condition | Meaning | Action |
|---|
LOCAL == REMOTE | In sync | Healthy — proceed |
REMOTE == "none" | Remote branch has no commits yet | Healthy (fresh init) — proceed |
LOCAL != REMOTE and BASE == REMOTE | Local is ahead | Warn and push: git -C ${WORKTREE_DIR} push origin ${BRANCH_NAME} |
LOCAL != REMOTE and BASE == LOCAL | Local is behind | Pull: git -C ${WORKTREE_DIR} pull --ff-only origin ${BRANCH_NAME} |
LOCAL != REMOTE and BASE != LOCAL and BASE != REMOTE | Diverged | STOP. Report error with both SHAs. Human must resolve. |
Step 4b: Factory lock status (BC-6.23.001 PC8 — shared helper)
After the sync state check, invoke the shared three-state lock status helper and append the
output to the health report:
plugins/vsdd-factory/bin/factory-lock-status.sh "${WORKTREE_DIR}/STATE.md" "$(git config user.email)"
The helper returns one of:
Factory lock: FREE — no lock held or lock expired
Factory lock: HELD by this session (expires <expires_at>) — self-held, unexpired
Factory lock: HELD by <holder_email> since <locked_at> (expires <expires_at>) — foreign, unexpired
Factory lock: FREE (malformed block — treated as unlocked) — parse failure, fail-open
This check reads the LOCAL STATE.md (no fetch required). Invokes the shared
factory-lock-status.sh helper (BC-6.23.001 PC8 AC-008 shared-helper mandate) so display
strings cannot diverge from /factory-health.
Step 5: Report Result
Report to orchestrator (one report per worktree checked):
FACTORY_WORKTREE_HEALTH: PASS
Worktree: ${WORKTREE_DIR}/
Remote branch: ${BRANCH_NAME} (exists)
Local worktree: ${WORKTREE_DIR}/ (mounted)
Sync state: [in-sync | pushed-local | pulled-remote | fresh-init]
Commits: [N] on ${BRANCH_NAME}
Or on failure:
FACTORY_WORKTREE_HEALTH: FAIL
Worktree: ${WORKTREE_DIR}/
Error: [description]
Recovery: [actionable command]
Failure Is Blocking
If this skill reports FAIL for ANY worktree, the orchestrator MUST NOT proceed.
.factory/ is required for:
- STATE.md (state-manager)
- All spec artifacts (Phase 1+)
- Artifact backup at phase gates
- Pipeline resume/crash recovery
Output
Health check report to orchestrator (one per worktree):
FACTORY_WORKTREE_HEALTH: PASS | FAIL
Worktree: [dir]
Remote branch: [name] (exists | created)
Sync state: [in-sync | pushed-local | pulled-remote | fresh-init]
Quality Gate
.factory-project/ is required for (multi-repo only):
- Project-level STATE.md (cross-repo coordination)
- Unified specs (L1 brief, L2 domain spec, L3 PRD)
- Cross-repo dependency graph and wave plans
- Cross-repo integration gate results
- Project-level cost tracking