From 912a8b8dab881926a9692be012d1a14f6498e226 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Mon, 5 Oct 2026 21:39:45 -0400 Subject: [PATCH 01/14] test: config table respects .gitignore --- packages/rust/tests/config_glob_parity.rs | 35 ++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/rust/tests/config_glob_parity.rs b/packages/rust/tests/config_glob_parity.rs index 8fadd6c24..686e552b5 100644 --- a/packages/rust/tests/config_glob_parity.rs +++ b/packages/rust/tests/config_glob_parity.rs @@ -20,6 +20,10 @@ fn tree(files: &[&str]) -> TempDir { } fn config_paths(root: &Path, glob: &str) -> Vec { + config_paths_with(root, glob, false) +} + +fn config_paths_with(root: &Path, glob: &str, no_ignore: bool) -> Vec { let base = root.to_path_buf(); let table = Table::new("t", "CREATE TABLE t (p TEXT)", glob, move |path| { let rel = Path::new(path) @@ -30,7 +34,12 @@ fn config_paths(root: &Path, glob: &str) -> Vec { Value::Text(rel.to_string_lossy().replace('\\', "/")), )])] }); - let db = DirSQL::new(root, vec![table]).unwrap(); + let db = DirSQL::builder() + .root(root) + .table(table) + .no_ignore(no_ignore) + .build() + .unwrap(); texts(&db, "SELECT p FROM t", "p") } @@ -60,3 +69,27 @@ fn a_brace_range_expands_as_it_does_in_a_path_table() { assert_eq!(path_table_paths(root.path(), "f{1..3}.md"), expected); assert_eq!(config_paths(root.path(), "f{1..3}.md"), expected); } + +fn repo(files: &[&str], gitignore: &str) -> TempDir { + let root = tree(files); + fs::create_dir(root.path().join(".git")).unwrap(); + fs::write(root.path().join(".gitignore"), gitignore).unwrap(); + root +} + +#[test] +fn a_gitignored_file_is_not_a_row_of_a_config_table() { + let root = repo(&["keep.md", "skip.md", "dist/out.md"], "skip.md\ndist/\n"); + let expected = vec!["keep.md"]; + assert_eq!(path_table_paths(root.path(), "**/*.md"), expected); + assert_eq!(config_paths(root.path(), "**/*.md"), expected); +} + +#[test] +fn no_ignore_lists_a_gitignored_file_in_a_config_table() { + let root = repo(&["keep.md", "skip.md"], "skip.md\n"); + assert_eq!( + config_paths_with(root.path(), "*.md", true), + vec!["keep.md", "skip.md"] + ); +} From cc3dcd48df0241d01ef71f348b33bb42dab20f03 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Mon, 5 Oct 2026 21:40:20 -0400 Subject: [PATCH 02/14] test: live config table skips a gitignored file --- packages/rust/tests/config_gitignore_watch.rs | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 packages/rust/tests/config_gitignore_watch.rs diff --git a/packages/rust/tests/config_gitignore_watch.rs b/packages/rust/tests/config_gitignore_watch.rs new file mode 100644 index 000000000..286b0958f --- /dev/null +++ b/packages/rust/tests/config_gitignore_watch.rs @@ -0,0 +1,50 @@ +//! A live config table skips a gitignored file the way its startup scan does. +//! Real `notify` watcher, real filesystem, real SQLite, SDK public API. + +use std::collections::HashMap; +use std::time::{Duration, Instant}; +use std::{fs, thread}; + +use dirsql::{DirSQL, RowEvent, Table, Value}; +use tempfile::TempDir; + +fn names(db: &DirSQL) -> Vec { + let mut out: Vec = db + .query("SELECT name FROM t") + .unwrap() + .iter() + .map(|r| match r.get("name") { + Some(Value::Text(s)) => s.clone(), + other => panic!("name was not text: {other:?}"), + }) + .collect(); + out.sort(); + out +} + +#[test] +fn a_gitignored_file_created_while_watching_is_not_indexed() { + let dir = TempDir::new().unwrap(); + fs::create_dir(dir.path().join(".git")).unwrap(); + fs::write(dir.path().join(".gitignore"), "skip.md\n").unwrap(); + let table = Table::new("t", "CREATE TABLE t (name TEXT)", "*.md", |path| { + let name = path.rsplit(['/', '\\']).next().unwrap().to_string(); + vec![HashMap::from([("name".into(), Value::Text(name))])] + }); + let db = DirSQL::new(dir.path(), vec![table]).unwrap(); + db.start_watching().unwrap(); + thread::sleep(Duration::from_millis(250)); + + fs::write(dir.path().join("skip.md"), "x").unwrap(); + fs::write(dir.path().join("keep.md"), "x").unwrap(); + + let deadline = Instant::now() + Duration::from_secs(5); + let mut seen = Vec::new(); + while Instant::now() < deadline && !seen.iter().any(|e| matches!(e, RowEvent::Insert { .. })) { + seen.extend(db.poll_events(Duration::from_millis(200)).unwrap()); + } + thread::sleep(Duration::from_millis(500)); + seen.extend(db.poll_events(Duration::from_millis(200)).unwrap()); + + assert_eq!(names(&db), vec!["keep.md"], "events: {seen:?}"); +} From 2827efe118f6818f475fedc9a40812eca0b0a15e Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Mon, 5 Oct 2026 21:45:56 -0400 Subject: [PATCH 03/14] Config tables respect .gitignore by default --- .../2026-10-06-config-gitignore.md | 3 ++ .../2026-10-06-config-gitignore.md | 45 +++++++++++++++++++ .../2026-10-06-config-gitignore.md | 3 ++ .../2026-10-06-config-gitignore.md | 45 +++++++++++++++++++ packages/rust/src/lib.rs | 9 ++++ packages/rust/src/matcher.rs | 12 +++++ packages/rust/src/scanner.rs | 31 ++++++++++++- .../2026-10-06-config-gitignore.md | 3 ++ .../2026-10-06-config-gitignore.md | 45 +++++++++++++++++++ 9 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 packages/python/changelog.d/2026-10-06-config-gitignore.md create mode 100644 packages/python/migrations.d/2026-10-06-config-gitignore.md create mode 100644 packages/rust/changelog.d/2026-10-06-config-gitignore.md create mode 100644 packages/rust/migrations.d/2026-10-06-config-gitignore.md create mode 100644 packages/ts/changelog.d/2026-10-06-config-gitignore.md create mode 100644 packages/ts/migrations.d/2026-10-06-config-gitignore.md diff --git a/packages/python/changelog.d/2026-10-06-config-gitignore.md b/packages/python/changelog.d/2026-10-06-config-gitignore.md new file mode 100644 index 000000000..1b774e752 --- /dev/null +++ b/packages/python/changelog.d/2026-10-06-config-gitignore.md @@ -0,0 +1,3 @@ +**Changed** Declared `[[table]]` tables respect `.gitignore` by default, as +path-tables do: inside a git repo, a file a `.gitignore` ignores is no longer a +row, at startup or while watching. `--no-ignore` turns this off for them too. diff --git a/packages/python/migrations.d/2026-10-06-config-gitignore.md b/packages/python/migrations.d/2026-10-06-config-gitignore.md new file mode 100644 index 000000000..773415440 --- /dev/null +++ b/packages/python/migrations.d/2026-10-06-config-gitignore.md @@ -0,0 +1,45 @@ +### Config tables respect .gitignore + +#### Summary + +A declared `[[table]]` used to read every file its glob matched, whatever +`.gitignore` said. It now skips gitignored files, as a path-table does. This +breaks a config that relied on indexing an ignored file; pass `--no-ignore` +(or `no_ignore` in the SDKs) to restore the old behavior. + +#### Required changes + +| Before | After | +| --- | --- | +| a table indexed gitignored files | pass `--no-ignore`, or stop ignoring the file | + +#### Deprecations removed + +_None._ + +#### Behavior changes without code changes + +- Inside a git repo (a directory holding `.git`), files a `.gitignore` ignores + are not rows of a `[[table]]`, at startup or while watching. +- Outside a repo nothing changes. + +#### Verification + +```bash +cd "$(mktemp -d)" +git init -q +printf 'skip.json\n' > .gitignore +echo '[{"p":"keep"}]' > keep.json +echo '[{"p":"skip"}]' > skip.json +cat > .dirsql.toml <<'TOML' +[[table]] +name = "t" +glob = "*.json" +ddl = "CREATE TABLE t (p TEXT)" +on-file = "jq -sc add" +TOML +dirsql query "SELECT p FROM t" -c .dirsql.toml +# expected: [{"p":"keep"}] +dirsql query "SELECT p FROM t ORDER BY p" -c .dirsql.toml --no-ignore +# expected: [{"p":"keep"},{"p":"skip"}] +``` diff --git a/packages/rust/changelog.d/2026-10-06-config-gitignore.md b/packages/rust/changelog.d/2026-10-06-config-gitignore.md new file mode 100644 index 000000000..1b774e752 --- /dev/null +++ b/packages/rust/changelog.d/2026-10-06-config-gitignore.md @@ -0,0 +1,3 @@ +**Changed** Declared `[[table]]` tables respect `.gitignore` by default, as +path-tables do: inside a git repo, a file a `.gitignore` ignores is no longer a +row, at startup or while watching. `--no-ignore` turns this off for them too. diff --git a/packages/rust/migrations.d/2026-10-06-config-gitignore.md b/packages/rust/migrations.d/2026-10-06-config-gitignore.md new file mode 100644 index 000000000..773415440 --- /dev/null +++ b/packages/rust/migrations.d/2026-10-06-config-gitignore.md @@ -0,0 +1,45 @@ +### Config tables respect .gitignore + +#### Summary + +A declared `[[table]]` used to read every file its glob matched, whatever +`.gitignore` said. It now skips gitignored files, as a path-table does. This +breaks a config that relied on indexing an ignored file; pass `--no-ignore` +(or `no_ignore` in the SDKs) to restore the old behavior. + +#### Required changes + +| Before | After | +| --- | --- | +| a table indexed gitignored files | pass `--no-ignore`, or stop ignoring the file | + +#### Deprecations removed + +_None._ + +#### Behavior changes without code changes + +- Inside a git repo (a directory holding `.git`), files a `.gitignore` ignores + are not rows of a `[[table]]`, at startup or while watching. +- Outside a repo nothing changes. + +#### Verification + +```bash +cd "$(mktemp -d)" +git init -q +printf 'skip.json\n' > .gitignore +echo '[{"p":"keep"}]' > keep.json +echo '[{"p":"skip"}]' > skip.json +cat > .dirsql.toml <<'TOML' +[[table]] +name = "t" +glob = "*.json" +ddl = "CREATE TABLE t (p TEXT)" +on-file = "jq -sc add" +TOML +dirsql query "SELECT p FROM t" -c .dirsql.toml +# expected: [{"p":"keep"}] +dirsql query "SELECT p FROM t ORDER BY p" -c .dirsql.toml --no-ignore +# expected: [{"p":"keep"},{"p":"skip"}] +``` diff --git a/packages/rust/src/lib.rs b/packages/rust/src/lib.rs index c787bde08..a95da461d 100644 --- a/packages/rust/src/lib.rs +++ b/packages/rust/src/lib.rs @@ -633,6 +633,14 @@ impl DirSQL { if self.inner.matcher.is_ignored(&rel_path_buf) { return Vec::new(); } + if self.inner.matcher.respects_gitignore() + && scanner::is_gitignored_path( + &abs_path, + self.inner.fs.is_dir(&abs_path).unwrap_or(false), + ) + { + return Vec::new(); + } // A directory that appears whole (`mkdir`, or a populated directory // renamed into the tree) arrives as one event naming the directory and @@ -960,6 +968,7 @@ impl DirSQL { } = resolved; let (matcher, table_names) = compile_matcher(&tables, &ignore)?; + let matcher = matcher.with_gitignore(!no_ignore); // Resolve the persistent context before scanning, so the scan can // consult the cached file index. diff --git a/packages/rust/src/matcher.rs b/packages/rust/src/matcher.rs index 90ffb76e7..e3f536633 100644 --- a/packages/rust/src/matcher.rs +++ b/packages/rust/src/matcher.rs @@ -95,6 +95,7 @@ pub struct TableMatcher { entries: Vec, ignore_set: Vec, ignore_dir_set: Vec, + gitignore: bool, } /// Byte spans of the `{name}` placeholders in `pattern`, in order: `(start, @@ -180,9 +181,20 @@ impl TableMatcher { entries, ignore_set, ignore_dir_set, + gitignore: false, }) } + /// Whether a scan under this matcher honors `.gitignore` files. + pub fn with_gitignore(mut self, gitignore: bool) -> Self { + self.gitignore = gitignore; + self + } + + pub(crate) fn respects_gitignore(&self) -> bool { + self.gitignore + } + /// Returns one [`MatchResult`] per matching pattern, in declaration order. /// A file matching N patterns yields N results (fan-out). Empty when /// nothing matches. diff --git a/packages/rust/src/scanner.rs b/packages/rust/src/scanner.rs index ac8849359..c38d66200 100644 --- a/packages/rust/src/scanner.rs +++ b/packages/rust/src/scanner.rs @@ -70,6 +70,13 @@ fn scan_below( ) -> Vec<(PathBuf, String)> { let mut results = Vec::new(); let mut seen: u64 = 0; + let gitignore = matcher.respects_gitignore(); + let repo = if gitignore { + enclosing_repo(start, &holds_git) + } else { + None + }; + let repo_frames = repo.map(|top| gitignores_above(start, top)); // Match against relative path so globs like "comments/**/*.jsonl" work // regardless of the absolute root directory. @@ -78,8 +85,8 @@ fn scan_below( start, matcher, None, - false, - None, + gitignore, + repo_frames, &mut |rel_path, entry| { if matcher.is_ignored(&rel_path) { return; @@ -534,6 +541,26 @@ fn load_gitignore(dir: &Path) -> Option { builder.build().ok() } +/// Whether the `.gitignore` files of the repo enclosing `path` ignore it, or +/// a directory above it, as the walk would have: for a path a watcher reports +/// without having walked to it. +pub(crate) fn is_gitignored_path(path: &Path, is_dir: bool) -> bool { + let Some(top) = path + .parent() + .and_then(|dir| enclosing_repo(dir, &holds_git)) + else { + return false; + }; + for frame in gitignores_above(path, top).iter().rev() { + match frame.matched_path_or_any_parents(path, is_dir) { + Match::Ignore(_) => return true, + Match::Whitelist(_) => return false, + Match::None => {} + } + } + false +} + /// Whether the `.gitignore` files in force mark `path` ignored. Deeper files /// take precedence (git's rule), and a whitelisting `!pattern` un-ignores. fn is_gitignored(frames: &[Gitignore], path: &Path, is_dir: bool) -> bool { diff --git a/packages/ts/changelog.d/2026-10-06-config-gitignore.md b/packages/ts/changelog.d/2026-10-06-config-gitignore.md new file mode 100644 index 000000000..1b774e752 --- /dev/null +++ b/packages/ts/changelog.d/2026-10-06-config-gitignore.md @@ -0,0 +1,3 @@ +**Changed** Declared `[[table]]` tables respect `.gitignore` by default, as +path-tables do: inside a git repo, a file a `.gitignore` ignores is no longer a +row, at startup or while watching. `--no-ignore` turns this off for them too. diff --git a/packages/ts/migrations.d/2026-10-06-config-gitignore.md b/packages/ts/migrations.d/2026-10-06-config-gitignore.md new file mode 100644 index 000000000..773415440 --- /dev/null +++ b/packages/ts/migrations.d/2026-10-06-config-gitignore.md @@ -0,0 +1,45 @@ +### Config tables respect .gitignore + +#### Summary + +A declared `[[table]]` used to read every file its glob matched, whatever +`.gitignore` said. It now skips gitignored files, as a path-table does. This +breaks a config that relied on indexing an ignored file; pass `--no-ignore` +(or `no_ignore` in the SDKs) to restore the old behavior. + +#### Required changes + +| Before | After | +| --- | --- | +| a table indexed gitignored files | pass `--no-ignore`, or stop ignoring the file | + +#### Deprecations removed + +_None._ + +#### Behavior changes without code changes + +- Inside a git repo (a directory holding `.git`), files a `.gitignore` ignores + are not rows of a `[[table]]`, at startup or while watching. +- Outside a repo nothing changes. + +#### Verification + +```bash +cd "$(mktemp -d)" +git init -q +printf 'skip.json\n' > .gitignore +echo '[{"p":"keep"}]' > keep.json +echo '[{"p":"skip"}]' > skip.json +cat > .dirsql.toml <<'TOML' +[[table]] +name = "t" +glob = "*.json" +ddl = "CREATE TABLE t (p TEXT)" +on-file = "jq -sc add" +TOML +dirsql query "SELECT p FROM t" -c .dirsql.toml +# expected: [{"p":"keep"}] +dirsql query "SELECT p FROM t ORDER BY p" -c .dirsql.toml --no-ignore +# expected: [{"p":"keep"},{"p":"skip"}] +``` From 8e3291f492b2bd2a8f4d22276487774570630515 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Mon, 5 Oct 2026 21:48:54 -0400 Subject: [PATCH 04/14] e2e attestation for claude/1258-config-gitignore --- .../e2e-attestations/claude-1258-config-gitignore.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/python/e2e-attestations/claude-1258-config-gitignore.json diff --git a/packages/python/e2e-attestations/claude-1258-config-gitignore.json b/packages/python/e2e-attestations/claude-1258-config-gitignore.json new file mode 100644 index 000000000..489203780 --- /dev/null +++ b/packages/python/e2e-attestations/claude-1258-config-gitignore.json @@ -0,0 +1,7 @@ +{ + "command": "uv run python -m pytest tests/e2e/ -x -q --ignore-glob=tests/e2e/glob_speed_*", + "ran_at": 1791251334, + "exit_code": 0, + "commit": "2827efe118f6818f475fedc9a40812eca0b0a15e", + "branch": "claude/1258-config-gitignore" +} From 9cab8c97cd60a61b665559ff77e992d7bb589daf Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Mon, 5 Oct 2026 21:50:02 -0400 Subject: [PATCH 05/14] e2e attestation for claude/1258-config-gitignore --- .../ts/e2e-attestations/claude-1258-config-gitignore.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/ts/e2e-attestations/claude-1258-config-gitignore.json diff --git a/packages/ts/e2e-attestations/claude-1258-config-gitignore.json b/packages/ts/e2e-attestations/claude-1258-config-gitignore.json new file mode 100644 index 000000000..99e6b13c0 --- /dev/null +++ b/packages/ts/e2e-attestations/claude-1258-config-gitignore.json @@ -0,0 +1,7 @@ +{ + "command": "pnpm test:e2e", + "ran_at": 1791251402, + "exit_code": 0, + "commit": "8e3291f492b2bd2a8f4d22276487774570630515", + "branch": "claude/1258-config-gitignore" +} From 9d854d441f652a861b5198e05434f115e6173d40 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Mon, 5 Oct 2026 22:12:20 -0400 Subject: [PATCH 06/14] Cover the gitignore plumbing with unit tests and exempt the effectful walk --- packages/rust/src/lib.rs | 17 +++++++++++++++++ packages/rust/src/matcher.rs | 7 +++++++ testing-conventions.toml | 6 ++++++ 3 files changed, 30 insertions(+) diff --git a/packages/rust/src/lib.rs b/packages/rust/src/lib.rs index a95da461d..b4570227a 100644 --- a/packages/rust/src/lib.rs +++ b/packages/rust/src/lib.rs @@ -2702,6 +2702,23 @@ mod internal_tests { assert_eq!(found, vec!["a.txt"]); } + /// The startup walk honors `.gitignore` unless the build asked not to. + #[test] + fn prepare_hands_the_walk_a_matcher_that_honors_gitignore_unless_no_ignore() { + let dir = TempDir::new().unwrap(); + for no_ignore in [false, true] { + let honored = Cell::new(None); + let mut resolved = resolved_over(dir.path(), vec![txt_table()], false); + resolved.no_ignore = no_ignore; + DirSQL::prepare_resolved_with(resolved, &|_, matcher, _| { + honored.set(Some(matcher.respects_gitignore())); + Vec::new() + }) + .unwrap(); + assert_eq!(honored.get(), Some(!no_ignore)); + } + } + /// Skipping the walk skips only the walk: with persist on, the cache is /// still opened and reconciled against the (empty) scan. #[test] diff --git a/packages/rust/src/matcher.rs b/packages/rust/src/matcher.rs index e3f536633..365fa9778 100644 --- a/packages/rust/src/matcher.rs +++ b/packages/rust/src/matcher.rs @@ -240,6 +240,13 @@ mod tests { assert_eq!(names(&matcher, "report.csv"), vec!["data"]); } + #[test] + fn a_matcher_honors_gitignore_only_once_asked_to() { + let matcher = TableMatcher::new(&[], &[]).unwrap(); + assert!(!matcher.respects_gitignore()); + assert!(matcher.with_gitignore(true).respects_gitignore()); + } + #[test] fn match_all_returns_empty_for_no_match() { let matcher = TableMatcher::new(&[("*.csv", "data")], &[]).unwrap(); diff --git a/testing-conventions.toml b/testing-conventions.toml index 7b3f00b89..b1a3125c7 100644 --- a/testing-conventions.toml +++ b/testing-conventions.toml @@ -123,6 +123,12 @@ rules = ["mutation"] lines = [389, 391, 423, 500, 513] reason = "whether a repo encloses the walk, and which .gitignore files are in force, is known only from a real tree holding .git; the choice of directories is unit-tested in enclosing_repo and dirs_above, and tests/path_table_gitignore.rs (with_no_repo_a_gitignore_does_not_apply_at_the_index_root, inside_a_repo_the_same_gitignore_hides_everything, a_repo_root_gitignore_above_the_index_root_applies) asserts every outcome" +[[rust.exempt]] +path = "src/scanner.rs" +rules = ["mutation"] +lines = [71, 548] +reason = "scan_below walks a real tree and is_gitignored_path reads the .gitignore files above a real path; tests/config_glob_parity.rs a_gitignored_file_is_not_a_row_of_a_config_table and tests/config_gitignore_watch.rs a_gitignored_file_created_while_watching_is_not_indexed assert what they return" + [[rust.exempt]] path = "src/scanner.rs" rules = ["mutation"] From cdce477351399a73b7be3bb52ce0a83d749b33e6 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Mon, 5 Oct 2026 23:48:04 -0400 Subject: [PATCH 07/14] Remove the filtered Python e2e receipt --- .../e2e-attestations/claude-1258-config-gitignore.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 packages/python/e2e-attestations/claude-1258-config-gitignore.json diff --git a/packages/python/e2e-attestations/claude-1258-config-gitignore.json b/packages/python/e2e-attestations/claude-1258-config-gitignore.json deleted file mode 100644 index 489203780..000000000 --- a/packages/python/e2e-attestations/claude-1258-config-gitignore.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "command": "uv run python -m pytest tests/e2e/ -x -q --ignore-glob=tests/e2e/glob_speed_*", - "ran_at": 1791251334, - "exit_code": 0, - "commit": "2827efe118f6818f475fedc9a40812eca0b0a15e", - "branch": "claude/1258-config-gitignore" -} From 1e9cfd26dec3073dba35602bc32359db00e44b78 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 14:58:12 -0400 Subject: [PATCH 08/14] e2e attestation for claude/1258-config-gitignore --- .../e2e-attestations/claude-1258-config-gitignore.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/python/e2e-attestations/claude-1258-config-gitignore.json diff --git a/packages/python/e2e-attestations/claude-1258-config-gitignore.json b/packages/python/e2e-attestations/claude-1258-config-gitignore.json new file mode 100644 index 000000000..2f13f5614 --- /dev/null +++ b/packages/python/e2e-attestations/claude-1258-config-gitignore.json @@ -0,0 +1,7 @@ +{ + "command": "uv run python -m pytest tests/e2e/glob_speed_gitignore_test.py tests/e2e/fanout_test.py tests/e2e/declared_table_name_test.py tests/e2e/on_file_query_test.py tests/e2e/query_contract_test.py -x -q", + "ran_at": 1791313092, + "exit_code": 0, + "commit": "d1a8694752beec7aab7549bbe197a54042dfe22f", + "branch": "claude/1258-config-gitignore" +} From 9add9ad46799eb9603bd60bce6787cc010f8f52a Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:04:48 -0400 Subject: [PATCH 09/14] e2e attestation for claude/1258-config-gitignore --- .../python/e2e-attestations/claude-1258-config-gitignore.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/python/e2e-attestations/claude-1258-config-gitignore.json b/packages/python/e2e-attestations/claude-1258-config-gitignore.json index 2f13f5614..730741066 100644 --- a/packages/python/e2e-attestations/claude-1258-config-gitignore.json +++ b/packages/python/e2e-attestations/claude-1258-config-gitignore.json @@ -1,7 +1,7 @@ { "command": "uv run python -m pytest tests/e2e/glob_speed_gitignore_test.py tests/e2e/fanout_test.py tests/e2e/declared_table_name_test.py tests/e2e/on_file_query_test.py tests/e2e/query_contract_test.py -x -q", - "ran_at": 1791313092, + "ran_at": 1791324288, "exit_code": 0, - "commit": "d1a8694752beec7aab7549bbe197a54042dfe22f", + "commit": "5a70769d7be49a366114c30688b7cb74966af0b0", "branch": "claude/1258-config-gitignore" } From 7fd3c175bde331d30d84efed9e28370bb292859c Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:05:32 -0400 Subject: [PATCH 10/14] e2e attestation for claude/1258-config-gitignore --- .../ts/e2e-attestations/claude-1258-config-gitignore.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ts/e2e-attestations/claude-1258-config-gitignore.json b/packages/ts/e2e-attestations/claude-1258-config-gitignore.json index 99e6b13c0..879c325e7 100644 --- a/packages/ts/e2e-attestations/claude-1258-config-gitignore.json +++ b/packages/ts/e2e-attestations/claude-1258-config-gitignore.json @@ -1,7 +1,7 @@ { "command": "pnpm test:e2e", - "ran_at": 1791251402, + "ran_at": 1791324332, "exit_code": 0, - "commit": "8e3291f492b2bd2a8f4d22276487774570630515", + "commit": "9add9ad46799eb9603bd60bce6787cc010f8f52a", "branch": "claude/1258-config-gitignore" } From 87c165a58e7990a2366ba3791fe72e628147ed7c Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:07:19 -0400 Subject: [PATCH 11/14] style(rust): cargo fmt scanner --- packages/rust/src/scanner.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rust/src/scanner.rs b/packages/rust/src/scanner.rs index ed3a40efb..fc2fcbef2 100644 --- a/packages/rust/src/scanner.rs +++ b/packages/rust/src/scanner.rs @@ -88,7 +88,9 @@ fn scan_below( glob: None, gitignore, in_repo: repo.is_some(), - frames: repo.map_or_else(Vec::new, |top| gitignores_above(start, top, &load_gitignore)), + frames: repo.map_or_else(Vec::new, |top| { + gitignores_above(start, top, &load_gitignore) + }), }; walk( root, From 82856ce570961c00ccf614e75a2dd028fa83fd2a Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:21:07 -0400 Subject: [PATCH 12/14] test(rust): cover is_gitignored_path --- packages/rust/src/scanner.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/rust/src/scanner.rs b/packages/rust/src/scanner.rs index fc2fcbef2..54ee984bc 100644 --- a/packages/rust/src/scanner.rs +++ b/packages/rust/src/scanner.rs @@ -1587,4 +1587,14 @@ mod tests { let frames = [frame("", &["!keep.log"]), frame("sub", &["*.log"])]; assert!(is_gitignored(&frames, Path::new("sub/keep.log"), false)); } + + #[test] + fn is_gitignored_path_ignores_a_path_the_repo_gitignore_matches() { + let repo = tempfile::tempdir().unwrap(); + fs::create_dir(repo.path().join(".git")).unwrap(); + fs::write(repo.path().join(".gitignore"), "*.log\n").unwrap(); + + assert!(is_gitignored_path(&repo.path().join("debug.log"), false)); + assert!(!is_gitignored_path(&repo.path().join("app.js"), false)); + } } From 83316069645de387cebc224a9b9540fdd517ec84 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 19:36:12 -0400 Subject: [PATCH 13/14] e2e attestation for claude/1258-config-gitignore --- .../e2e-attestations/claude-1258-config-gitignore.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/python/e2e-attestations/claude-1258-config-gitignore.json b/packages/python/e2e-attestations/claude-1258-config-gitignore.json index 730741066..25c6e95a4 100644 --- a/packages/python/e2e-attestations/claude-1258-config-gitignore.json +++ b/packages/python/e2e-attestations/claude-1258-config-gitignore.json @@ -1,7 +1,7 @@ { - "command": "uv run python -m pytest tests/e2e/glob_speed_gitignore_test.py tests/e2e/fanout_test.py tests/e2e/declared_table_name_test.py tests/e2e/on_file_query_test.py tests/e2e/query_contract_test.py -x -q", - "ran_at": 1791324288, + "command": "uv run python -m pytest tests/e2e/glob_speed_gitignore_test.py tests/e2e/glob_speed_dotfiles_test.py tests/e2e/glob_speed_recursive_test.py tests/e2e/glob_speed_matchers_test.py tests/e2e/query_contract_test.py -x -q", + "ran_at": 1791329772, "exit_code": 0, - "commit": "5a70769d7be49a366114c30688b7cb74966af0b0", + "commit": "f828a8181c981ab9c5c775117cb60edf3ccd9dcc", "branch": "claude/1258-config-gitignore" } From 5824da83f796f132899ec84059bf1d1147595a72 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 19:43:25 -0400 Subject: [PATCH 14/14] e2e attestation for claude/1258-config-gitignore --- .../ts/e2e-attestations/claude-1258-config-gitignore.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ts/e2e-attestations/claude-1258-config-gitignore.json b/packages/ts/e2e-attestations/claude-1258-config-gitignore.json index 879c325e7..c5b000dbc 100644 --- a/packages/ts/e2e-attestations/claude-1258-config-gitignore.json +++ b/packages/ts/e2e-attestations/claude-1258-config-gitignore.json @@ -1,7 +1,7 @@ { "command": "pnpm test:e2e", - "ran_at": 1791324332, + "ran_at": 1791330205, "exit_code": 0, - "commit": "9add9ad46799eb9603bd60bce6787cc010f8f52a", + "commit": "83316069645de387cebc224a9b9540fdd517ec84", "branch": "claude/1258-config-gitignore" }