From 1fae969e51512bf52d329c60c2e2a1375719246f Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Mon, 5 Oct 2026 23:49:36 -0400 Subject: [PATCH 1/8] Test that config globs skip node_modules and follow symlinks --- packages/rust/tests/config_glob_parity.rs | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/rust/tests/config_glob_parity.rs b/packages/rust/tests/config_glob_parity.rs index ba0a66837..b063eff73 100644 --- a/packages/rust/tests/config_glob_parity.rs +++ b/packages/rust/tests/config_glob_parity.rs @@ -147,3 +147,35 @@ fn a_spelled_dot_directory_is_listed() { assert_eq!(path_table_paths(root.path(), ".hid/*.md"), expected); assert_eq!(config_paths(root.path(), ".hid/*.md"), expected); } + +#[test] +fn node_modules_is_skipped_unless_the_glob_names_it() { + let root = tree(&["top.js", "node_modules/top.js", "pkg/node_modules/dep/i.js"]); + let expected = vec!["top.js"]; + assert_eq!(path_table_paths(root.path(), "**/*.js"), expected); + assert_eq!(config_paths(root.path(), "**/*.js"), expected); +} + +#[test] +fn a_glob_naming_node_modules_lists_it() { + let root = tree(&["top.js", "node_modules/top.js"]); + let expected = vec!["node_modules/top.js"]; + assert_eq!(path_table_paths(root.path(), "node_modules/*.js"), expected); + assert_eq!(config_paths(root.path(), "node_modules/*.js"), expected); +} + +#[cfg(unix)] +#[test] +fn a_symlinked_file_and_directory_are_followed() { + use std::os::unix::fs::symlink; + let root = tree(&["top.md", "real/r.md"]); + symlink("top.md", root.path().join("link.md")).unwrap(); + symlink("real", root.path().join("linkdir")).unwrap(); + for (glob, expected) in [ + ("link.md", vec!["link.md"]), + ("linkdir/*", vec!["linkdir/r.md"]), + ] { + assert_eq!(path_table_paths(root.path(), glob), expected, "{glob}"); + assert_eq!(config_paths(root.path(), glob), expected, "{glob}"); + } +} From 580787babfd5db4ef749c3dd453efa649f39484c Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 00:20:18 -0400 Subject: [PATCH 2/8] Skip node_modules and follow symlinks in config globs --- .../changelog.d/2026-10-06-config-links.md | 3 + .../migrations.d/2026-10-06-config-links.md | 43 +++++++++++++ .../changelog.d/2026-10-06-config-links.md | 3 + .../migrations.d/2026-10-06-config-links.md | 43 +++++++++++++ packages/rust/src/matcher.rs | 62 ++++++++++++++++--- packages/rust/src/scanner.rs | 43 +++++-------- .../ts/changelog.d/2026-10-06-config-links.md | 3 + .../migrations.d/2026-10-06-config-links.md | 43 +++++++++++++ 8 files changed, 207 insertions(+), 36 deletions(-) create mode 100644 packages/python/changelog.d/2026-10-06-config-links.md create mode 100644 packages/python/migrations.d/2026-10-06-config-links.md create mode 100644 packages/rust/changelog.d/2026-10-06-config-links.md create mode 100644 packages/rust/migrations.d/2026-10-06-config-links.md create mode 100644 packages/ts/changelog.d/2026-10-06-config-links.md create mode 100644 packages/ts/migrations.d/2026-10-06-config-links.md diff --git a/packages/python/changelog.d/2026-10-06-config-links.md b/packages/python/changelog.d/2026-10-06-config-links.md new file mode 100644 index 000000000..f7b499d1c --- /dev/null +++ b/packages/python/changelog.d/2026-10-06-config-links.md @@ -0,0 +1,3 @@ +**Changed** A declared `[[table]] glob` skips `node_modules` unless the glob +names it, and follows symlinks, as a path-table does. `**/*.js` no longer lists +`node_modules/...`; `link.md -> top.md` and `linkdir/*` now list their rows. diff --git a/packages/python/migrations.d/2026-10-06-config-links.md b/packages/python/migrations.d/2026-10-06-config-links.md new file mode 100644 index 000000000..1a00dc32f --- /dev/null +++ b/packages/python/migrations.d/2026-10-06-config-links.md @@ -0,0 +1,43 @@ +### Config globs skip node_modules unless named, and follow symlinks + +#### Summary + +`glob = "**/*.js"` used to list files under any `node_modules`; it now does +not, unless a component of the glob is `node_modules`. Symlinked files and +directories, which a config glob used to ignore, are now followed as in a +path-table and in bash. + +#### Required changes + +| Before | After | +| --- | --- | +| `glob = "**/*.js"` (included `node_modules/`) | `glob = "node_modules/**/*.js"` to list it | + +#### Deprecations removed + +_None._ + +#### Behavior changes without code changes + +- A glob with no `node_modules` component never matches under one. +- A symlinked file or directory the glob reaches now yields rows. + +#### Verification + +```bash +cd "$(mktemp -d)" +mkdir real node_modules +echo '[{"p":"r"}]' > real/r.json +echo '[{"p":"n"}]' > node_modules/n.json +ln -s real linkdir +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: no row from node_modules; rows for real/ (symlinked linkdir/ is +# reached by `linkdir/*.json`, not by `**`) +``` diff --git a/packages/rust/changelog.d/2026-10-06-config-links.md b/packages/rust/changelog.d/2026-10-06-config-links.md new file mode 100644 index 000000000..f7b499d1c --- /dev/null +++ b/packages/rust/changelog.d/2026-10-06-config-links.md @@ -0,0 +1,3 @@ +**Changed** A declared `[[table]] glob` skips `node_modules` unless the glob +names it, and follows symlinks, as a path-table does. `**/*.js` no longer lists +`node_modules/...`; `link.md -> top.md` and `linkdir/*` now list their rows. diff --git a/packages/rust/migrations.d/2026-10-06-config-links.md b/packages/rust/migrations.d/2026-10-06-config-links.md new file mode 100644 index 000000000..1a00dc32f --- /dev/null +++ b/packages/rust/migrations.d/2026-10-06-config-links.md @@ -0,0 +1,43 @@ +### Config globs skip node_modules unless named, and follow symlinks + +#### Summary + +`glob = "**/*.js"` used to list files under any `node_modules`; it now does +not, unless a component of the glob is `node_modules`. Symlinked files and +directories, which a config glob used to ignore, are now followed as in a +path-table and in bash. + +#### Required changes + +| Before | After | +| --- | --- | +| `glob = "**/*.js"` (included `node_modules/`) | `glob = "node_modules/**/*.js"` to list it | + +#### Deprecations removed + +_None._ + +#### Behavior changes without code changes + +- A glob with no `node_modules` component never matches under one. +- A symlinked file or directory the glob reaches now yields rows. + +#### Verification + +```bash +cd "$(mktemp -d)" +mkdir real node_modules +echo '[{"p":"r"}]' > real/r.json +echo '[{"p":"n"}]' > node_modules/n.json +ln -s real linkdir +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: no row from node_modules; rows for real/ (symlinked linkdir/ is +# reached by `linkdir/*.json`, not by `**`) +``` diff --git a/packages/rust/src/matcher.rs b/packages/rust/src/matcher.rs index 129be062a..4a032195d 100644 --- a/packages/rust/src/matcher.rs +++ b/packages/rust/src/matcher.rs @@ -1,5 +1,5 @@ use crate::posix_class::expand_posix_classes; -use crate::scanner::{PathGlob, compile_glob}; +use crate::scanner::{PathGlob, compile_glob, compile_globs}; use globset::GlobBuilder; use regex::{Regex, RegexBuilder}; use std::ffi::OsStr; @@ -80,21 +80,28 @@ pub struct MatchResult { pub table_name: String, } +const NODE_MODULES: &str = "node_modules"; + struct PatternEntry { pattern: PathGlob, table_name: String, + names_node_modules: bool, } /// Maps file paths to table names based on glob patterns. /// Every matching pattern fires: a file matching N patterns yields N /// `MatchResult`s (one per table), so a file can belong to multiple tables. -/// An ignore list filters paths entirely. `{name}` placeholders in glob -/// patterns are accepted and behave like `*`. +/// An ignore list filters paths entirely. pub struct TableMatcher { entries: Vec, ignore_set: Vec, ignore_dir_set: Vec, gitignore: bool, + walk: PathGlob, +} + +fn has_node_modules_component(path: &Path) -> bool { + path.components().any(|c| c.as_os_str() == NODE_MODULES) } impl TableMatcher { @@ -105,8 +112,11 @@ impl TableMatcher { entries.push(PatternEntry { pattern: compile_glob(pattern)?, table_name: table_name.to_string(), + names_node_modules: pattern.split('/').any(|c| c == NODE_MODULES), }); } + let globs: Vec<&str> = mappings.iter().map(|(pattern, _)| *pattern).collect(); + let walk = compile_globs(&globs)?; let mut ignore_set = Vec::new(); let mut ignore_dir_set = Vec::new(); @@ -122,6 +132,7 @@ impl TableMatcher { ignore_set, ignore_dir_set, gitignore: false, + walk, }) } @@ -141,18 +152,27 @@ impl TableMatcher { pub fn match_all(&self, path: &Path) -> Vec { self.entries .iter() - .filter(|entry| entry.pattern.is_match_unhidden(path)) + .filter(|entry| { + entry.pattern.is_match_unhidden(path) + && (entry.names_node_modules || !has_node_modules_component(path)) + }) .map(|entry| MatchResult { table_name: entry.table_name.clone(), }) .collect() } - /// Whether any table's glob spells the dot-named `name`. - pub(crate) fn spells_dot_name(&self, name: &OsStr) -> bool { - self.entries - .iter() - .any(|entry| entry.pattern.spells_dot_name(name)) + /// The one glob a walk for every table at once follows. + pub(crate) fn walk_glob(&self) -> &PathGlob { + &self.walk + } + + /// Whether the walk may skip a directory called `name` outright: it is + /// `node_modules` and no table's glob names it. + pub(crate) fn prunes_directory(&self, name: &OsStr) -> bool { + name == NODE_MODULES + && !self.entries.is_empty() + && !self.entries.iter().any(|e| e.names_node_modules) } /// Returns true if the path matches any ignore pattern. @@ -194,6 +214,30 @@ mod tests { assert!(matcher.with_gitignore(true).respects_gitignore()); } + #[test] + fn node_modules_is_skipped_unless_a_table_names_it() { + let matcher = + TableMatcher::new(&[("**/*.js", "all"), ("node_modules/*.js", "nm")], &[]).unwrap(); + assert_eq!(names(&matcher, "pkg/a.js"), vec!["all"]); + assert_eq!( + names(&matcher, "pkg/node_modules/a.js"), + Vec::::new() + ); + assert_eq!(names(&matcher, "node_modules/a.js"), vec!["nm"]); + } + + #[test] + fn the_walk_prunes_node_modules_only_while_no_table_names_it() { + let name = OsStr::new("node_modules"); + let plain = TableMatcher::new(&[("**/*.js", "t")], &[]).unwrap(); + let naming = TableMatcher::new(&[("node_modules/*.js", "t")], &[]).unwrap(); + let none = TableMatcher::new(&[], &[]).unwrap(); + assert!(plain.prunes_directory(name)); + assert!(!plain.prunes_directory(OsStr::new("src"))); + assert!(!naming.prunes_directory(name)); + assert!(!none.prunes_directory(name)); + } + #[test] fn match_all_returns_empty_for_no_match() { let matcher = TableMatcher::new(&[("*.csv", "data")], &[]).unwrap(); diff --git a/packages/rust/src/scanner.rs b/packages/rust/src/scanner.rs index 863ead84a..78065133b 100644 --- a/packages/rust/src/scanner.rs +++ b/packages/rust/src/scanner.rs @@ -84,7 +84,7 @@ fn scan_below( root, start, matcher, - None, + Some(matcher.walk_glob()), gitignore, repo_frames, &mut |rel_path, entry| { @@ -280,7 +280,16 @@ impl PathGlob { /// it a lone `*` would cross `/` and the explicit non-recursive spelling would /// silently recurse. `**` still crosses separators. pub fn compile_glob(pattern: &str) -> Result { - let words = crate::brace::expand(pattern); + compile_globs(&[pattern]) +} + +/// One [`PathGlob`] over every word of every pattern: the walk a set of +/// tables shares, entering what any of them could reach. +pub fn compile_globs(patterns: &[&str]) -> Result { + let words: Vec = patterns + .iter() + .flat_map(|pattern| crate::brace::expand(pattern)) + .collect(); let mut files = Vec::new(); let mut spelled_dot_names = Vec::new(); for word in &words { @@ -446,16 +455,16 @@ impl Walk<'_> { /// `.gitignore` files in force. fn admits(&self, depth: usize, is_dir: bool, name: &OsStr, path: &Path, rel: &Path) -> bool { should_descend(depth, is_dir, name, rel, self.ignore) + && !(is_dir && self.ignore.prunes_directory(name)) && self.admits_name(name) && (self.frames.is_empty() || !is_gitignored(&self.frames, path, is_dir)) } fn admits_name(&self, name: &OsStr) -> bool { - !is_dot_named(name) - || match self.glob { - Some(glob) => glob.spells_dot_name(name), - None => self.ignore.spells_dot_name(name), - } + match self.glob { + Some(glob) => !is_dot_named(name) || glob.spells_dot_name(name), + None => true, + } } fn next_states(&self, states: &[usize], name: &OsStr, kind: Kind) -> Vec { @@ -910,26 +919,6 @@ mod tests { )); } - #[test] - fn a_table_walk_admits_a_dot_name_only_a_table_glob_spells() { - let ignore = TableMatcher::new(&[(".env", "t")], &[]).unwrap(); - let walk = walk_with(&ignore, None, Vec::new()); - assert!(walk.admits( - 1, - false, - OsStr::new(".env"), - Path::new("/r/.env"), - Path::new(".env") - )); - assert!(!walk.admits( - 1, - false, - OsStr::new(".other"), - Path::new("/r/.other"), - Path::new(".other") - )); - } - #[test] fn a_match_with_an_unspelled_dot_component_is_hidden() { let glob = compile_glob("**/*.md").unwrap(); diff --git a/packages/ts/changelog.d/2026-10-06-config-links.md b/packages/ts/changelog.d/2026-10-06-config-links.md new file mode 100644 index 000000000..f7b499d1c --- /dev/null +++ b/packages/ts/changelog.d/2026-10-06-config-links.md @@ -0,0 +1,3 @@ +**Changed** A declared `[[table]] glob` skips `node_modules` unless the glob +names it, and follows symlinks, as a path-table does. `**/*.js` no longer lists +`node_modules/...`; `link.md -> top.md` and `linkdir/*` now list their rows. diff --git a/packages/ts/migrations.d/2026-10-06-config-links.md b/packages/ts/migrations.d/2026-10-06-config-links.md new file mode 100644 index 000000000..1a00dc32f --- /dev/null +++ b/packages/ts/migrations.d/2026-10-06-config-links.md @@ -0,0 +1,43 @@ +### Config globs skip node_modules unless named, and follow symlinks + +#### Summary + +`glob = "**/*.js"` used to list files under any `node_modules`; it now does +not, unless a component of the glob is `node_modules`. Symlinked files and +directories, which a config glob used to ignore, are now followed as in a +path-table and in bash. + +#### Required changes + +| Before | After | +| --- | --- | +| `glob = "**/*.js"` (included `node_modules/`) | `glob = "node_modules/**/*.js"` to list it | + +#### Deprecations removed + +_None._ + +#### Behavior changes without code changes + +- A glob with no `node_modules` component never matches under one. +- A symlinked file or directory the glob reaches now yields rows. + +#### Verification + +```bash +cd "$(mktemp -d)" +mkdir real node_modules +echo '[{"p":"r"}]' > real/r.json +echo '[{"p":"n"}]' > node_modules/n.json +ln -s real linkdir +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: no row from node_modules; rows for real/ (symlinked linkdir/ is +# reached by `linkdir/*.json`, not by `**`) +``` From a5fee4d9fcb18462f4b121c3272e901460b6da0a Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 00:22:23 -0400 Subject: [PATCH 3/8] e2e attestation for claude/1258-config-links --- packages/ts/e2e-attestations/claude-1258-config-links.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/ts/e2e-attestations/claude-1258-config-links.json diff --git a/packages/ts/e2e-attestations/claude-1258-config-links.json b/packages/ts/e2e-attestations/claude-1258-config-links.json new file mode 100644 index 000000000..d71ab9707 --- /dev/null +++ b/packages/ts/e2e-attestations/claude-1258-config-links.json @@ -0,0 +1,7 @@ +{ + "command": "pnpm test:e2e", + "ran_at": 1791260543, + "exit_code": 0, + "commit": "580787babfd5db4ef749c3dd453efa649f39484c", + "branch": "claude/1258-config-links" +} From e43fe7a3b68690b9197493ad4e1b447cfa8cb302 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 00:37:30 -0400 Subject: [PATCH 4/8] Root the init config tests at the temp directory and drop a stale mutation exemption --- packages/rust/tests/init_integration.rs | 12 +++++++++--- testing-conventions.toml | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/rust/tests/init_integration.rs b/packages/rust/tests/init_integration.rs index 5fd3e840d..1a173b34a 100644 --- a/packages/rust/tests/init_integration.rs +++ b/packages/rust/tests/init_integration.rs @@ -46,8 +46,11 @@ fn writes_the_default_config_verbatim() { "init must write DEFAULT_CONFIG_TOML verbatim", ); - dirsql::DirSQL::from_config_path(&config_path) - .expect("config produced by `dirsql init` must load via from_config_path"); + dirsql::DirSQL::builder() + .root(cwd.path()) + .config(&config_path) + .build() + .expect("config produced by `dirsql init` must load"); } #[test] @@ -104,7 +107,10 @@ fn force_flag_overwrites_existing_config() { let written = fs::read_to_string(cwd.path().join(".dirsql.toml")).unwrap(); assert_eq!(written, dirsql::cli::DEFAULT_CONFIG_TOML); - dirsql::DirSQL::from_config_path(cwd.path().join(".dirsql.toml")) + dirsql::DirSQL::builder() + .root(cwd.path()) + .config(cwd.path().join(".dirsql.toml")) + .build() .expect("forced-overwrite config must load"); } diff --git a/testing-conventions.toml b/testing-conventions.toml index b1a3125c7..8c60f6db0 100644 --- a/testing-conventions.toml +++ b/testing-conventions.toml @@ -108,7 +108,7 @@ features = ["cli"] [[rust.exempt]] path = "src/scanner.rs" rules = ["mutation"] -lines = [72, 131, 349, 386, 465, 486] +lines = [72, 131, 349, 386, 486] reason = "scan_below, scan_glob, walk, descend, kind_of and sorted_entries read the filesystem; tests/scanner.rs (scan_finds_matching_files, scan_recurses_into_subdirectories), tests/vtab.rs (glob_scopes_the_walk, rowids_count_up_from_zero_in_scan_order) and tests/path_table_symlinks.rs assert what they return" [[rust.exempt]] From cad09c68a8827a45153429187501d1410948efab Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 00:54:00 -0400 Subject: [PATCH 5/8] Start a subtree walk at the glob state its path implies and pin the node_modules prune --- packages/rust/src/scanner.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/rust/src/scanner.rs b/packages/rust/src/scanner.rs index 78065133b..625a323cd 100644 --- a/packages/rust/src/scanner.rs +++ b/packages/rust/src/scanner.rs @@ -384,7 +384,11 @@ fn walk( in_repo: repo_frames.is_some(), frames: repo_frames.unwrap_or_default(), }; - let states = glob.map_or_else(Vec::new, PathGlob::start); + let states = glob.map_or_else(Vec::new, |glob| { + rel.components().fold(glob.start(), |states, component| { + glob.step(&states, component.as_os_str(), Kind::Dir) + }) + }); walk.descend(start, rel, depth, &states, false, visit); } @@ -919,6 +923,24 @@ mod tests { )); } + #[test] + fn a_table_walk_skips_a_node_modules_directory_no_table_names() { + let ignore = TableMatcher::new(&[("**/*.js", "t")], &[]).unwrap(); + let walk = walk_with(&ignore, Some(ignore.walk_glob()), Vec::new()); + let admits = |is_dir, name: &str| { + walk.admits( + 1, + is_dir, + OsStr::new(name), + Path::new(name), + Path::new(name), + ) + }; + assert!(!admits(true, "node_modules")); + assert!(admits(false, "node_modules")); + assert!(admits(true, "src")); + } + #[test] fn a_match_with_an_unspelled_dot_component_is_hidden() { let glob = compile_glob("**/*.md").unwrap(); From fecfababc5c842fd184d874ce299250ba9ecc500 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 01:09:54 -0400 Subject: [PATCH 6/8] Realign the scanner mutation exemptions to the shifted lines --- testing-conventions.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testing-conventions.toml b/testing-conventions.toml index 8c60f6db0..75cc42a17 100644 --- a/testing-conventions.toml +++ b/testing-conventions.toml @@ -108,37 +108,37 @@ features = ["cli"] [[rust.exempt]] path = "src/scanner.rs" rules = ["mutation"] -lines = [72, 131, 349, 386, 486] +lines = [72, 138, 376, 417, 497, 518] reason = "scan_below, scan_glob, walk, descend, kind_of and sorted_entries read the filesystem; tests/scanner.rs (scan_finds_matching_files, scan_recurses_into_subdirectories), tests/vtab.rs (glob_scopes_the_walk, rowids_count_up_from_zero_in_scan_order) and tests/path_table_symlinks.rs assert what they return" [[rust.exempt]] path = "src/scanner.rs" rules = ["mutation"] -lines = [403, 404, 407, 466, 469] +lines = [434, 435, 438, 498, 501] reason = "whether a walked entry is a symlink, and whether the walk is below one, is known only from a real tree; tests/path_table_symlinks.rs asserts every outcome against bash, and the decisions themselves are unit-tested in classify, Walk::follows and PathGlob::step" [[rust.exempt]] path = "src/scanner.rs" rules = ["mutation"] -lines = [389, 391, 423, 500, 513] +lines = [420, 422, 454, 532, 545] 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] +lines = [71, 573] 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"] -lines = [89] +lines = [96] reason = "the walk's running file count is observable only through the CLI's progress line; tests/scan_progress_e2e.rs forced_progress_reports_the_walk_phase_on_stderr asserts the number" [[rust.exempt]] path = "src/scanner.rs" rules = ["mutation"] -lines = [397] +lines = [428] reason = "a child's depth decides the reserved top-level .dirsql rule for a real tree; tests/scanner.rs scan_excludes_top_level_dirsql_directory and tests/vtab.rs reserved_dirsql_directory_is_skipped assert it" [[rust.exempt]] From d686573e68751258dc25c982adcfaef986ca6176 Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 22:04:02 -0400 Subject: [PATCH 7/8] e2e attestation for claude/1258-config-links --- .../python/e2e-attestations/claude-1258-config-links.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 packages/python/e2e-attestations/claude-1258-config-links.json diff --git a/packages/python/e2e-attestations/claude-1258-config-links.json b/packages/python/e2e-attestations/claude-1258-config-links.json new file mode 100644 index 000000000..f729ec37e --- /dev/null +++ b/packages/python/e2e-attestations/claude-1258-config-links.json @@ -0,0 +1,7 @@ +{ + "command": "uv run python -m pytest tests/e2e/glob_speed_symlink_test.py tests/e2e/glob_speed_node_modules_test.py tests/e2e/glob_speed_dotfiles_test.py tests/e2e/glob_speed_matchers_test.py tests/e2e/query_contract_test.py -x -q", + "ran_at": 1791338642, + "exit_code": 0, + "commit": "81890d53f01c2d6e6e833e0748a6ff952e3382c5", + "branch": "claude/1258-config-links" +} From f3b11147b3bcfda0cf3b21a4cffff309de72347f Mon Sep 17 00:00:00 2001 From: thekevinbot <248217931+thekevinbot@users.noreply.github.com> Date: Tue, 6 Oct 2026 22:04:36 -0400 Subject: [PATCH 8/8] e2e attestation for claude/1258-config-links --- packages/ts/e2e-attestations/claude-1258-config-links.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ts/e2e-attestations/claude-1258-config-links.json b/packages/ts/e2e-attestations/claude-1258-config-links.json index d71ab9707..88c339807 100644 --- a/packages/ts/e2e-attestations/claude-1258-config-links.json +++ b/packages/ts/e2e-attestations/claude-1258-config-links.json @@ -1,7 +1,7 @@ { "command": "pnpm test:e2e", - "ran_at": 1791260543, + "ran_at": 1791338676, "exit_code": 0, - "commit": "580787babfd5db4ef749c3dd453efa649f39484c", + "commit": "d686573e68751258dc25c982adcfaef986ca6176", "branch": "claude/1258-config-links" }