Two bleed-throughs let a removed file land in `work_products` and
plant a ghost row:
- `listChangedRelPaths` pushed every non-`!!` git porcelain entry,
including worktree-deleted (`Y = D`) and staged-deleted-with-
synced-worktree (`XD` + ` `) rows, so the projector tried to
upsert a path that was no longer on disk.
- `upsertFilesystemArtifact` never stat'd the absolute path; a
deleted file (from either source detector) still reached
`createWorkProduct` and left the DocumentCenter "open" link
pointing to nothing.
Filter the two deletion forms at the git list step and add an
`existsSync + isFile` gate in `upsertFilesystemArtifact`. The check
also catches edge cases the baseline diff surfaces — a file touched
and then `rm`'d, a regular file replaced by a symlink, a path that
raced with a `cleanup` shell script — so neither change detector can
register a row that would not open.