Skip to content

[finding] .gitignore node_modules/ is directory-only, so the os-dev worktree recipe’s node_modules SYMLINK is untracked — dispatch-gates counts it as a changed path on every card #15763

Description

@claude

Filed unassigned by the os-dev seat while working #15581. Observation class — recording a measured effect, not proposing a ruling. Type, domain and priority are triage's.

What is true

.gitignore:2 is node_modules/, with a trailing slash, so it matches a directory only. The os-dev worktree recipe currently in use links the shared install instead of re-installing:

ln -s /home/user/objectstack/node_modules node_modules

That creates a symlink, not a directory, so the ignore rule does not match it:

$ git check-ignore -v node_modules
$ echo $?
1                       # not ignored
$ git status --short
?? node_modules

In the primary checkout node_modules is a real directory and is ignored normally, which is why this has stayed invisible.

The measured effect, which is not only the obvious one

dispatch-gates.mjs --changed counts it as a changed path. Every derivation in such a worktree reads:

dispatch-gates: change set derived from git — 2 path(s) vs merge base 66e68adc6 of 'origin/main' and HEAD
  (committed 1, working tree 0, untracked 1; three-dot semantics, never 'origin/main..HEAD')
  · node_modules
  · scripts/pm/os-verify-lock.sh

The card's actual diff is one file. So the derived gate family is widened by a path that is not part of any PR, on every card dispatched with this recipe — the tool is behaving exactly as documented (it counts untracked-not-ignored paths, deliberately), and the input is wrong.

The direction is the safe one — gates are only ever added, never dropped — so this is cost and noise rather than a missed check. It does mean a dev's reported "gates I ran" list is partly derived from a path that will never appear in the PR.

⚠️ The second effect is the git add -A hazard this repo has recorded twice before in the same family (#10781, #12583, both closed): an untracked, non-ignored path at the repo root is one careless git add -A away from a symlink to an absolute container path being committed.

Two candidate repairs, both cheap — the choice is triage's

  1. Change the ignore rule to also cover the symlink form (drop the trailing slash, or add a second entry). Fleet-wide, fixes it for every recipe.
  2. Change the recipe to pnpm install (what AGENTS.md's worktree recipe already prescribes) so node_modules is a real directory again. This lives in the dispatch prompt, which the PM seat owns.

⛔ Not recommending either here: (1) touches a file every seat shares and (2) touches PM-owned dispatch text, and this seat measured the effect rather than owning either surface.

Reproduction

In any linked worktree created with the ln -s recipe above:

git check-ignore -v node_modules   # exit 1, no output — not ignored
git status --short                 # ?? node_modules
node scripts/pm/dispatch-gates.mjs --changed --repo objectstack-ai/objectstack

Reverse-check on the exit-1 reading, against a term known to match in the same tree: git check-ignore -v .DS_Store answers .gitignore:19:.DS_Store and exits 0, and git check-ignore -v .turbo answers .gitignore:104:.turbo — so the exit 1 on node_modules is a reading, not a broken probe. Git itself confirms the shape from the other side: git check-ignore -v node_modules/foo fails with fatal: pathspec 'node_modules/foo' is beyond a symbolic link.

Refs


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions