dirsql 0.4.109__tar.gz → 0.4.110__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.
- {dirsql-0.4.109 → dirsql-0.4.110}/Cargo.lock +2 -2
- {dirsql-0.4.109 → dirsql-0.4.110}/PKG-INFO +1 -1
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/Cargo.toml +1 -1
- dirsql-0.4.110/packages/python/e2e-attestations/bot-1464-fastest-native-1008.json +7 -0
- dirsql-0.4.110/packages/python/e2e-attestations/bot-1470-perf-suite-1009.json +7 -0
- dirsql-0.4.110/packages/python/tests/e2e/bench_report.py +97 -0
- dirsql-0.4.110/packages/python/tests/e2e/bench_suite.py +115 -0
- dirsql-0.4.110/packages/python/tests/e2e/speed_of_light.py +417 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/Cargo.toml +1 -1
- dirsql-0.4.109/packages/python/tests/e2e/speed_of_light.py +0 -205
- {dirsql-0.4.109 → dirsql-0.4.110}/Cargo.toml +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/README.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/__init__.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/_async.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/cli/discover_plugins/__init__.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/cli/discover_plugins/discovered_fragments.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/cli/discover_plugins/discovery_disabled.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/cli/discover_plugins/fragment_path.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/cli/discover_plugins/with_discovered_plugins.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/cli/main.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/cli/resolve_config_extensions.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/plan_entry_path.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/py.typed +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/read_config.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/resolve_configs_extension_specs.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/resolve_extension.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/dirsql/resolve_package.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/AGENTS.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/context/.gitattributes +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/context/recipes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/context/usage.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/explanation.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/getting-started.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/agent-skill.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/embed.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/persist.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/query-json.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/index.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/package.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/plugins.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/reference/cli.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/reference/columns.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/reference/config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/reference/glob.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/reference/hooks.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/reference/http-api.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/docs/reference/sdk.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/CHANGELOG.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/MIGRATIONS.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/README.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-07-13-plugin-discovery.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-07-13-repeatable-config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-08-02-release-profile.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-08-02-scan-failures.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-08-03-discovery-ext-resolution.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-08-03-manylinux-dynamic-binary.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-08-03-python-no-ignore.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-08-04-cast-lints.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-08-20-curtaincall-dev-dependency.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-04-config-paths-from-argv-module.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-05-config-extension-loader-split.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-05-resolve-config-extensions-split.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-05-resolve-extension-split.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-09-launcher-config-path-scan.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-17-extension-resolution-via-core.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-18-export-scan-failure.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-18-flatten-row-event-in-core.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-18-programmatic-extension-plan.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-02-readme-docs-host.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-03-path-table-directory-one-level.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-05-brace-groups-follow-bash.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-05-cli-context.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-05-gitignore-requires-repo.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-05-path-table-node-modules-named.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-05-path-table-symlinks.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-05-path-table-trailing-slash.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-05-unbalanced-brackets-literal.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-06-config-braces.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-06-config-directory.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-06-config-dotnames.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-06-config-gitignore.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-06-config-globs-anchor-at-the-config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-06-config-links.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-06-one-glob-compiler.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-06-plugin-no-default-records.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-06-watch-broadcast.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-06-zero-match-config-table-warning.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-07-bracket-slash-literal.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-07-dotdot-and-double-slashes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-07-dotdot-as-written.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-07-glob-walks-node-modules.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-07-literal-gitignore.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-07-on-file-ndjson.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-07-parallel-hooks.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-07-persist-cache-outside-root.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-07-posix-classes-unicode.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-07-spread-few-large-files.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-08-small-walks-stay-on-one-thread.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/2026-10-08-watch-requires-named-table.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/changelog.d/README.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/conftest.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/context/.gitattributes +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/context/recipes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/context/usage.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/explanation.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/agent-skill.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/embed.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/persist.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/query-json.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/index.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/package.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/plugins.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/reference/cli.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/reference/columns.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/reference/config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/reference/glob.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/reference/hooks.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/reference/http-api.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/docs/reference/sdk.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1334-listing-exemptions.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1397-watch-broadcast.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1398-inotify-error.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1399-server-cors.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1401-watch-scope.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1406-watch-no-tables-1008.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1407-child-place-depth.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1414-stat-speed.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1415-server-speed.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1416-watch-speed-1008.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1418-node-modules.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1419-dotdot-slashes.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1420-bracket-slash.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1421-posix-unicode.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1422-literal-gitignore.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1426-walk-spawn-threshold-1008.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1428-ndjson-hooks.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1429-parallel-hooks.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1430-dotdot-as-written.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1431-persist-cache-dir.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1437-test-cache-isolation.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1440-fix-main-build.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1448-wildcard-ignored-prefix.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1451-named-dir-never-hidden.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1454-split-few-files.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1457-incremental-refresh-1008.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1459-rescan-on-overflow-1008.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1461-row-footprint-1008.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-1462-paired-speed-harness-1008.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/bot-fix-main-place-depth-20261007.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/cc-keen-knuth-f11gyq.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1056-py-ofpf9.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1066-p1-resolve-extension.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1078-argv-config-paths-core.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1079-p2-resolve-config-extensions.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1080-share-vtab-scaffolding.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1081-indicatif-progress.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1096-watch-moved-dir.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1109-watch-moved-out.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1119-ext-plan.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1120-py-ext.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1122-ext-cleanup.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1130-codec-crates.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1131-flatten-row-event.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1139-sse-flatten.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1140-scan-failure-export.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1148-clippy-all-targets.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1164-sigint-fatal.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1170-projection-order.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1172-on-file-path.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1173-py-projection-order.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1184-win-rel-paths.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1185-win-abs-table-names.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1186-win-test-harness.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1196-join-index.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1199-glob-prefix.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1201-single-walk.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1204-embed-batch.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1207-win-argv-quote.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1208-win-nonverbatim-paths.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1215-on-file-batch.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1216-on-file-cleanup.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1223-config-glob-rule.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1223-dir-one-level.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1225-plugin-no-default.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1226-stale-docs.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1232-anchor-plumbing.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1232-config-anchor.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1232-multi-watch.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1232-zero-match.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1238-parallel-walk.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1241-content-prefetch.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1243-ingest-perf.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1249-dotfiles.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1256-symlinks.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1257-trailing-slash.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1258-config-braces.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1258-config-directory.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1258-config-dotnames.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1258-config-gitignore.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1258-config-links.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1258-one-pattern.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1262-brace-literal.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1264-context.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1267-posix-classes.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1268-unbalanced-brackets.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1269-utf8-chars.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1271-node-modules-named.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1272-ancestor-gitignore.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1273-walk-prune.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1285-ingest-fast.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1286-nested-repo.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1305-glob-speed.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1308-glob-speed.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1310-glob-speed.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1311-glob-speed.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1312-glob-speed.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1318-lazy-stat.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1320-walk-speed.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1322-walk-readdir.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1325-parallel-walk.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1326-stream-rows.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1330-python-dirsql-patch.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1330-python-extensions-patch.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1330-scanner-effects.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1330-scanner-gitignore.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1330-vtab-prefetch-flag.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1330-vtab-read.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-1351-dot-dirs.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-819-oneshot-timeout.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-827-unquote-doubled-quotes.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-epic-953-slice2-reedline.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-epic-953-slice3-format.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-epic-953-stacked-prs-x59wm3.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-github-issue-825-e4mhhp.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-issue-951-0eease.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-issue-962-0jjrfv.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-issue-986-red-test-e7sjrb.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-tackle-1034-cachesplit.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-tackle-1042-py12.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-tackle-956-xzen74.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6-worker-calls.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-tackle-957-lrm0z6.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/e2e-attestations/claude-tackle-975-n8mc2h.json +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-07-13-drop-cwd-config-auto-detect.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-07-13-rename-extract-to-on-file.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-07-13-sdk-default-baked-in-config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-07-20-drop-implicit-files-table.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-07-21-remove-glob-captures.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-07-24-hookless-table-config-error.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-07-24-remove-stat-fact-injection.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-07-29-restore-python-310.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-08-04-cli-in-process.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-08-20-declared-table-name.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-09-20-sigint-ends-a-run-in-progress.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-09-24-query-rows-in-projection-order.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-02-readme-docs-host.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-03-one-glob-rule-for-config-globs.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-03-path-table-directory-one-level.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-04-path-table-dotfiles-hidden.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-05-brace-groups-follow-bash.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-05-cli-context.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-05-gitignore-requires-repo.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-05-path-table-node-modules-named.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-05-path-table-symlinks.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-05-path-table-trailing-slash.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-05-unbalanced-brackets-literal.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-06-config-braces.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-06-config-directory.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-06-config-dotnames.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-06-config-gitignore.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-06-config-globs-anchor-at-the-config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-06-config-links.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-06-one-glob-compiler.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-06-plugin-no-default-records.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-06-watch-broadcast.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-06-zero-match-config-table-warning.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-07-bracket-slash-literal.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-07-dotdot-and-double-slashes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-07-dotdot-as-written.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-07-glob-walks-node-modules.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-07-literal-gitignore.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-07-on-file-ndjson.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-07-parallel-hooks.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-07-persist-cache-outside-root.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-07-posix-classes-unicode.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-07-spread-few-large-files.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-08-small-walks-stay-on-one-thread.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/2026-10-08-watch-requires-named-table.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/migrations.d/README.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/src/lib.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/testing-conventions.toml +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/__init__.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/tests/e2e/fixtures/dirsql_plugin_fixture/dirsql.toml +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/tests/integration/binding/__init__.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/python/tests/integration/hermetic/__init__.py +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/CHANGELOG.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/MIGRATIONS.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/README.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/context/.gitattributes +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/context/recipes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/context/troubleshooting.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/context/usage.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/explanation.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/agent-skill.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/columns-from-paths.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/define-tables.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/embed.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/extract-from-contents.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/load-extension.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/parse-files-into-columns.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/persist.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/query-json.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/query-without-config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/react-to-changes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/search-by-meaning.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/search-indexes.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/skip-files.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/howto/write-a-plugin.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/index.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/plugins.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/reference/cli.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/reference/columns.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/reference/config.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/reference/glob.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/reference/hooks.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/reference/http-api.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/reference/path-tables.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/docs/reference/sdk.md +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/brace.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/cli/context.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/cli/execute.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/cli/repl.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/cli/run.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/cli/table.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/command.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/config.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/db.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/default_config.toml +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/extension_resolution.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/functions.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/infer.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/launcher.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/lib.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/listing.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/on_file.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/parsed_vtab.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/path_table.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/posix_class.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/progress.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/row_event_flat.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/sql_literal.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/tree_walk.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/vtab.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/vtab_scaffold.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.4.109 → dirsql-0.4.110}/pyproject.toml +0 -0
|
@@ -573,7 +573,7 @@ dependencies = [
|
|
|
573
573
|
|
|
574
574
|
[[package]]
|
|
575
575
|
name = "dirsql"
|
|
576
|
-
version = "0.4.
|
|
576
|
+
version = "0.4.110"
|
|
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.
|
|
628
|
+
version = "0.4.110"
|
|
629
629
|
dependencies = [
|
|
630
630
|
"dirsql",
|
|
631
631
|
"pyo3",
|
|
@@ -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.
|
|
7
|
+
version = "0.4.110"
|
|
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,97 @@
|
|
|
1
|
+
"""Records, report and markdown for the performance suite (`just bench-suite`)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import statistics
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
RECORDS = "cases.jsonl"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def ratio_stats(ratios):
|
|
13
|
+
low, high = min(ratios), max(ratios)
|
|
14
|
+
median = statistics.median(ratios)
|
|
15
|
+
return {"min": low, "median": median, "max": high, "spread": (high - low) / median}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def case_record(name, result, startup):
|
|
19
|
+
natives = {}
|
|
20
|
+
for native, seconds in result.native_seconds.items():
|
|
21
|
+
net = [s - startup.native for s in seconds]
|
|
22
|
+
natives[native] = {
|
|
23
|
+
"native_median_s": statistics.median(seconds),
|
|
24
|
+
"ratio": ratio_stats(
|
|
25
|
+
[(d - startup.dirsql) / n for d, n in zip(result.dirsql_seconds, net)]
|
|
26
|
+
),
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
"name": name,
|
|
30
|
+
"pairs": len(result.dirsql_seconds),
|
|
31
|
+
"fastest": result.fastest,
|
|
32
|
+
"ratio_vs_fastest": natives[result.fastest]["ratio"]["median"],
|
|
33
|
+
"dirsql_median_s": statistics.median(result.dirsql_seconds),
|
|
34
|
+
"startup": {"dirsql": startup.dirsql, "native": startup.native},
|
|
35
|
+
"natives": natives,
|
|
36
|
+
"skipped": list(result.skipped),
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def build_report(records, meta):
|
|
41
|
+
return {**meta, "cases": sorted(records, key=lambda c: c["name"])}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def append_record(out, record):
|
|
45
|
+
with (Path(out) / RECORDS).open("a") as file:
|
|
46
|
+
file.write(json.dumps(record) + "\n")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def read_records(out):
|
|
50
|
+
lines = (Path(out) / RECORDS).read_text().splitlines()
|
|
51
|
+
return [json.loads(line) for line in lines]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def render_markdown(report):
|
|
55
|
+
machine = ", ".join(f"{k}: {v}" for k, v in report["machine"].items())
|
|
56
|
+
versions = ", ".join(f"{k}: {v}" for k, v in report["versions"].items())
|
|
57
|
+
lines = [
|
|
58
|
+
"# dirsql performance suite",
|
|
59
|
+
"",
|
|
60
|
+
f"- Commit: {report['commit']}",
|
|
61
|
+
f"- Date: {report['date']}",
|
|
62
|
+
f"- Machine: {machine}",
|
|
63
|
+
f"- Versions: {versions}",
|
|
64
|
+
(
|
|
65
|
+
f"- Method: {report['pairs']} paired runs per case, interleaved; ratios"
|
|
66
|
+
" are dirsql over the native after each side's startup, median across"
|
|
67
|
+
" pairs"
|
|
68
|
+
),
|
|
69
|
+
"",
|
|
70
|
+
"| Case | Fastest native | dirsql / fastest | Spread | vs 1.0x |",
|
|
71
|
+
"|---|---|---|---|---|",
|
|
72
|
+
]
|
|
73
|
+
for case in report["cases"]:
|
|
74
|
+
stats = case["natives"][case["fastest"]]["ratio"]
|
|
75
|
+
verdict = "over" if case["ratio_vs_fastest"] > 1.0 else "ok"
|
|
76
|
+
lines.append(
|
|
77
|
+
f"| {case['name']} | {case['fastest']} | {case['ratio_vs_fastest']:.2f}x"
|
|
78
|
+
f" | {stats['spread']:.0%} | {verdict} |"
|
|
79
|
+
)
|
|
80
|
+
for case in report["cases"]:
|
|
81
|
+
lines += [
|
|
82
|
+
"",
|
|
83
|
+
f"## {case['name']}",
|
|
84
|
+
"",
|
|
85
|
+
f"dirsql median {case['dirsql_median_s']:.3f}s",
|
|
86
|
+
"",
|
|
87
|
+
"| Native | Median s | dirsql / native | Min | Max | Spread |",
|
|
88
|
+
"|---|---|---|---|---|---|",
|
|
89
|
+
]
|
|
90
|
+
for native, data in sorted(case["natives"].items()):
|
|
91
|
+
r = data["ratio"]
|
|
92
|
+
lines.append(
|
|
93
|
+
f"| {native} | {data['native_median_s']:.3f} | {r['median']:.2f}x"
|
|
94
|
+
f" | {r['min']:.2f}x | {r['max']:.2f}x | {r['spread']:.0%} |"
|
|
95
|
+
)
|
|
96
|
+
lines += [f"- {tool} (not installed)" for tool in case["skipped"]]
|
|
97
|
+
return "\n".join(lines) + "\n"
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Entry point for `just bench-suite`.
|
|
2
|
+
|
|
3
|
+
Runs every speed-of-light case with every native timed in each paired,
|
|
4
|
+
interleaved run, then writes `report.json` and `report.md` beside the raw
|
|
5
|
+
per-case records. The cases are the e2e tests themselves, so the suite and the
|
|
6
|
+
ratchet never disagree on what a case is.
|
|
7
|
+
|
|
8
|
+
python -m tests.e2e.bench_suite --pairs 100 --out /tmp/bench [-k expr]
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import datetime
|
|
15
|
+
import json
|
|
16
|
+
import os
|
|
17
|
+
import platform
|
|
18
|
+
import shutil
|
|
19
|
+
import subprocess
|
|
20
|
+
import sys
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from .bench_report import build_report, read_records, render_markdown
|
|
24
|
+
|
|
25
|
+
HERE = Path(__file__).parent
|
|
26
|
+
TOOLS = (
|
|
27
|
+
("bash", ["bash", "--version"]),
|
|
28
|
+
("find", ["find", "--version"]),
|
|
29
|
+
("fd", ["fd", "--version"]),
|
|
30
|
+
("rg", ["rg", "--version"]),
|
|
31
|
+
("xargs", ["xargs", "--version"]),
|
|
32
|
+
("inotifywait", ["inotifywait", "--help"]),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def case_files(directory=HERE):
|
|
37
|
+
return sorted(
|
|
38
|
+
path
|
|
39
|
+
for path in directory.glob("*_test.py")
|
|
40
|
+
if "assert_speed_of_light" in path.read_text()
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def first_line(argv):
|
|
45
|
+
if shutil.which(argv[0]) is None:
|
|
46
|
+
return None
|
|
47
|
+
proc = subprocess.run(argv, capture_output=True, text=True, check=False)
|
|
48
|
+
lines = (proc.stdout or proc.stderr).splitlines()
|
|
49
|
+
return lines[0].strip() if lines else None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def cpu_model():
|
|
53
|
+
try:
|
|
54
|
+
for line in Path("/proc/cpuinfo").read_text().splitlines():
|
|
55
|
+
if line.startswith("model name"):
|
|
56
|
+
return line.split(":", 1)[1].strip()
|
|
57
|
+
except OSError:
|
|
58
|
+
pass
|
|
59
|
+
return platform.processor() or "unknown"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def git_commit():
|
|
63
|
+
proc = subprocess.run(
|
|
64
|
+
["git", "rev-parse", "HEAD"], capture_output=True, text=True, check=False
|
|
65
|
+
)
|
|
66
|
+
return proc.stdout.strip() or "unknown"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def metadata(pairs):
|
|
70
|
+
versions = {}
|
|
71
|
+
for name, argv in TOOLS:
|
|
72
|
+
versions[name] = first_line(argv)
|
|
73
|
+
return {
|
|
74
|
+
"commit": git_commit(),
|
|
75
|
+
"date": datetime.datetime.now(datetime.timezone.utc).strftime(
|
|
76
|
+
"%Y-%m-%dT%H:%M:%SZ"
|
|
77
|
+
),
|
|
78
|
+
"machine": {
|
|
79
|
+
"platform": platform.platform(),
|
|
80
|
+
"cpu": cpu_model(),
|
|
81
|
+
"cpus": os.cpu_count(),
|
|
82
|
+
},
|
|
83
|
+
"versions": {k: v for k, v in versions.items() if v},
|
|
84
|
+
"pairs": pairs,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def main(argv=None):
|
|
89
|
+
parser = argparse.ArgumentParser()
|
|
90
|
+
parser.add_argument("--pairs", type=int, default=100)
|
|
91
|
+
parser.add_argument("--out", type=Path, required=True)
|
|
92
|
+
parser.add_argument("-k", default="")
|
|
93
|
+
args = parser.parse_args(argv)
|
|
94
|
+
args.out.mkdir(parents=True, exist_ok=True)
|
|
95
|
+
(args.out / "cases.jsonl").unlink(missing_ok=True)
|
|
96
|
+
env = {
|
|
97
|
+
**os.environ,
|
|
98
|
+
"DIRSQL_BENCH_PAIRS": str(args.pairs),
|
|
99
|
+
"DIRSQL_BENCH_OUT": str(args.out),
|
|
100
|
+
}
|
|
101
|
+
pytest = [sys.executable, "-m", "pytest", "-q", "-s", "-p", "no:cacheprovider"]
|
|
102
|
+
if args.k:
|
|
103
|
+
pytest += ["-k", args.k]
|
|
104
|
+
code = subprocess.run(
|
|
105
|
+
pytest + [str(p) for p in case_files()], env=env, check=False
|
|
106
|
+
).returncode
|
|
107
|
+
report = build_report(read_records(args.out), metadata(args.pairs))
|
|
108
|
+
(args.out / "report.json").write_text(json.dumps(report, indent=2) + "\n")
|
|
109
|
+
(args.out / "report.md").write_text(render_markdown(report))
|
|
110
|
+
print(f"wrote {args.out}/report.json and {args.out}/report.md")
|
|
111
|
+
return code
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__":
|
|
115
|
+
sys.exit(main())
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"""Harness for the use-case speed-of-light tests.
|
|
2
|
+
|
|
3
|
+
Each test asks one question of a generated corpus through every plausible
|
|
4
|
+
native pipeline (find, fd, rg, xargs -P, a single parser process) and once
|
|
5
|
+
through the real `dirsql` launcher. Every native's rows must equal dirsql's.
|
|
6
|
+
dirsql's wall time, after subtracting the launcher's measured startup, must be
|
|
7
|
+
within ten percent of the case's bar native, `find` or the case's own first
|
|
8
|
+
native unless the case passes `bar=FASTEST`. The fastest native's ratio is
|
|
9
|
+
printed either way. The bar is a ratio, never a millisecond number, so it holds
|
|
10
|
+
on any machine. A native whose tool is not installed is printed as SKIPPED,
|
|
11
|
+
never dropped quietly.
|
|
12
|
+
|
|
13
|
+
A few screening pairs time every native to find the fastest; the measured
|
|
14
|
+
pairs then run only the fastest and the bar native. Pairs alternate (natives
|
|
15
|
+
first, then dirsql first, and so on) after one discarded warm-up pair, so
|
|
16
|
+
drift in machine speed hits every side alike. The verdict is the median of the
|
|
17
|
+
per-pair ratios. Startup is the median of `dirsql query 'SELECT 1'` runs with
|
|
18
|
+
the first dropped, and native's own is the median of `bash -c true` the same
|
|
19
|
+
way; each is subtracted from its side. A corpus too small to time is grown by
|
|
20
|
+
doubling until the native pipeline takes a second, unless the corpus ceiling
|
|
21
|
+
stops it sooner.
|
|
22
|
+
Output is captured as bytes and decoded after the clock stops.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import json
|
|
28
|
+
import os
|
|
29
|
+
import shutil
|
|
30
|
+
import statistics
|
|
31
|
+
import subprocess
|
|
32
|
+
import tempfile
|
|
33
|
+
import time
|
|
34
|
+
from collections.abc import Callable
|
|
35
|
+
from dataclasses import dataclass, field
|
|
36
|
+
from typing import NamedTuple
|
|
37
|
+
|
|
38
|
+
from .bench_report import append_record, case_record
|
|
39
|
+
|
|
40
|
+
ONE_SECOND = 1.0
|
|
41
|
+
TOLERANCE = 1.1
|
|
42
|
+
STARTUP_PROBES = 11
|
|
43
|
+
PAIRS = 15
|
|
44
|
+
SCREEN_PAIRS = 5
|
|
45
|
+
FASTEST = "fastest"
|
|
46
|
+
HOPELESS_STREAK = 3
|
|
47
|
+
NATIVE_ENV = {**os.environ, "LC_ALL": "C"}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class Startup(NamedTuple):
|
|
51
|
+
dirsql: float
|
|
52
|
+
native: float
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class Native(NamedTuple):
|
|
56
|
+
"""One native pipeline. `needs` lists the names its tool goes by, first
|
|
57
|
+
installed wins; `script` has `{bin}` where that name goes."""
|
|
58
|
+
|
|
59
|
+
name: str
|
|
60
|
+
needs: tuple
|
|
61
|
+
script: str
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Natives(NamedTuple):
|
|
65
|
+
"""`bar` names the native dirsql is held to: the first one by default, or
|
|
66
|
+
`FASTEST`."""
|
|
67
|
+
|
|
68
|
+
runs: dict
|
|
69
|
+
skipped: list
|
|
70
|
+
bar: str = ""
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class Series(NamedTuple):
|
|
74
|
+
rows: dict
|
|
75
|
+
dirsql_rows: object
|
|
76
|
+
native_seconds: dict
|
|
77
|
+
dirsql_seconds: list
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class Paired:
|
|
82
|
+
native_rows: dict
|
|
83
|
+
dirsql_rows: object
|
|
84
|
+
native_seconds: dict
|
|
85
|
+
dirsql_seconds: list
|
|
86
|
+
skipped: list
|
|
87
|
+
screen_seconds: dict = field(default_factory=dict)
|
|
88
|
+
screen_dirsql: list = field(default_factory=list)
|
|
89
|
+
fastest: str = ""
|
|
90
|
+
bar: str = ""
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def suite_pairs():
|
|
94
|
+
"""The pair count when `just bench-suite` drives the run, else None."""
|
|
95
|
+
count = os.environ.get("DIRSQL_BENCH_PAIRS")
|
|
96
|
+
return int(count) if count and os.environ.get("DIRSQL_BENCH_OUT") else None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def suite_only(*specs):
|
|
100
|
+
"""Natives the performance suite times that the e2e ratchet does not."""
|
|
101
|
+
return list(specs) if suite_pairs() else []
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def cli() -> str:
|
|
105
|
+
dirsql = shutil.which("dirsql")
|
|
106
|
+
assert dirsql is not None, (
|
|
107
|
+
"`dirsql` console script not on PATH -- run `uv run maturin develop`"
|
|
108
|
+
)
|
|
109
|
+
return dirsql
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def timed(argv, cwd, timeout, env=None):
|
|
113
|
+
started = time.perf_counter()
|
|
114
|
+
proc = subprocess.run(
|
|
115
|
+
argv,
|
|
116
|
+
cwd=str(cwd),
|
|
117
|
+
stdin=subprocess.DEVNULL,
|
|
118
|
+
capture_output=True,
|
|
119
|
+
timeout=timeout,
|
|
120
|
+
env=env,
|
|
121
|
+
check=False,
|
|
122
|
+
)
|
|
123
|
+
seconds = time.perf_counter() - started
|
|
124
|
+
proc.stdout = proc.stdout.decode()
|
|
125
|
+
proc.stderr = proc.stderr.decode()
|
|
126
|
+
return proc, seconds
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def timed_native(argv, cwd, timeout=600):
|
|
130
|
+
return timed(argv, cwd, timeout, env=NATIVE_ENV)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def sorted_lines(proc):
|
|
134
|
+
return sorted(proc.stdout.splitlines())
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def resolve_natives(specs, which=shutil.which):
|
|
138
|
+
runnable, skipped = [], []
|
|
139
|
+
for spec in specs:
|
|
140
|
+
binary = next((n for n in spec.needs if which(n)), None)
|
|
141
|
+
if binary is None:
|
|
142
|
+
skipped.append(spec.name)
|
|
143
|
+
else:
|
|
144
|
+
runnable.append((spec.name, spec.script.replace("{bin}", binary)))
|
|
145
|
+
assert runnable, f"no native installed: {[s.name for s in specs]}"
|
|
146
|
+
return runnable, skipped
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def shell_natives(root, specs, parse=sorted_lines, shell="bash", bar="") -> Natives:
|
|
150
|
+
def runner(script):
|
|
151
|
+
def run():
|
|
152
|
+
proc, seconds = timed_native([shell, "-c", script], root)
|
|
153
|
+
assert proc.returncode == 0, proc.stderr
|
|
154
|
+
return parse(proc), seconds
|
|
155
|
+
|
|
156
|
+
return run
|
|
157
|
+
|
|
158
|
+
runnable, skipped = resolve_natives(specs)
|
|
159
|
+
return Natives({name: runner(script) for name, script in runnable}, skipped, bar)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
AGG_AWK = (
|
|
163
|
+
'{ n[$1]++; s[$1] += $2 } END { for (k in n) print k "\\t" n[k] "\\t" s[k] }\n'
|
|
164
|
+
)
|
|
165
|
+
MERGE_AWK = (
|
|
166
|
+
'{ n[$1] += $2; s[$1] += $3 } END { for (k in n) print k "\\t" n[k] "\\t" s[k] }\n'
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def fd(args):
|
|
171
|
+
return Native("fd", ("fd", "fdfind"), "{bin} --no-ignore --type f " + args)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def rg(args):
|
|
175
|
+
return Native("rg", ("rg",), "{bin} --files --no-ignore " + args)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def globstar(pattern):
|
|
179
|
+
trim = "cut -c3-" if pattern.startswith("./") else "cat"
|
|
180
|
+
return Native(
|
|
181
|
+
"bash-globstar",
|
|
182
|
+
("bash",),
|
|
183
|
+
'{bin} -O globstar -O nullglob -c \'printf "%s\\n" ' + pattern + f"' | {trim}",
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def baseline(natives: Natives) -> Callable:
|
|
188
|
+
return next(iter(natives.runs.values()))
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def median_after_first(samples):
|
|
192
|
+
return statistics.median(samples[1:])
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def probe_seconds(argv, cwd, env=None) -> float:
|
|
196
|
+
samples = []
|
|
197
|
+
for _ in range(STARTUP_PROBES):
|
|
198
|
+
proc, seconds = timed(argv, cwd, timeout=60, env=env)
|
|
199
|
+
assert proc.returncode == 0, proc.stderr
|
|
200
|
+
samples.append(seconds)
|
|
201
|
+
return median_after_first(samples)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def startup_seconds(argv=None, cwd=None) -> Startup:
|
|
205
|
+
argv = [cli(), "query", "SELECT 1"] if argv is None else argv
|
|
206
|
+
with tempfile.TemporaryDirectory() as empty:
|
|
207
|
+
dirsql = probe_seconds(argv, cwd or empty)
|
|
208
|
+
native = probe_seconds(["bash", "-c", "true"], empty, NATIVE_ENV)
|
|
209
|
+
return Startup(dirsql, native)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def dirsql_rows(proc, columns):
|
|
213
|
+
assert proc.returncode == 0, (
|
|
214
|
+
f"dirsql failed: stdout={proc.stdout!r} stderr={proc.stderr!r}"
|
|
215
|
+
)
|
|
216
|
+
return [tuple(row[column] for column in columns) for row in json.loads(proc.stdout)]
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def grow_until_native_takes_a_second(build, native, start, ceiling):
|
|
220
|
+
"""Grow the corpus by doubling until `native` runs for a second.
|
|
221
|
+
|
|
222
|
+
`build(lo, hi)` adds items `lo` through `hi - 1` to the corpus already
|
|
223
|
+
holding `lo` items, so each doubling writes only the new half.
|
|
224
|
+
"""
|
|
225
|
+
built, size = 0, start
|
|
226
|
+
while True:
|
|
227
|
+
build(built, size)
|
|
228
|
+
os.sync()
|
|
229
|
+
built = size
|
|
230
|
+
_, seconds = native()
|
|
231
|
+
if seconds >= ONE_SECOND or size >= ceiling:
|
|
232
|
+
return size
|
|
233
|
+
size *= 2
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def dirsql_timeout(native_seconds: float) -> float:
|
|
237
|
+
return max(60.0, 30 * native_seconds)
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def pair_ratios(native_seconds, dirsql_seconds, startup):
|
|
241
|
+
ratios = []
|
|
242
|
+
for native, dirsql in zip(native_seconds, dirsql_seconds):
|
|
243
|
+
net = native - startup.native
|
|
244
|
+
assert net > 0, (
|
|
245
|
+
f"native {native:.3f}s is under its startup {startup.native:.3f}s"
|
|
246
|
+
)
|
|
247
|
+
ratios.append((dirsql - startup.dirsql) / net)
|
|
248
|
+
return ratios
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def is_hopeless(native, dirsql, startup):
|
|
252
|
+
return dirsql - startup.dirsql > 10 * TOLERANCE * (native - startup.native)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def run_or_fail(run, name):
|
|
256
|
+
try:
|
|
257
|
+
return run()
|
|
258
|
+
except subprocess.TimeoutExpired as expired:
|
|
259
|
+
raise AssertionError(
|
|
260
|
+
f"{name} did not finish within {expired.timeout:.0f}s"
|
|
261
|
+
) from None
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def paired(natives, dirsql, startup, pairs=PAIRS, screen=SCREEN_PAIRS):
|
|
265
|
+
"""Screen every native, then time dirsql against the bar and the fastest.
|
|
266
|
+
|
|
267
|
+
The first pair is a discarded warm-up that also sets dirsql's timeout.
|
|
268
|
+
`screen` alternating pairs run every native to find the fastest by median
|
|
269
|
+
time; `pairs` alternating pairs then run only the fastest and the bar
|
|
270
|
+
native (the same one unless the bar is pinned elsewhere). A run that
|
|
271
|
+
raises `TimeoutExpired` fails the test at once. Three hopeless pairs in a
|
|
272
|
+
row, judged against the pair's fastest native, end the measured series
|
|
273
|
+
early: noise does not account for an order of magnitude, so more pairs
|
|
274
|
+
cannot bring the median under the bar.
|
|
275
|
+
"""
|
|
276
|
+
runs = natives.runs
|
|
277
|
+
rows = {}
|
|
278
|
+
warm = []
|
|
279
|
+
for name, run in runs.items():
|
|
280
|
+
rows[name], seconds = run_or_fail(run, name)
|
|
281
|
+
warm.append(seconds)
|
|
282
|
+
timeout = dirsql_timeout(max(warm))
|
|
283
|
+
|
|
284
|
+
def run_dirsql():
|
|
285
|
+
return run_or_fail(lambda: dirsql(timeout), "dirsql")
|
|
286
|
+
|
|
287
|
+
run_dirsql()
|
|
288
|
+
everyone = suite_pairs()
|
|
289
|
+
if everyone:
|
|
290
|
+
result = run_pairs(runs, run_dirsql, everyone)
|
|
291
|
+
fastest = fastest_by_median(result.native_seconds)
|
|
292
|
+
return Paired(
|
|
293
|
+
{**rows, **result.rows},
|
|
294
|
+
result.dirsql_rows,
|
|
295
|
+
result.native_seconds,
|
|
296
|
+
result.dirsql_seconds,
|
|
297
|
+
natives.skipped,
|
|
298
|
+
fastest=fastest,
|
|
299
|
+
bar=fastest,
|
|
300
|
+
)
|
|
301
|
+
screened = run_pairs(runs, run_dirsql, screen)
|
|
302
|
+
rows.update(screened.rows)
|
|
303
|
+
fastest = fastest_by_median(screened.native_seconds)
|
|
304
|
+
bar = fastest if natives.bar == FASTEST else natives.bar or next(iter(runs))
|
|
305
|
+
measured = {name: runs[name] for name in dict.fromkeys([fastest, bar])}
|
|
306
|
+
result = run_pairs(measured, run_dirsql, pairs, startup)
|
|
307
|
+
rows.update(result.rows)
|
|
308
|
+
return Paired(
|
|
309
|
+
rows,
|
|
310
|
+
result.dirsql_rows,
|
|
311
|
+
result.native_seconds,
|
|
312
|
+
result.dirsql_seconds,
|
|
313
|
+
natives.skipped,
|
|
314
|
+
screened.native_seconds,
|
|
315
|
+
screened.dirsql_seconds,
|
|
316
|
+
fastest,
|
|
317
|
+
bar,
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def run_pairs(runs, run_dirsql, count, startup=None):
|
|
322
|
+
"""Alternate every run in `runs` with dirsql, runs first on even pairs."""
|
|
323
|
+
rows = {}
|
|
324
|
+
dirsql_rows_ = None
|
|
325
|
+
native_times = {name: [] for name in runs}
|
|
326
|
+
dirsql_times, streak = [], 0
|
|
327
|
+
for index in range(count):
|
|
328
|
+
order = list(runs)
|
|
329
|
+
if index % 2:
|
|
330
|
+
order.reverse()
|
|
331
|
+
this_pair = {}
|
|
332
|
+
if index % 2 == 0:
|
|
333
|
+
for name in order:
|
|
334
|
+
rows[name], this_pair[name] = run_or_fail(runs[name], name)
|
|
335
|
+
dirsql_rows_, dirsql_seconds = run_dirsql()
|
|
336
|
+
else:
|
|
337
|
+
dirsql_rows_, dirsql_seconds = run_dirsql()
|
|
338
|
+
for name in order:
|
|
339
|
+
rows[name], this_pair[name] = run_or_fail(runs[name], name)
|
|
340
|
+
for name, seconds in this_pair.items():
|
|
341
|
+
native_times[name].append(seconds)
|
|
342
|
+
dirsql_times.append(dirsql_seconds)
|
|
343
|
+
if startup is None:
|
|
344
|
+
continue
|
|
345
|
+
hopeless = is_hopeless(min(this_pair.values()), dirsql_seconds, startup)
|
|
346
|
+
streak = streak + 1 if hopeless else 0
|
|
347
|
+
if streak == HOPELESS_STREAK:
|
|
348
|
+
break
|
|
349
|
+
return Series(rows, dirsql_rows_, native_times, dirsql_times)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def summarize(ratios):
|
|
353
|
+
low, high = min(ratios), max(ratios)
|
|
354
|
+
median = statistics.median(ratios)
|
|
355
|
+
return low, median, high, (high - low) / median
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def fastest_by_median(native_seconds):
|
|
359
|
+
return min(native_seconds, key=lambda name: statistics.median(native_seconds[name]))
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def agreed_rows(result):
|
|
363
|
+
names = list(result.native_rows)
|
|
364
|
+
first = names[0]
|
|
365
|
+
for name in names[1:]:
|
|
366
|
+
assert result.native_rows[name] == result.native_rows[first], (
|
|
367
|
+
f"{name} disagrees with {first}"
|
|
368
|
+
)
|
|
369
|
+
return result.native_rows[first]
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def ratio_line(label, native, native_seconds, dirsql_seconds, startup):
|
|
373
|
+
ratios = pair_ratios(native_seconds, dirsql_seconds, startup)
|
|
374
|
+
low, median, high, spread = summarize(ratios)
|
|
375
|
+
line = (
|
|
376
|
+
f"{label} vs {native}: {len(ratios)} pairs, ratio min {low:.3f}"
|
|
377
|
+
f" median {median:.3f} max {high:.3f} spread {spread:.0%}, native"
|
|
378
|
+
f" median {statistics.median(native_seconds):.3f}s"
|
|
379
|
+
)
|
|
380
|
+
return median, line
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def assert_speed_of_light(name, result, startup):
|
|
384
|
+
"""Print every native's screening time and ratio, then hold dirsql to the bar.
|
|
385
|
+
|
|
386
|
+
The bar is `result.bar`; the fastest native's ratio is printed beside it
|
|
387
|
+
and not asserted unless the bar is that native. Under `just bench-suite`
|
|
388
|
+
the case is recorded and nothing is asserted: the suite reports.
|
|
389
|
+
"""
|
|
390
|
+
if suite_pairs():
|
|
391
|
+
append_record(
|
|
392
|
+
os.environ["DIRSQL_BENCH_OUT"], case_record(name, result, startup)
|
|
393
|
+
)
|
|
394
|
+
return
|
|
395
|
+
lines = []
|
|
396
|
+
for native, seconds in result.screen_seconds.items():
|
|
397
|
+
_, line = ratio_line(
|
|
398
|
+
f"{name} screen", native, seconds, result.screen_dirsql, startup
|
|
399
|
+
)
|
|
400
|
+
lines.append(line + (" [fastest]" if native == result.fastest else ""))
|
|
401
|
+
lines.extend(f"{name}: SKIPPED {tool} (not installed)" for tool in result.skipped)
|
|
402
|
+
verdicts = {}
|
|
403
|
+
for role, native in (("bar", result.bar), ("fastest", result.fastest)):
|
|
404
|
+
verdicts[role] = ratio_line(
|
|
405
|
+
name, native, result.native_seconds[native], result.dirsql_seconds, startup
|
|
406
|
+
)
|
|
407
|
+
lines.append(f"{role} {verdicts[role][1]}")
|
|
408
|
+
lines.append(
|
|
409
|
+
f"{name}: startup dirsql {startup.dirsql:.3f}s native {startup.native:.3f}s,"
|
|
410
|
+
f" load {os.getloadavg()[0]:.1f}"
|
|
411
|
+
)
|
|
412
|
+
for line in lines:
|
|
413
|
+
print(f"SPEED {line}")
|
|
414
|
+
median, line = verdicts["bar"]
|
|
415
|
+
assert median <= TOLERANCE, (
|
|
416
|
+
f"bar native {result.bar}: {line}; median is over {TOLERANCE}x"
|
|
417
|
+
)
|
|
@@ -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.
|
|
9
|
+
version = "0.4.110"
|
|
10
10
|
edition.workspace = true
|
|
11
11
|
# Literal `license` (not `license.workspace = true`) because
|
|
12
12
|
# putitoutthere's preflight check reads `[package].license` directly
|