Problem
Step 3ter drift gate currently iterates files via git ls-files <stack-roots> on the downstream checkout, then probes each against upstream with git ls-tree devkit-node/master -- \"\$f\". This catches drift on files PRESENT locally and DIFFERENT from upstream, plus correctly skips downstream-only files (upstream returns empty).
But it does NOT catch the inverse: files PRESENT upstream that are MISSING locally — e.g. a downstream that did --ours against a new upstream file during conflict resolution, or accidentally deleted a stack file. The gate silently passes.
Fix
Switch the scan source: iterate git ls-tree -r devkit-node/master --name-only modules/ lib/ config/ (upstream tree) and probe each against local. Missing-locally case becomes detectable.
Logic change:
# OLD
done < <(git ls-files modules lib config 2>/dev/null \
| grep -vE "/(tests |__tests__)/" | grep -vE "\.(test|spec)\.(js|jsx|ts|tsx)$")
# NEW
done < <(git ls-tree -r devkit-node/master --name-only modules/ lib/ config/ 2>/dev/null \
| grep -vE "/(tests|__tests__)/" | grep -vE "\.(test|spec)\.(js|jsx|ts|tsx)$")
Then in the loop body:
upstream_blob=$(git ls-tree devkit-node/master -- "$f" | awk '{print $3}') # always non-empty now
local_blob=$(git rev-parse "HEAD:$f" 2>/dev/null)
if [ -z "$local_blob" ]; then
echo "BLOCK: missing locally (was on upstream): $f"
echo " Fix — restore: git checkout devkit-node/master -- $f"
drift_found=1
elif [ "$upstream_blob" != "$local_blob" ]; then
echo "BLOCK: drift on shared stack file: $f"
...
fi
Why follow-up not in #3777
The no-ledger refactor was already scoped (drop ledger condition + auto-derive scan list). Adding scan-source flip would have ballooned the PR. Track separately.
Cross-refs
Problem
Step 3ter drift gate currently iterates files via
git ls-files <stack-roots>on the downstream checkout, then probes each against upstream withgit ls-tree devkit-node/master -- \"\$f\". This catches drift on files PRESENT locally and DIFFERENT from upstream, plus correctly skips downstream-only files (upstream returns empty).But it does NOT catch the inverse: files PRESENT upstream that are MISSING locally — e.g. a downstream that did
--oursagainst a new upstream file during conflict resolution, or accidentally deleted a stack file. The gate silently passes.Fix
Switch the scan source: iterate
git ls-tree -r devkit-node/master --name-only modules/ lib/ config/(upstream tree) and probe each against local. Missing-locally case becomes detectable.Logic change:
Then in the loop body:
Why follow-up not in #3777
The no-ledger refactor was already scoped (drop ledger condition + auto-derive scan list). Adding scan-source flip would have ballooned the PR. Track separately.
Cross-refs