dirsql 0.4.126__tar.gz → 0.4.127__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (489) hide show
  1. {dirsql-0.4.126 → dirsql-0.4.127}/Cargo.lock +2 -2
  2. {dirsql-0.4.126 → dirsql-0.4.127}/PKG-INFO +1 -1
  3. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/Cargo.toml +1 -1
  4. dirsql-0.4.127/packages/python/e2e-attestations/bot-1562-hook-savepoint-1102.json +7 -0
  5. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/Cargo.toml +1 -1
  6. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/command.rs +71 -21
  7. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/foreign_key.rs +61 -10
  8. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/lib.rs +152 -51
  9. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/on_file.rs +59 -21
  10. {dirsql-0.4.126 → dirsql-0.4.127}/Cargo.toml +0 -0
  11. {dirsql-0.4.126 → dirsql-0.4.127}/README.md +0 -0
  12. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/__init__.py +0 -0
  13. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/_async.py +0 -0
  14. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/_dirsql.pyi +0 -0
  15. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/cli/__init__.py +0 -0
  16. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/cli/discover_plugins/__init__.py +0 -0
  17. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
  18. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
  19. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
  20. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
  21. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/cli/main.py +0 -0
  22. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/cli/resolve_config_extensions.py +0 -0
  23. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/plan_entry_path.py +0 -0
  24. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/py.typed +0 -0
  25. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/read_config.py +0 -0
  26. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/resolve_configs_extension_specs.py +0 -0
  27. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/resolve_extension.py +0 -0
  28. {dirsql-0.4.126 → dirsql-0.4.127}/dirsql/resolve_package.py +0 -0
  29. {dirsql-0.4.126 → dirsql-0.4.127}/docs/.claude/CLAUDE.md +0 -0
  30. {dirsql-0.4.126 → dirsql-0.4.127}/docs/.vitepress/config.ts +0 -0
  31. {dirsql-0.4.126 → dirsql-0.4.127}/docs/.vitepress/theme/index.ts +0 -0
  32. {dirsql-0.4.126 → dirsql-0.4.127}/docs/.vitepress/theme/lang.ts +0 -0
  33. {dirsql-0.4.126 → dirsql-0.4.127}/docs/AGENTS.md +0 -0
  34. {dirsql-0.4.126 → dirsql-0.4.127}/docs/context/.gitattributes +0 -0
  35. {dirsql-0.4.126 → dirsql-0.4.127}/docs/context/recipes.md +0 -0
  36. {dirsql-0.4.126 → dirsql-0.4.127}/docs/context/troubleshooting.md +0 -0
  37. {dirsql-0.4.126 → dirsql-0.4.127}/docs/context/usage.md +0 -0
  38. {dirsql-0.4.126 → dirsql-0.4.127}/docs/explanation.md +0 -0
  39. {dirsql-0.4.126 → dirsql-0.4.127}/docs/getting-started.md +0 -0
  40. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/agent-skill.md +0 -0
  41. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/columns-from-paths.md +0 -0
  42. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/define-tables.md +0 -0
  43. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/embed.md +0 -0
  44. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/extract-from-contents.md +0 -0
  45. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/load-extension.md +0 -0
  46. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/parse-files-into-columns.md +0 -0
  47. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/persist.md +0 -0
  48. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/query-json.md +0 -0
  49. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/query-without-config.md +0 -0
  50. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/react-to-changes.md +0 -0
  51. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/search-by-meaning.md +0 -0
  52. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/search-indexes.md +0 -0
  53. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/skip-files.md +0 -0
  54. {dirsql-0.4.126 → dirsql-0.4.127}/docs/howto/write-a-plugin.md +0 -0
  55. {dirsql-0.4.126 → dirsql-0.4.127}/docs/index.md +0 -0
  56. {dirsql-0.4.126 → dirsql-0.4.127}/docs/package.json +0 -0
  57. {dirsql-0.4.126 → dirsql-0.4.127}/docs/plugins.md +0 -0
  58. {dirsql-0.4.126 → dirsql-0.4.127}/docs/pnpm-lock.yaml +0 -0
  59. {dirsql-0.4.126 → dirsql-0.4.127}/docs/pnpm-workspace.yaml +0 -0
  60. {dirsql-0.4.126 → dirsql-0.4.127}/docs/reference/cli.md +0 -0
  61. {dirsql-0.4.126 → dirsql-0.4.127}/docs/reference/columns.md +0 -0
  62. {dirsql-0.4.126 → dirsql-0.4.127}/docs/reference/config.md +0 -0
  63. {dirsql-0.4.126 → dirsql-0.4.127}/docs/reference/glob.md +0 -0
  64. {dirsql-0.4.126 → dirsql-0.4.127}/docs/reference/hooks.md +0 -0
  65. {dirsql-0.4.126 → dirsql-0.4.127}/docs/reference/http-api.md +0 -0
  66. {dirsql-0.4.126 → dirsql-0.4.127}/docs/reference/path-tables.md +0 -0
  67. {dirsql-0.4.126 → dirsql-0.4.127}/docs/reference/sdk.md +0 -0
  68. {dirsql-0.4.126 → dirsql-0.4.127}/docs/speed.json +0 -0
  69. {dirsql-0.4.126 → dirsql-0.4.127}/docs/speed.md +0 -0
  70. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/CHANGELOG.md +0 -0
  71. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/MIGRATIONS.md +0 -0
  72. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/README.md +0 -0
  73. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  74. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
  75. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  76. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
  77. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  78. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
  79. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
  80. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
  81. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  82. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
  83. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
  84. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
  85. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
  86. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
  87. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
  88. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
  89. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
  90. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
  91. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
  92. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
  93. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
  94. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
  95. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
  96. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
  97. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +0 -0
  98. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-18-export-scan-failure.md +0 -0
  99. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-18-flatten-row-event-in-core.md +0 -0
  100. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-18-programmatic-extension-plan.md +0 -0
  101. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
  102. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md +0 -0
  103. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-02-readme-docs-host.md +0 -0
  104. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
  105. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-03-path-table-directory-one-level.md +0 -0
  106. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
  107. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-brace-groups-follow-bash.md +0 -0
  108. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-cli-context.md +0 -0
  109. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-gitignore-requires-repo.md +0 -0
  110. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-path-table-node-modules-named.md +0 -0
  111. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-path-table-symlinks.md +0 -0
  112. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-path-table-trailing-slash.md +0 -0
  113. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-05-unbalanced-brackets-literal.md +0 -0
  114. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-braces.md +0 -0
  115. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-directory.md +0 -0
  116. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-dotnames.md +0 -0
  117. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-gitignore.md +0 -0
  118. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-globs-anchor-at-the-config.md +0 -0
  119. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-config-links.md +0 -0
  120. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-one-glob-compiler.md +0 -0
  121. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-plugin-no-default-records.md +0 -0
  122. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-watch-broadcast.md +0 -0
  123. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-06-zero-match-config-table-warning.md +0 -0
  124. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-bracket-slash-literal.md +0 -0
  125. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-dotdot-and-double-slashes.md +0 -0
  126. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-dotdot-as-written.md +0 -0
  127. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-glob-walks-node-modules.md +0 -0
  128. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-literal-gitignore.md +0 -0
  129. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-on-file-ndjson.md +0 -0
  130. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-parallel-hooks.md +0 -0
  131. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-persist-cache-outside-root.md +0 -0
  132. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-posix-classes-unicode.md +0 -0
  133. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-07-spread-few-large-files.md +0 -0
  134. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-08-small-walks-stay-on-one-thread.md +0 -0
  135. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-10-08-watch-requires-named-table.md +0 -0
  136. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-11-02-watch-dirs-created-mid-registration.md +0 -0
  137. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/2026-11-02-watch-live-on-return.md +0 -0
  138. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/changelog.d/README.md +0 -0
  139. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/conftest.py +0 -0
  140. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/.claude/CLAUDE.md +0 -0
  141. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/.vitepress/config.ts +0 -0
  142. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  143. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  144. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/AGENTS.md +0 -0
  145. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/context/.gitattributes +0 -0
  146. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/context/recipes.md +0 -0
  147. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/context/troubleshooting.md +0 -0
  148. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/context/usage.md +0 -0
  149. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/explanation.md +0 -0
  150. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/getting-started.md +0 -0
  151. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/agent-skill.md +0 -0
  152. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/columns-from-paths.md +0 -0
  153. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/define-tables.md +0 -0
  154. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/embed.md +0 -0
  155. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/extract-from-contents.md +0 -0
  156. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/load-extension.md +0 -0
  157. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
  158. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/persist.md +0 -0
  159. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/query-json.md +0 -0
  160. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/query-without-config.md +0 -0
  161. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/react-to-changes.md +0 -0
  162. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/search-by-meaning.md +0 -0
  163. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/search-indexes.md +0 -0
  164. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/skip-files.md +0 -0
  165. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/howto/write-a-plugin.md +0 -0
  166. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/index.md +0 -0
  167. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/package.json +0 -0
  168. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/plugins.md +0 -0
  169. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/pnpm-lock.yaml +0 -0
  170. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/pnpm-workspace.yaml +0 -0
  171. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/reference/cli.md +0 -0
  172. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/reference/columns.md +0 -0
  173. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/reference/config.md +0 -0
  174. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/reference/glob.md +0 -0
  175. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/reference/hooks.md +0 -0
  176. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/reference/http-api.md +0 -0
  177. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/reference/path-tables.md +0 -0
  178. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/reference/sdk.md +0 -0
  179. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/speed.json +0 -0
  180. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/docs/speed.md +0 -0
  181. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1334-listing-exemptions.json +0 -0
  182. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1397-watch-broadcast.json +0 -0
  183. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1398-inotify-error.json +0 -0
  184. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1399-server-cors.json +0 -0
  185. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1401-watch-scope.json +0 -0
  186. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1406-watch-no-tables-1008.json +0 -0
  187. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1407-child-place-depth.json +0 -0
  188. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1414-stat-speed.json +0 -0
  189. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1415-server-speed.json +0 -0
  190. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1416-watch-speed-1008.json +0 -0
  191. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1418-node-modules.json +0 -0
  192. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1419-dotdot-slashes.json +0 -0
  193. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1420-bracket-slash.json +0 -0
  194. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1421-posix-unicode.json +0 -0
  195. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1422-literal-gitignore.json +0 -0
  196. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1426-walk-spawn-threshold-1008.json +0 -0
  197. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1428-ndjson-hooks.json +0 -0
  198. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1429-parallel-hooks.json +0 -0
  199. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1430-dotdot-as-written.json +0 -0
  200. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1431-persist-cache-dir.json +0 -0
  201. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1437-test-cache-isolation.json +0 -0
  202. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1440-fix-main-build.json +0 -0
  203. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1448-wildcard-ignored-prefix.json +0 -0
  204. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1451-named-dir-never-hidden.json +0 -0
  205. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1454-split-few-files.json +0 -0
  206. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1457-incremental-refresh-1008.json +0 -0
  207. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1459-rescan-on-overflow-1008.json +0 -0
  208. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1461-chunked-read-1016.json +0 -0
  209. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1461-row-footprint-1008.json +0 -0
  210. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1461-step3-1020.json +0 -0
  211. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1461-wide-read-1015.json +0 -0
  212. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1462-paired-speed-harness-1008.json +0 -0
  213. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1464-fastest-native-1008.json +0 -0
  214. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1469-ci-speed-sanity-1009.json +0 -0
  215. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1470-perf-suite-1009.json +0 -0
  216. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1470-speed-page-1011.json +0 -0
  217. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1474-vtab-speed-1014.json +0 -0
  218. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1475-rowpath-1016.json +0 -0
  219. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1477-onelevel-speed-1015.json +0 -0
  220. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1477-onelevel-speed-1016.json +0 -0
  221. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1478-perdir-walk-1020.json +0 -0
  222. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1480-matcher-speed-1015.json +0 -0
  223. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1481-gitrepo-speed-1015.json +0 -0
  224. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1483-fm-speed-1015.json +0 -0
  225. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1484-jsonl-speed-1015.json +0 -0
  226. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1487-frontend-query-1011.json +0 -0
  227. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1488-frontend-metadata-1011.json +0 -0
  228. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1489-frontend-browse-1013.json +0 -0
  229. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1503-bench-watch-1011.json +0 -0
  230. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1504-bench-names-1011.json +0 -0
  231. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1514-watch-rerun-inline-1015.json +0 -0
  232. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1524-path-eq-1016.json +0 -0
  233. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1526-main-red-1016.json +0 -0
  234. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1532-gitignore-fastest-bar-1016.json +0 -0
  235. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1534-fm-native-1016.json +0 -0
  236. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1534-fm-native-1102.json +0 -0
  237. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1538-onfile-order-1019.json +0 -0
  238. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1540-update-in-place-1019.json +0 -0
  239. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1541-defer-fk-1019.json +0 -0
  240. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1544-perfile-update-1020.json +0 -0
  241. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1552-watch-gap-1102.json +0 -0
  242. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1557-watch-rename-1102.json +0 -0
  243. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-1562-watch-speed-1102.json +0 -0
  244. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-fix-main-place-depth-20261007.json +0 -0
  245. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-issue-1486-frontend-20261009.json +0 -0
  246. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-gap-childpath-1011.json +0 -0
  247. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-parse-overlap-1011.json +0 -0
  248. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-parse-paths-1009.json +0 -0
  249. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-parse-pragmas-1011.json +0 -0
  250. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-sql-valueref-1013.json +0 -0
  251. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-walk-components-1011.json +0 -0
  252. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-walk-rowpath-1011.json +0 -0
  253. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-walk-rows-1013.json +0 -0
  254. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/bot-speed-walk-sched-1009.json +0 -0
  255. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
  256. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
  257. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
  258. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
  259. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
  260. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
  261. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
  262. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
  263. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
  264. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1119-ext-plan.json +0 -0
  265. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1120-py-ext.json +0 -0
  266. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1122-ext-cleanup.json +0 -0
  267. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1130-codec-crates.json +0 -0
  268. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1131-flatten-row-event.json +0 -0
  269. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1139-sse-flatten.json +0 -0
  270. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1140-scan-failure-export.json +0 -0
  271. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1148-clippy-all-targets.json +0 -0
  272. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1164-sigint-fatal.json +0 -0
  273. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1170-projection-order.json +0 -0
  274. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1172-on-file-path.json +0 -0
  275. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1173-py-projection-order.json +0 -0
  276. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1184-win-rel-paths.json +0 -0
  277. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1185-win-abs-table-names.json +0 -0
  278. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1186-win-test-harness.json +0 -0
  279. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1196-join-index.json +0 -0
  280. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1199-glob-prefix.json +0 -0
  281. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1201-single-walk.json +0 -0
  282. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1204-embed-batch.json +0 -0
  283. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1207-win-argv-quote.json +0 -0
  284. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1208-win-nonverbatim-paths.json +0 -0
  285. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1215-on-file-batch.json +0 -0
  286. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1216-on-file-cleanup.json +0 -0
  287. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1223-config-glob-rule.json +0 -0
  288. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1223-dir-one-level.json +0 -0
  289. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1225-plugin-no-default.json +0 -0
  290. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1226-stale-docs.json +0 -0
  291. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1232-anchor-plumbing.json +0 -0
  292. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1232-config-anchor.json +0 -0
  293. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1232-multi-watch.json +0 -0
  294. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1232-zero-match.json +0 -0
  295. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1238-parallel-walk.json +0 -0
  296. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1241-content-prefetch.json +0 -0
  297. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1243-ingest-perf.json +0 -0
  298. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1249-dotfiles.json +0 -0
  299. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1256-symlinks.json +0 -0
  300. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1257-trailing-slash.json +0 -0
  301. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-config-braces.json +0 -0
  302. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-config-directory.json +0 -0
  303. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-config-dotnames.json +0 -0
  304. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-config-gitignore.json +0 -0
  305. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-config-links.json +0 -0
  306. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1258-one-pattern.json +0 -0
  307. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1262-brace-literal.json +0 -0
  308. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1264-context.json +0 -0
  309. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1267-posix-classes.json +0 -0
  310. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1268-unbalanced-brackets.json +0 -0
  311. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1269-utf8-chars.json +0 -0
  312. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1271-node-modules-named.json +0 -0
  313. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1272-ancestor-gitignore.json +0 -0
  314. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1273-walk-prune.json +0 -0
  315. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1285-ingest-fast.json +0 -0
  316. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1286-nested-repo.json +0 -0
  317. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1305-glob-speed.json +0 -0
  318. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1308-glob-speed.json +0 -0
  319. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1310-glob-speed.json +0 -0
  320. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1311-glob-speed.json +0 -0
  321. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1312-glob-speed.json +0 -0
  322. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1318-lazy-stat.json +0 -0
  323. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1320-walk-speed.json +0 -0
  324. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1322-walk-readdir.json +0 -0
  325. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1325-parallel-walk.json +0 -0
  326. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1326-stream-rows.json +0 -0
  327. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-python-dirsql-patch.json +0 -0
  328. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-python-extensions-patch.json +0 -0
  329. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-scanner-effects.json +0 -0
  330. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-scanner-gitignore.json +0 -0
  331. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-vtab-prefetch-flag.json +0 -0
  332. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1330-vtab-read.json +0 -0
  333. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-1351-dot-dirs.json +0 -0
  334. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
  335. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
  336. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
  337. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
  338. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
  339. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
  340. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
  341. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
  342. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
  343. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
  344. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
  345. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
  346. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
  347. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
  348. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
  349. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
  350. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
  351. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
  352. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
  353. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
  354. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
  355. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
  356. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
  357. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
  358. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
  359. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
  360. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md +0 -0
  361. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-02-readme-docs-host.md +0 -0
  362. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
  363. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-03-path-table-directory-one-level.md +0 -0
  364. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
  365. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-brace-groups-follow-bash.md +0 -0
  366. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-cli-context.md +0 -0
  367. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-gitignore-requires-repo.md +0 -0
  368. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-path-table-node-modules-named.md +0 -0
  369. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-path-table-symlinks.md +0 -0
  370. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-path-table-trailing-slash.md +0 -0
  371. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-05-unbalanced-brackets-literal.md +0 -0
  372. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-braces.md +0 -0
  373. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-directory.md +0 -0
  374. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-dotnames.md +0 -0
  375. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-gitignore.md +0 -0
  376. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-globs-anchor-at-the-config.md +0 -0
  377. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-config-links.md +0 -0
  378. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-one-glob-compiler.md +0 -0
  379. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-plugin-no-default-records.md +0 -0
  380. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-watch-broadcast.md +0 -0
  381. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-06-zero-match-config-table-warning.md +0 -0
  382. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-bracket-slash-literal.md +0 -0
  383. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-dotdot-and-double-slashes.md +0 -0
  384. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-dotdot-as-written.md +0 -0
  385. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-glob-walks-node-modules.md +0 -0
  386. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-literal-gitignore.md +0 -0
  387. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-on-file-ndjson.md +0 -0
  388. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-parallel-hooks.md +0 -0
  389. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-persist-cache-outside-root.md +0 -0
  390. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-posix-classes-unicode.md +0 -0
  391. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-07-spread-few-large-files.md +0 -0
  392. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-08-small-walks-stay-on-one-thread.md +0 -0
  393. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-10-08-watch-requires-named-table.md +0 -0
  394. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-11-02-watch-dirs-created-mid-registration.md +0 -0
  395. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/2026-11-02-watch-live-on-return.md +0 -0
  396. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/migrations.d/README.md +0 -0
  397. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/src/lib.rs +0 -0
  398. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/testing-conventions.toml +0 -0
  399. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/__init__.py +0 -0
  400. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/conftest.py +0 -0
  401. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/e2e/__init__.py +0 -0
  402. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/e2e/bench_report.py +0 -0
  403. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/e2e/bench_suite.py +0 -0
  404. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
  405. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
  406. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/e2e/speed_of_light.py +0 -0
  407. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/integration/__init__.py +0 -0
  408. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/integration/binding/__init__.py +0 -0
  409. {dirsql-0.4.126 → dirsql-0.4.127}/packages/python/tests/integration/hermetic/__init__.py +0 -0
  410. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/CHANGELOG.md +0 -0
  411. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/MIGRATIONS.md +0 -0
  412. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/README.md +0 -0
  413. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/benches/db_bench.rs +0 -0
  414. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/benches/differ_bench.rs +0 -0
  415. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/benches/matcher_bench.rs +0 -0
  416. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/benches/scanner_bench.rs +0 -0
  417. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/context/.gitattributes +0 -0
  418. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/context/recipes.md +0 -0
  419. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/context/troubleshooting.md +0 -0
  420. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/context/usage.md +0 -0
  421. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/explanation.md +0 -0
  422. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/getting-started.md +0 -0
  423. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/agent-skill.md +0 -0
  424. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/columns-from-paths.md +0 -0
  425. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/define-tables.md +0 -0
  426. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/embed.md +0 -0
  427. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/extract-from-contents.md +0 -0
  428. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/load-extension.md +0 -0
  429. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
  430. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/persist.md +0 -0
  431. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/query-json.md +0 -0
  432. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/query-without-config.md +0 -0
  433. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/react-to-changes.md +0 -0
  434. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/search-by-meaning.md +0 -0
  435. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/search-indexes.md +0 -0
  436. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/skip-files.md +0 -0
  437. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/howto/write-a-plugin.md +0 -0
  438. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/index.md +0 -0
  439. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/plugins.md +0 -0
  440. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/reference/cli.md +0 -0
  441. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/reference/columns.md +0 -0
  442. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/reference/config.md +0 -0
  443. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/reference/glob.md +0 -0
  444. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/reference/hooks.md +0 -0
  445. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/reference/http-api.md +0 -0
  446. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/reference/path-tables.md +0 -0
  447. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/reference/sdk.md +0 -0
  448. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/speed.json +0 -0
  449. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/docs/speed.md +0 -0
  450. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/bin/dirsql.rs +0 -0
  451. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/brace.rs +0 -0
  452. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/context.rs +0 -0
  453. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/execute.rs +0 -0
  454. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/frontend.html +0 -0
  455. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/frontend.js +0 -0
  456. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/init.rs +0 -0
  457. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/mod.rs +0 -0
  458. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/repl.rs +0 -0
  459. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/router.rs +0 -0
  460. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/run.rs +0 -0
  461. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/serialize.rs +0 -0
  462. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/server.rs +0 -0
  463. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/cli/table.rs +0 -0
  464. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/config.rs +0 -0
  465. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/db.rs +0 -0
  466. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/default_config.toml +0 -0
  467. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/differ.rs +0 -0
  468. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/extension_resolution.rs +0 -0
  469. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/functions.rs +0 -0
  470. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/gitignore_frame.rs +0 -0
  471. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/infer.rs +0 -0
  472. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/launcher.rs +0 -0
  473. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/listing.rs +0 -0
  474. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/matcher.rs +0 -0
  475. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/parsed_vtab.rs +0 -0
  476. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/path_table.rs +0 -0
  477. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/per_thread.rs +0 -0
  478. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/persist.rs +0 -0
  479. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/posix_class.rs +0 -0
  480. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/progress.rs +0 -0
  481. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/row_event_flat.rs +0 -0
  482. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/row_stream.rs +0 -0
  483. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/scanner.rs +0 -0
  484. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/sql_literal.rs +0 -0
  485. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/tree_walk.rs +0 -0
  486. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/vtab.rs +0 -0
  487. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/vtab_scaffold.rs +0 -0
  488. {dirsql-0.4.126 → dirsql-0.4.127}/packages/rust/src/watcher.rs +0 -0
  489. {dirsql-0.4.126 → dirsql-0.4.127}/pyproject.toml +0 -0
@@ -573,7 +573,7 @@ dependencies = [
573
573
 
574
574
  [[package]]
575
575
  name = "dirsql"
576
- version = "0.4.126"
576
+ version = "0.4.127"
577
577
  dependencies = [
578
578
  "assert_cmd",
579
579
  "axum",
@@ -625,7 +625,7 @@ dependencies = [
625
625
 
626
626
  [[package]]
627
627
  name = "dirsql-py-ext"
628
- version = "0.4.126"
628
+ version = "0.4.127"
629
629
  dependencies = [
630
630
  "dirsql",
631
631
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.4.126
3
+ Version: 0.4.127
4
4
  Requires-Dist: bin-shim>=0.1
5
5
  Summary: Ephemeral SQL index over a local directory
6
6
  Keywords: sql,filesystem,directory,sqlite,index
@@ -4,7 +4,7 @@ name = "dirsql-py-ext"
4
4
  # pypi/maturin handler can rewrite it via `write-version` before
5
5
  # `maturin build`. `pyproject.toml` declares `dynamic = ["version"]`
6
6
  # and maturin reads this field. Mirrors `packages/rust/Cargo.toml`.
7
- version = "0.4.126"
7
+ version = "0.4.127"
8
8
  # abi3 note: the `abi3-py310` pyo3 feature (below) builds ONE stable-ABI
9
9
  # `cp310-abi3` wheel per platform that loads on every CPython >= 3.10
10
10
  # (matching `pyproject.toml`'s `requires-python = ">=3.10"`), instead of
@@ -0,0 +1,7 @@
1
+ {
2
+ "command": "uv run python -m pytest tests/e2e/on_file_query_test.py tests/e2e/query_contract_test.py tests/e2e/declared_table_name_test.py tests/e2e/fanout_test.py tests/e2e/use_case_dossier_test.py tests/e2e/use_case_join_test.py tests/e2e/use_case_notebook_test.py tests/e2e/use_case_transcripts_test.py tests/e2e/watch_speed_test.py -q",
3
+ "ran_at": 1793671776,
4
+ "exit_code": 0,
5
+ "commit": "92277f18890c83a5a800db7c2dec4d6f0e4bb8fb",
6
+ "branch": "bot/1562-hook-savepoint-1102"
7
+ }
@@ -6,7 +6,7 @@ description = "Ephemeral SQL index over a local directory"
6
6
  # version stays for the binding crates (publish = false). The literal
7
7
  # intentionally lags the published version: putitoutthere rewrites it to
8
8
  # the planned release version at build time and never commits it back.
9
- version = "0.4.126"
9
+ version = "0.4.127"
10
10
  edition.workspace = true
11
11
  # Literal `license` (not `license.workspace = true`) because
12
12
  # putitoutthere's preflight check reads `[package].license` directly
@@ -286,12 +286,14 @@ const READ_BYTES: usize = 262_144;
286
286
  /// Run an already-built `argv` and hand its stdout to `on_block` as it
287
287
  /// arrives, in blocks that each hold whole lines (the last block may lack its
288
288
  /// trailing newline). The child runs with stdin closed. A non-zero exit is an
289
- /// error after every block has been delivered.
289
+ /// error after every block has been delivered. `on_eof` runs once stdout has
290
+ /// closed, before the child's exit is known.
290
291
  pub(crate) fn run_argv_blocks(
291
292
  command: &str,
292
293
  argv: &[String],
293
294
  cwd: &Path,
294
295
  on_block: &mut dyn FnMut(&str),
296
+ on_eof: &mut dyn FnMut(),
295
297
  ) -> Result<(), CommandError> {
296
298
  let mut cmd = Command::new(&argv[0]);
297
299
  push_args(&mut cmd, &argv[1..]);
@@ -310,10 +312,29 @@ pub(crate) fn run_argv_blocks(
310
312
  buf
311
313
  });
312
314
  let mut stdout_pipe = child.stdout.take().expect("stdout piped");
315
+ let status =
316
+ drain_then_reap(&mut stdout_pipe, on_block, on_eof, || child.wait()).map_err(|source| {
317
+ CommandError::Io {
318
+ command: command.to_string(),
319
+ source,
320
+ }
321
+ })?;
322
+ let stderr = stderr_thread.join().unwrap_or_default();
323
+ check_exit(command, status, &stderr)
324
+ }
325
+
326
+ /// Hand `stdout` to `on_block` in blocks of whole lines until it closes, run
327
+ /// `on_eof`, then `reap` the child, so work on the output overlaps its exit.
328
+ fn drain_then_reap<T>(
329
+ stdout: &mut dyn Read,
330
+ on_block: &mut dyn FnMut(&str),
331
+ on_eof: &mut dyn FnMut(),
332
+ reap: impl FnOnce() -> T,
333
+ ) -> T {
313
334
  let mut pending: Vec<u8> = Vec::new();
314
335
  let mut buf = vec![0u8; READ_BYTES];
315
336
  loop {
316
- let n = match stdout_pipe.read(&mut buf) {
337
+ let n = match stdout.read(&mut buf) {
317
338
  Ok(0) | Err(_) => break,
318
339
  Ok(n) => n,
319
340
  };
@@ -326,13 +347,8 @@ pub(crate) fn run_argv_blocks(
326
347
  if !pending.is_empty() {
327
348
  on_block(&String::from_utf8_lossy(&pending));
328
349
  }
329
-
330
- let status = child.wait().map_err(|source| CommandError::Io {
331
- command: command.to_string(),
332
- source,
333
- })?;
334
- let stderr = stderr_thread.join().unwrap_or_default();
335
- check_exit(command, status, &stderr)
350
+ on_eof();
351
+ reap()
336
352
  }
337
353
 
338
354
  // One fn with cfg blocks rather than two cfg'd fns: cargo-mutants mutates
@@ -809,10 +825,16 @@ mod tests {
809
825
  ];
810
826
  let mut seen = String::new();
811
827
  let mut blocks = 0;
812
- run_argv_blocks("t", &argv, &cwd(), &mut |block| {
813
- seen.push_str(block);
814
- blocks += 1;
815
- })
828
+ run_argv_blocks(
829
+ "t",
830
+ &argv,
831
+ &cwd(),
832
+ &mut |block| {
833
+ seen.push_str(block);
834
+ blocks += 1;
835
+ },
836
+ &mut || {},
837
+ )
816
838
  .unwrap();
817
839
  assert_eq!(seen, "a\nb\nc");
818
840
  assert!(blocks >= 1);
@@ -827,11 +849,17 @@ mod tests {
827
849
  ];
828
850
  let mut lines = 0;
829
851
  let mut blocks = 0;
830
- run_argv_blocks("t", &argv, &cwd(), &mut |block| {
831
- blocks += 1;
832
- assert!(block.ends_with('\n'), "block cut mid-line");
833
- lines += block.lines().count();
834
- })
852
+ run_argv_blocks(
853
+ "t",
854
+ &argv,
855
+ &cwd(),
856
+ &mut |block| {
857
+ blocks += 1;
858
+ assert!(block.ends_with('\n'), "block cut mid-line");
859
+ lines += block.lines().count();
860
+ },
861
+ &mut || {},
862
+ )
835
863
  .unwrap();
836
864
  assert_eq!(lines, 100_000);
837
865
  assert!(blocks > 1, "2.7 MB arrives in more than one read");
@@ -845,8 +873,14 @@ mod tests {
845
873
  "echo partial; echo oops >&2; exit 3".to_string(),
846
874
  ];
847
875
  let mut seen = String::new();
848
- let err =
849
- run_argv_blocks("t", &argv, &cwd(), &mut |block| seen.push_str(block)).unwrap_err();
876
+ let err = run_argv_blocks(
877
+ "t",
878
+ &argv,
879
+ &cwd(),
880
+ &mut |block| seen.push_str(block),
881
+ &mut || {},
882
+ )
883
+ .unwrap_err();
850
884
  assert_eq!(seen, "partial\n");
851
885
  match err {
852
886
  CommandError::NonZeroExit {
@@ -859,10 +893,26 @@ mod tests {
859
893
  }
860
894
  }
861
895
 
896
+ #[test]
897
+ fn drain_then_reap_ends_the_output_before_reaping_the_child() {
898
+ let order = std::cell::RefCell::new(Vec::new());
899
+ let reaped = drain_then_reap(
900
+ &mut &b"a\nb"[..],
901
+ &mut |block| order.borrow_mut().push(block.to_string()),
902
+ &mut || order.borrow_mut().push("eof".to_string()),
903
+ || {
904
+ order.borrow_mut().push("reap".to_string());
905
+ 7
906
+ },
907
+ );
908
+ assert_eq!(reaped, 7);
909
+ assert_eq!(*order.borrow(), vec!["a\n", "b", "eof", "reap"]);
910
+ }
911
+
862
912
  #[test]
863
913
  fn run_argv_blocks_names_a_missing_program() {
864
914
  let argv = vec!["definitely-not-a-real-binary-xyzzy".to_string()];
865
- let err = run_argv_blocks("t", &argv, &cwd(), &mut |_| {}).unwrap_err();
915
+ let err = run_argv_blocks("t", &argv, &cwd(), &mut |_| {}, &mut || {}).unwrap_err();
866
916
  assert!(
867
917
  matches!(err, CommandError::NotOnPath { .. }),
868
918
  "got: {err:?}"
@@ -54,18 +54,32 @@ pub(crate) fn commit(conn: &Connection) -> Result<(), DbError> {
54
54
  pub(crate) fn atomically<T, E: From<rusqlite::Error>>(
55
55
  conn: &Connection,
56
56
  unit: impl FnOnce() -> Result<T, E>,
57
+ ) -> Result<T, E> {
58
+ let value = stage(conn, unit)?;
59
+ keep(conn)?;
60
+ Ok(value)
61
+ }
62
+
63
+ /// Apply `unit` but hold it open, for [`keep`] or [`discard`] to settle. A
64
+ /// unit that fails is discarded here and leaves nothing open.
65
+ pub(crate) fn stage<T, E: From<rusqlite::Error>>(
66
+ conn: &Connection,
67
+ unit: impl FnOnce() -> Result<T, E>,
57
68
  ) -> Result<T, E> {
58
69
  conn.execute_batch("SAVEPOINT dirsql_unit")?;
59
- match unit() {
60
- Ok(value) => {
61
- conn.execute_batch("RELEASE dirsql_unit")?;
62
- Ok(value)
63
- }
64
- Err(e) => {
65
- conn.execute_batch("ROLLBACK TO dirsql_unit; RELEASE dirsql_unit")?;
66
- Err(e)
67
- }
68
- }
70
+ unit().inspect_err(|_| {
71
+ let _ = discard(conn);
72
+ })
73
+ }
74
+
75
+ /// Keep the unit [`stage`] left open.
76
+ pub(crate) fn keep(conn: &Connection) -> rusqlite::Result<()> {
77
+ conn.execute_batch("RELEASE dirsql_unit")
78
+ }
79
+
80
+ /// Drop the unit [`stage`] left open, as if it had never run.
81
+ pub(crate) fn discard(conn: &Connection) -> rusqlite::Result<()> {
82
+ conn.execute_batch("ROLLBACK TO dirsql_unit; RELEASE dirsql_unit")
69
83
  }
70
84
 
71
85
  /// The rows violating a foreign key right now, or `None` when there are none.
@@ -402,4 +416,41 @@ mod tests {
402
416
  commit(&conn).unwrap();
403
417
  assert_eq!(count(&conn, "parent"), 1);
404
418
  }
419
+ #[test]
420
+ fn a_staged_unit_is_visible_until_discarded() {
421
+ let conn = family(CHILD);
422
+ let out: rusqlite::Result<i32> = stage(&conn, || {
423
+ conn.execute_batch("INSERT INTO parent VALUES (1, 'a')")?;
424
+ Ok(7)
425
+ });
426
+ assert_eq!(out.unwrap(), 7);
427
+ assert_eq!(count(&conn, "parent"), 1);
428
+ discard(&conn).unwrap();
429
+ assert_eq!(count(&conn, "parent"), 0);
430
+ assert!(conn.is_autocommit());
431
+ }
432
+
433
+ #[test]
434
+ fn a_staged_unit_kept_stays() {
435
+ let conn = family(CHILD);
436
+ let out: rusqlite::Result<()> = stage(&conn, || {
437
+ conn.execute_batch("INSERT INTO parent VALUES (1, 'a')")
438
+ });
439
+ out.unwrap();
440
+ keep(&conn).unwrap();
441
+ assert!(conn.is_autocommit());
442
+ assert_eq!(count(&conn, "parent"), 1);
443
+ }
444
+
445
+ #[test]
446
+ fn a_staged_unit_that_fails_leaves_nothing_open() {
447
+ let conn = family(CHILD);
448
+ let out: rusqlite::Result<()> = stage(&conn, || {
449
+ conn.execute_batch("INSERT INTO parent VALUES (1, 'a')")?;
450
+ conn.execute_batch("INSERT INTO nowhere VALUES (1)")
451
+ });
452
+ assert!(out.is_err());
453
+ assert!(conn.is_autocommit());
454
+ assert_eq!(count(&conn, "parent"), 0);
455
+ }
405
456
  }
@@ -108,7 +108,10 @@ type OnFileFn = dyn Fn(&str) -> std::result::Result<Vec<Row>, BoxError> + Send +
108
108
  type RowSink<'a> = dyn FnMut(Vec<infer::JsonRow>) + Send + 'a;
109
109
  /// The paths a per-table hook runs over, yielded as the scan finds them.
110
110
  type PathFeed<'a> = dyn Iterator<Item = PathBuf> + Send + 'a;
111
- type OnFilesFn = dyn Fn(&mut PathFeed<'_>, &mut RowSink<'_>) -> std::result::Result<(), BoxError>
111
+ /// What a per-table hook may call once its last chunk is out, before it knows
112
+ /// whether it succeeded, so its rows can be staged while it finishes.
113
+ type OutputEnd<'a> = dyn FnMut() + 'a;
114
+ type OnFilesFn = dyn Fn(&mut PathFeed<'_>, &mut RowSink<'_>, &mut OutputEnd<'_>) -> std::result::Result<(), BoxError>
112
115
  + Send
113
116
  + Sync
114
117
  + 'static;
@@ -378,11 +381,16 @@ impl Table {
378
381
  + Sync
379
382
  + 'static,
380
383
  {
381
- Self::per_table_streaming(name, ddl, glob, move |feed, sink: &mut RowSink<'_>| {
382
- let paths: Vec<PathBuf> = feed.collect();
383
- sink(on_files(&paths)?);
384
- Ok(())
385
- })
384
+ Self::per_table_streaming(
385
+ name,
386
+ ddl,
387
+ glob,
388
+ move |feed, sink: &mut RowSink<'_>, _: &mut OutputEnd<'_>| {
389
+ let paths: Vec<PathBuf> = feed.collect();
390
+ sink(on_files(&paths)?);
391
+ Ok(())
392
+ },
393
+ )
386
394
  }
387
395
 
388
396
  /// [`per_table`](Self::per_table) for a hook that hands its rows over in
@@ -394,7 +402,11 @@ impl Table {
394
402
  on_files: F,
395
403
  ) -> Self
396
404
  where
397
- F: Fn(&mut PathFeed<'_>, &mut RowSink<'_>) -> std::result::Result<(), BoxError>
405
+ F: Fn(
406
+ &mut PathFeed<'_>,
407
+ &mut RowSink<'_>,
408
+ &mut OutputEnd<'_>,
409
+ ) -> std::result::Result<(), BoxError>
398
410
  + Send
399
411
  + Sync
400
412
  + 'static,
@@ -1031,27 +1043,31 @@ impl DirSQL {
1031
1043
  .unwrap_or_default(),
1032
1044
  Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
1033
1045
  };
1034
- let raw_rows = match collect_table_rows(hook.as_ref(), &abs_paths) {
1035
- Ok(rows) => rows,
1036
- Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
1037
- };
1038
1046
  let strict = *self.inner.strict_map.get(table).unwrap_or(&false);
1039
-
1040
- let changes = {
1041
- let db = match self.inner.db.lock() {
1042
- Ok(g) => g,
1043
- Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
1044
- };
1045
- let new_rows = match shape_rows(&db, table, raw_rows, strict) {
1046
- Ok(rows) => rows,
1047
- Err(message) => return vec![error_event(Some(table), trigger, message)],
1048
- };
1049
- match foreign_key::atomically(db.conn(), || {
1050
- db.reconcile_batch_rows(table, BATCH_OWNER, &new_rows)
1051
- }) {
1052
- Ok(changes) => changes,
1053
- Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
1047
+ let rows = Mutex::new(Vec::new());
1048
+ let take_rows = || std::mem::take(&mut *rows.lock().expect("hook rows lock"));
1049
+ let mut staged = None;
1050
+ let produced = hook(
1051
+ &mut abs_paths.into_iter(),
1052
+ &mut |chunk| rows.lock().expect("hook rows lock").extend(chunk),
1053
+ &mut || staged = Some(self.stage_table_rows(table, take_rows(), strict)),
1054
+ );
1055
+ let staged = match (produced, staged) {
1056
+ (Err(e), staged) => {
1057
+ if let Some(Ok(staged)) = staged {
1058
+ let _ = foreign_key::discard(staged.db.conn());
1059
+ }
1060
+ return vec![error_event(Some(table), trigger, e.to_string())];
1054
1061
  }
1062
+ (Ok(()), Some(staged)) => staged,
1063
+ (Ok(()), None) => self.stage_table_rows(table, take_rows(), strict),
1064
+ };
1065
+ let changes = match staged {
1066
+ Ok(Staged { db, changes }) => match foreign_key::keep(db.conn()) {
1067
+ Ok(()) => changes,
1068
+ Err(e) => return vec![error_event(Some(table), trigger, e.to_string())],
1069
+ },
1070
+ Err(message) => return vec![error_event(Some(table), trigger, message)],
1055
1071
  };
1056
1072
 
1057
1073
  if changes.keyed {
@@ -1067,6 +1083,23 @@ impl DirSQL {
1067
1083
  }
1068
1084
  }
1069
1085
 
1086
+ /// Shape a per-table hook's rows and write them as `table`'s, held open
1087
+ /// under the database lock until the hook's exit keeps or discards them.
1088
+ fn stage_table_rows(
1089
+ &self,
1090
+ table: &str,
1091
+ raw_rows: Vec<infer::JsonRow>,
1092
+ strict: bool,
1093
+ ) -> std::result::Result<Staged<'_>, String> {
1094
+ let db = self.inner.db.lock().map_err(|e| e.to_string())?;
1095
+ let rows = shape_rows(&db, table, raw_rows, strict)?;
1096
+ let changes = foreign_key::stage(db.conn(), || {
1097
+ db.reconcile_batch_rows(table, BATCH_OWNER, &rows)
1098
+ })
1099
+ .map_err(|e| e.to_string())?;
1100
+ Ok(Staged { db, changes })
1101
+ }
1102
+
1070
1103
  /// Record in the table's file set whether `abs_path` is, now, one of the
1071
1104
  /// files its per-table hook runs over. The set stays in walk order
1072
1105
  /// (component-wise byte order), so the hook sees the same argument list a
@@ -2567,16 +2600,6 @@ fn shape_rows(
2567
2600
  .map_err(|e| e.to_string())
2568
2601
  }
2569
2602
 
2570
- /// Every row a per-table hook produces over `paths`, gathered into one list.
2571
- fn collect_table_rows(
2572
- hook: &OnFilesFn,
2573
- paths: &[PathBuf],
2574
- ) -> std::result::Result<Vec<infer::JsonRow>, BoxError> {
2575
- let mut rows = Vec::new();
2576
- hook(&mut paths.iter().cloned(), &mut |chunk| rows.extend(chunk))?;
2577
- Ok(rows)
2578
- }
2579
-
2580
2603
  /// Replace a per-table hook's rows under [`BATCH_OWNER`], storing each chunk
2581
2604
  /// the hook emits while the hook, on its own thread, goes on producing the
2582
2605
  /// next. Chunks are shaped on a thread of their own, in order, so shaping one
@@ -2660,6 +2683,12 @@ fn refill_table_rows(
2660
2683
  Ok(outcome)
2661
2684
  }
2662
2685
 
2686
+ /// A per-table hook's rows written but not yet kept.
2687
+ struct Staged<'a> {
2688
+ db: std::sync::MutexGuard<'a, Db>,
2689
+ changes: db::RowChanges,
2690
+ }
2691
+
2663
2692
  /// A per-table hook running on its own thread, its rows arriving as chunks.
2664
2693
  struct Production {
2665
2694
  chunks: std::sync::mpsc::Receiver<Vec<infer::JsonRow>>,
@@ -2689,9 +2718,13 @@ fn start_hook(
2689
2718
  if paths.peek().is_none() {
2690
2719
  return Ok(());
2691
2720
  }
2692
- hook(&mut paths, &mut |chunk| {
2693
- let _ = sender.send(chunk);
2694
- })
2721
+ hook(
2722
+ &mut paths,
2723
+ &mut |chunk| {
2724
+ let _ = sender.send(chunk);
2725
+ },
2726
+ &mut || {},
2727
+ )
2695
2728
  .map_err(|e| e.to_string())
2696
2729
  });
2697
2730
  Production { chunks, handle }
@@ -2964,8 +2997,8 @@ fn build_tables_from_config(cfg: &config::Config, config_dir: &Path) -> Result<V
2964
2997
  table_cfg.name.clone(),
2965
2998
  table_cfg.ddl.clone(),
2966
2999
  glob,
2967
- move |paths: &mut PathFeed<'_>, sink: &mut RowSink<'_>| {
2968
- run_on_files(&command, paths, &hook_cwd, &hook_root, sink)
3000
+ move |paths: &mut PathFeed<'_>, sink: &mut RowSink<'_>, end: &mut OutputEnd<'_>| {
3001
+ run_on_files(&command, paths, &hook_cwd, &hook_root, sink, end)
2969
3002
  },
2970
3003
  )
2971
3004
  .anchored(anchor)
@@ -2992,9 +3025,10 @@ fn run_on_files(
2992
3025
  config_dir: &Path,
2993
3026
  root: &Path,
2994
3027
  sink: &mut RowSink<'_>,
3028
+ end: &mut OutputEnd<'_>,
2995
3029
  ) -> std::result::Result<(), BoxError> {
2996
3030
  Ok(on_file::run_streaming(
2997
- command, config_dir, root, paths, sink,
3031
+ command, config_dir, root, paths, sink, end,
2998
3032
  )?)
2999
3033
  }
3000
3034
 
@@ -3478,7 +3512,7 @@ mod internal_tests {
3478
3512
  "items",
3479
3513
  "CREATE TABLE items (name TEXT)",
3480
3514
  "**/*.txt",
3481
- move |paths: &mut PathFeed<'_>, _: &mut RowSink<'_>| {
3515
+ move |paths: &mut PathFeed<'_>, _: &mut RowSink<'_>, _: &mut OutputEnd<'_>| {
3482
3516
  for path in paths {
3483
3517
  let _ = got.lock().unwrap().send(path);
3484
3518
  }
@@ -4794,7 +4828,7 @@ mod internal_tests {
4794
4828
  chunks: Vec<Vec<infer::JsonRow>>,
4795
4829
  outcome: std::result::Result<(), String>,
4796
4830
  ) -> Production {
4797
- let hook: Arc<OnFilesFn> = Arc::new(move |_paths, sink| {
4831
+ let hook: Arc<OnFilesFn> = Arc::new(move |_paths, sink, _end| {
4798
4832
  for chunk in chunks.clone() {
4799
4833
  sink(chunk);
4800
4834
  }
@@ -5399,12 +5433,14 @@ mod internal_tests {
5399
5433
  let Hook::PerTable(on_files) = &tables[0].hook else {
5400
5434
  panic!("a configured on-file command runs once per table");
5401
5435
  };
5402
- assert_eq!(
5403
- collect_table_rows(on_files.as_ref(), &[dir.path().join("f.a")])
5404
- .unwrap()
5405
- .len(),
5406
- 1
5407
- );
5436
+ let mut rows = Vec::new();
5437
+ on_files(
5438
+ &mut std::iter::once(dir.path().join("f.a")),
5439
+ &mut |chunk| rows.extend(chunk),
5440
+ &mut || {},
5441
+ )
5442
+ .unwrap();
5443
+ assert_eq!(rows.len(), 1);
5408
5444
  assert!(tables[1].strict, "on-file table preserves strict flag");
5409
5445
  }
5410
5446
 
@@ -5574,6 +5610,7 @@ mod internal_tests {
5574
5610
  config_dir,
5575
5611
  root,
5576
5612
  &mut |chunk| rows.extend(chunk),
5613
+ &mut || {},
5577
5614
  )?;
5578
5615
  Ok(rows)
5579
5616
  }
@@ -5605,6 +5642,7 @@ mod internal_tests {
5605
5642
  dir.path(),
5606
5643
  dir.path(),
5607
5644
  &mut |chunk| chunks.push(chunk),
5645
+ &mut || {},
5608
5646
  )
5609
5647
  .expect("a well-formed payload parses");
5610
5648
  assert!(chunks.len() > 1, "{} invocation(s)", chunks.len());
@@ -5991,7 +6029,7 @@ mod internal_tests {
5991
6029
  "items",
5992
6030
  "CREATE TABLE items (name TEXT)",
5993
6031
  "*.txt",
5994
- move |_: &mut PathFeed<'_>, sink: &mut RowSink<'_>| hook(sink),
6032
+ move |_: &mut PathFeed<'_>, sink: &mut RowSink<'_>, _: &mut OutputEnd<'_>| hook(sink),
5995
6033
  )
5996
6034
  }
5997
6035
 
@@ -6421,6 +6459,69 @@ mod internal_tests {
6421
6459
  );
6422
6460
  }
6423
6461
 
6462
+ /// A per-table hook that answers `answer`'s name, ends its output, and
6463
+ /// then fails when `answer` says so.
6464
+ fn ending_per_table(answer: Arc<Mutex<(String, bool)>>) -> Table {
6465
+ Table::per_table_streaming(
6466
+ "items",
6467
+ "CREATE TABLE items (name TEXT)",
6468
+ "**/*.txt",
6469
+ move |_: &mut PathFeed<'_>, sink: &mut RowSink<'_>, end: &mut OutputEnd<'_>| {
6470
+ let (name, fails) = answer.lock().unwrap().clone();
6471
+ sink(vec![name_json_row(&name)]);
6472
+ end();
6473
+ if fails {
6474
+ return Err("exited 1".into());
6475
+ }
6476
+ Ok(())
6477
+ },
6478
+ )
6479
+ }
6480
+
6481
+ fn ending_hook_db(answer: &Arc<Mutex<(String, bool)>>) -> (TempDir, DirSQL, PathBuf) {
6482
+ let dir = TempDir::new().unwrap();
6483
+ let root = dir.path().to_path_buf();
6484
+ let a = root.join("a.txt");
6485
+ let fake = Arc::new(
6486
+ FakeFs::default().with_subtree(root.clone(), vec![(a.clone(), "items".into())]),
6487
+ );
6488
+ let items = ending_per_table(Arc::clone(answer));
6489
+ let db =
6490
+ DirSQL::with_ignore_and_fs(&root, vec![items], Vec::<String>::new(), fake).unwrap();
6491
+ db.apply_file_events(vec![FileEvent::Created(a.clone())]);
6492
+ (dir, db, a)
6493
+ }
6494
+
6495
+ #[test]
6496
+ fn a_per_table_hook_that_fails_after_ending_its_output_writes_nothing() {
6497
+ let answer = Arc::new(Mutex::new(("old".to_string(), false)));
6498
+ let (_dir, db, a) = ending_hook_db(&answer);
6499
+ *answer.lock().unwrap() = ("new".to_string(), true);
6500
+
6501
+ let events = db.apply_file_events(vec![FileEvent::Modified(a)]);
6502
+
6503
+ assert!(
6504
+ matches!(&events[..], [RowEvent::Error { error, .. }] if error.contains("exited 1")),
6505
+ "{events:?}"
6506
+ );
6507
+ assert_eq!(row_names(&db), vec!["old"]);
6508
+ }
6509
+
6510
+ #[test]
6511
+ fn a_per_table_hook_that_succeeds_after_ending_its_output_keeps_its_rows() {
6512
+ let answer = Arc::new(Mutex::new(("old".to_string(), false)));
6513
+ let (_dir, db, a) = ending_hook_db(&answer);
6514
+ *answer.lock().unwrap() = ("new".to_string(), false);
6515
+
6516
+ let events = db.apply_file_events(vec![FileEvent::Modified(a)]);
6517
+
6518
+ assert!(
6519
+ matches!(&events[..], [RowEvent::Update { .. }]),
6520
+ "{events:?}"
6521
+ );
6522
+ assert_eq!(row_names(&db), vec!["new"]);
6523
+ }
6524
+
6424
6525
  #[test]
6425
6526
  fn apply_file_events_writes_only_the_rows_a_per_table_refresh_changed() {
6426
6527
  let dir = TempDir::new().unwrap();