This repository has no description

let git overrule an exclusion list that matches on names alone master

`build` in push-project.sh's EXCLUDES means "output some command regenerates", but a repository is free to track a source file under that name, and one does: apps/publisher/build/docs.ts never reached the server. The damage is not the missing file, it is that pushing again cannot repair it — the exclusion that caused the deletion also blocks the file that would fix it, so the checkout reads as dirty from then on and every later push stops to ask about overwriting changes nobody made. git_protect_list() names every tracked file, and every ancestor directory of one, ahead of the general patterns. Ancestors are not optional: rsync prunes an excluded directory during the walk and never descends into it, so protecting the file without protecting its parent protects nothing. Three filter tiers, first match winning: a project's own .flit-push-exclude, then git's tracked files, then the general list. Explicit intent beats git, and git beats a guess about a name — a project's file outranks the protection on purpose, since a repository may track a data set the server has its own copy of. That tier can still strand a tracked file, so after the transfer the run asks the server for `git ls-files --deleted` and reports what is missing, rather than leaving the next push to discover it. Twelve cases pin this, and they assert rsync's filter semantics directly because /usr/bin/rsync is openrsync on the laptop and GNU rsync on the server; an --include-from the two read differently would restore the defect in silence. 93 passed on both. Standing rule 17.