From b3cbeca1bf7245ebcd1f5b793217936eca56e00e Mon Sep 17 00:00:00 2001 From: cproudlock Date: Mon, 31 Aug 2026 07:14:12 -0400 Subject: [PATCH] Keep local scratch notes out of the publication tree The export rsyncs the WORKING TREE, so .gitignore does not apply to it: anything ignored-but-present reaches the publication repo unless it is named as an exclude. devnotes/ is declared never-committed and holds review writeups and chat handoffs, and it went straight through. The scrub gate stopped it, which is what that gate is for, and nothing was committed or bundled. But a gate failure is a stop, not a filter, and the fix a hurried person reaches for is deleting their notes to get a bundle out. Same shape as the stray .env.bak that reached this tree once before, so the rsync now carries a note saying why excludes live there rather than in .gitignore. Scope: product (cherry picked from commit f1136d920d90d3a538c610c221003deb8a085c01) --- tools/export-github.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/export-github.sh b/tools/export-github.sh index baf9c824..6cbf194d 100755 --- a/tools/export-github.sh +++ b/tools/export-github.sh @@ -121,6 +121,12 @@ done fi ) +# NOTE ON EXCLUDES: this walks the WORKING TREE, so .gitignore does not apply. +# Anything ignored-but-present has to be named here or it reaches publication - +# how a stray .env.bak once did, and how devnotes/ (local review writeups, chat +# handoffs) did. The scrub gate catches such things, which is the point, but a +# gate failure is a stop, not a filter: add the exclude rather than deleting +# your notes to get a bundle out. rsync -a --delete \ --exclude '.git' \ --exclude '.gitea' \ @@ -129,6 +135,7 @@ rsync -a --delete \ --exclude '/docs/*' \ --exclude '/tools' \ --exclude '/mcp' \ + --exclude '/devnotes' \ --exclude 'start-api.sh' \ --exclude 'start-ui.sh' \ --exclude 'CLAUDE.md' \