indexpilot 1.1.0a2__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.
- indexpilot-1.1.0a2/LICENSE +21 -0
- indexpilot-1.1.0a2/PKG-INFO +389 -0
- indexpilot-1.1.0a2/README.md +340 -0
- indexpilot-1.1.0a2/indexpilot/__init__.py +40 -0
- indexpilot-1.1.0a2/indexpilot/__main__.py +6 -0
- indexpilot-1.1.0a2/indexpilot/cli.py +502 -0
- indexpilot-1.1.0a2/indexpilot.egg-info/PKG-INFO +389 -0
- indexpilot-1.1.0a2/indexpilot.egg-info/SOURCES.txt +132 -0
- indexpilot-1.1.0a2/indexpilot.egg-info/dependency_links.txt +1 -0
- indexpilot-1.1.0a2/indexpilot.egg-info/entry_points.txt +8 -0
- indexpilot-1.1.0a2/indexpilot.egg-info/requires.txt +26 -0
- indexpilot-1.1.0a2/indexpilot.egg-info/top_level.txt +2 -0
- indexpilot-1.1.0a2/pyproject.toml +75 -0
- indexpilot-1.1.0a2/setup.cfg +4 -0
- indexpilot-1.1.0a2/src/__init__.py +1 -0
- indexpilot-1.1.0a2/src/adapters.py +805 -0
- indexpilot-1.1.0a2/src/adaptive_safeguards.py +369 -0
- indexpilot-1.1.0a2/src/algorithm_tracking.py +131 -0
- indexpilot-1.1.0a2/src/algorithms/__init__.py +85 -0
- indexpilot-1.1.0a2/src/algorithms/alex.py +398 -0
- indexpilot-1.1.0a2/src/algorithms/bx_tree.py +340 -0
- indexpilot-1.1.0a2/src/algorithms/cert.py +157 -0
- indexpilot-1.1.0a2/src/algorithms/constraint_optimizer.py +609 -0
- indexpilot-1.1.0a2/src/algorithms/cortex.py +417 -0
- indexpilot-1.1.0a2/src/algorithms/fractal_tree.py +374 -0
- indexpilot-1.1.0a2/src/algorithms/idistance.py +479 -0
- indexpilot-1.1.0a2/src/algorithms/pgm_index.py +378 -0
- indexpilot-1.1.0a2/src/algorithms/predictive_indexing.py +675 -0
- indexpilot-1.1.0a2/src/algorithms/qpg.py +512 -0
- indexpilot-1.1.0a2/src/algorithms/radix_string_spline.py +480 -0
- indexpilot-1.1.0a2/src/algorithms/xgboost_classifier.py +713 -0
- indexpilot-1.1.0a2/src/api_auth.py +62 -0
- indexpilot-1.1.0a2/src/api_server.py +891 -0
- indexpilot-1.1.0a2/src/approval_workflow.py +396 -0
- indexpilot-1.1.0a2/src/audit.py +357 -0
- indexpilot-1.1.0a2/src/auto_indexer.py +3011 -0
- indexpilot-1.1.0a2/src/before_after_validation.py +207 -0
- indexpilot-1.1.0a2/src/bypass_config.py +61 -0
- indexpilot-1.1.0a2/src/bypass_status.py +171 -0
- indexpilot-1.1.0a2/src/composite_index_detection.py +465 -0
- indexpilot-1.1.0a2/src/concurrent_index_monitoring.py +299 -0
- indexpilot-1.1.0a2/src/config_loader.py +398 -0
- indexpilot-1.1.0a2/src/cpu_throttle.py +413 -0
- indexpilot-1.1.0a2/src/database/__init__.py +31 -0
- indexpilot-1.1.0a2/src/database/adapters/__init__.py +9 -0
- indexpilot-1.1.0a2/src/database/adapters/base.py +115 -0
- indexpilot-1.1.0a2/src/database/adapters/postgresql.py +89 -0
- indexpilot-1.1.0a2/src/database/detector.py +48 -0
- indexpilot-1.1.0a2/src/database/type_detector.py +160 -0
- indexpilot-1.1.0a2/src/db.py +450 -0
- indexpilot-1.1.0a2/src/error_handler.py +271 -0
- indexpilot-1.1.0a2/src/expression.py +188 -0
- indexpilot-1.1.0a2/src/foreign_key_suggestions.py +315 -0
- indexpilot-1.1.0a2/src/genome.py +188 -0
- indexpilot-1.1.0a2/src/graceful_shutdown.py +212 -0
- indexpilot-1.1.0a2/src/health_check.py +251 -0
- indexpilot-1.1.0a2/src/index_cleanup.py +223 -0
- indexpilot-1.1.0a2/src/index_health.py +204 -0
- indexpilot-1.1.0a2/src/index_lifecycle_advanced.py +722 -0
- indexpilot-1.1.0a2/src/index_lifecycle_manager.py +971 -0
- indexpilot-1.1.0a2/src/index_retry.py +244 -0
- indexpilot-1.1.0a2/src/index_type_selection.py +750 -0
- indexpilot-1.1.0a2/src/lock_manager.py +332 -0
- indexpilot-1.1.0a2/src/maintenance.py +1211 -0
- indexpilot-1.1.0a2/src/maintenance_window.py +274 -0
- indexpilot-1.1.0a2/src/materialized_view_support.py +270 -0
- indexpilot-1.1.0a2/src/memory_config.py +234 -0
- indexpilot-1.1.0a2/src/ml_query_interception.py +324 -0
- indexpilot-1.1.0a2/src/monitoring.py +267 -0
- indexpilot-1.1.0a2/src/paths.py +27 -0
- indexpilot-1.1.0a2/src/pattern_detection.py +521 -0
- indexpilot-1.1.0a2/src/per_tenant_config.py +246 -0
- indexpilot-1.1.0a2/src/production_cache.py +421 -0
- indexpilot-1.1.0a2/src/production_config.py +222 -0
- indexpilot-1.1.0a2/src/query_analyzer.py +1041 -0
- indexpilot-1.1.0a2/src/query_executor.py +354 -0
- indexpilot-1.1.0a2/src/query_interceptor.py +1044 -0
- indexpilot-1.1.0a2/src/query_pattern_learning.py +474 -0
- indexpilot-1.1.0a2/src/query_patterns.py +183 -0
- indexpilot-1.1.0a2/src/query_timeout.py +114 -0
- indexpilot-1.1.0a2/src/rate_limiter.py +257 -0
- indexpilot-1.1.0a2/src/redundant_index_detection.py +89 -0
- indexpilot-1.1.0a2/src/resilience.py +510 -0
- indexpilot-1.1.0a2/src/rollback.py +435 -0
- indexpilot-1.1.0a2/src/safeguard_monitoring.py +163 -0
- indexpilot-1.1.0a2/src/scaled_reporting.py +895 -0
- indexpilot-1.1.0a2/src/schema/__init__.py +38 -0
- indexpilot-1.1.0a2/src/schema/auto_discovery.py +404 -0
- indexpilot-1.1.0a2/src/schema/change_detection.py +226 -0
- indexpilot-1.1.0a2/src/schema/discovery.py +129 -0
- indexpilot-1.1.0a2/src/schema/initialization.py +468 -0
- indexpilot-1.1.0a2/src/schema/loader.py +282 -0
- indexpilot-1.1.0a2/src/schema/validator.py +195 -0
- indexpilot-1.1.0a2/src/schema_evolution.py +1463 -0
- indexpilot-1.1.0a2/src/simulation/__init__.py +35 -0
- indexpilot-1.1.0a2/src/simulation/advanced_simulation.py +369 -0
- indexpilot-1.1.0a2/src/simulation/simulation_enhancements.py +197 -0
- indexpilot-1.1.0a2/src/simulation/simulation_verification.py +979 -0
- indexpilot-1.1.0a2/src/simulation/simulator.py +2373 -0
- indexpilot-1.1.0a2/src/simulation/stock_simulator.py +309 -0
- indexpilot-1.1.0a2/src/sql_parser.py +532 -0
- indexpilot-1.1.0a2/src/statistics_refresh.py +425 -0
- indexpilot-1.1.0a2/src/stats.py +355 -0
- indexpilot-1.1.0a2/src/stock_data_loader.py +368 -0
- indexpilot-1.1.0a2/src/stock_genome.py +136 -0
- indexpilot-1.1.0a2/src/storage_budget.py +247 -0
- indexpilot-1.1.0a2/src/structured_logging.py +180 -0
- indexpilot-1.1.0a2/src/type_definitions.py +449 -0
- indexpilot-1.1.0a2/src/validation.py +341 -0
- indexpilot-1.1.0a2/src/workload_analysis.py +847 -0
- indexpilot-1.1.0a2/src/workload_dna.py +2177 -0
- indexpilot-1.1.0a2/src/write_performance.py +228 -0
- indexpilot-1.1.0a2/tests/test_algorithms_math.py +293 -0
- indexpilot-1.1.0a2/tests/test_api_auth.py +48 -0
- indexpilot-1.1.0a2/tests/test_audit_algorithms.py +293 -0
- indexpilot-1.1.0a2/tests/test_auto_indexer.py +92 -0
- indexpilot-1.1.0a2/tests/test_cli.py +322 -0
- indexpilot-1.1.0a2/tests/test_config_loader.py +35 -0
- indexpilot-1.1.0a2/tests/test_db_config.py +19 -0
- indexpilot-1.1.0a2/tests/test_foreign_key_suggestions.py +47 -0
- indexpilot-1.1.0a2/tests/test_genome.py +49 -0
- indexpilot-1.1.0a2/tests/test_index_retry.py +91 -0
- indexpilot-1.1.0a2/tests/test_legacy_index_safety.py +229 -0
- indexpilot-1.1.0a2/tests/test_package_surface.py +47 -0
- indexpilot-1.1.0a2/tests/test_proposed_index_parser.py +264 -0
- indexpilot-1.1.0a2/tests/test_redundant_index_detection.py +57 -0
- indexpilot-1.1.0a2/tests/test_schema_mutations.py +245 -0
- indexpilot-1.1.0a2/tests/test_simulator.py +123 -0
- indexpilot-1.1.0a2/tests/test_small_sim.py +121 -0
- indexpilot-1.1.0a2/tests/test_statistics_refresh.py +70 -0
- indexpilot-1.1.0a2/tests/test_storage_budget.py +61 -0
- indexpilot-1.1.0a2/tests/test_workload_analysis.py +57 -0
- indexpilot-1.1.0a2/tests/test_workload_dna.py +951 -0
- indexpilot-1.1.0a2/tests/test_xgboost_integration.py +109 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Jai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: indexpilot
|
|
3
|
+
Version: 1.1.0a2
|
|
4
|
+
Summary: Workload-aware PostgreSQL index review for migration pull requests
|
|
5
|
+
Author: IndexPilot contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://eyeinthesky6.github.io/indexpilot/
|
|
8
|
+
Project-URL: Repository, https://github.com/eyeinthesky6/indexpilot
|
|
9
|
+
Project-URL: Issues, https://github.com/eyeinthesky6/indexpilot/issues
|
|
10
|
+
Project-URL: Documentation, https://github.com/eyeinthesky6/indexpilot#readme
|
|
11
|
+
Project-URL: Changelog, https://github.com/eyeinthesky6/indexpilot/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: postgresql,indexing,performance,hypopg,database,database-migrations,ci,github-actions
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Database
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: psycopg2-binary<3,>=2.9.9
|
|
26
|
+
Requires-Dist: python-dotenv<2,>=1.2.2
|
|
27
|
+
Requires-Dist: psutil<8,>=5.9.6
|
|
28
|
+
Requires-Dist: PyYAML<7,>=6.0
|
|
29
|
+
Requires-Dist: sqlglot<31,>=30.12
|
|
30
|
+
Requires-Dist: typing-extensions<5,>=4.12
|
|
31
|
+
Provides-Extra: api
|
|
32
|
+
Requires-Dist: fastapi<1,>=0.115; extra == "api"
|
|
33
|
+
Requires-Dist: uvicorn[standard]<1,>=0.32; extra == "api"
|
|
34
|
+
Provides-Extra: ml
|
|
35
|
+
Requires-Dist: numpy<3,>=1.24.3; extra == "ml"
|
|
36
|
+
Requires-Dist: scipy<2,>=1.11.4; extra == "ml"
|
|
37
|
+
Requires-Dist: scikit-learn<2,>=1.3.2; extra == "ml"
|
|
38
|
+
Requires-Dist: xgboost<4,>=2.1; extra == "ml"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: build<2,>=1.2; extra == "dev"
|
|
41
|
+
Requires-Dist: httpx<1,>=0.27; extra == "dev"
|
|
42
|
+
Requires-Dist: mypy<2,>=1.7; extra == "dev"
|
|
43
|
+
Requires-Dist: pytest<10,>=9.0.3; extra == "dev"
|
|
44
|
+
Requires-Dist: ruff<1,>=0.1.6; extra == "dev"
|
|
45
|
+
Requires-Dist: types-psycopg2>=2.9; extra == "dev"
|
|
46
|
+
Requires-Dist: types-psutil>=7.0; extra == "dev"
|
|
47
|
+
Requires-Dist: types-PyYAML>=6.0; extra == "dev"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
<p align="center">
|
|
51
|
+
<img src="https://raw.githubusercontent.com/eyeinthesky6/indexpilot/main/ui/public/brand/indexpilot-mark.svg" width="88" height="88" alt="IndexPilot Evidence Gate logo">
|
|
52
|
+
</p>
|
|
53
|
+
|
|
54
|
+
# IndexPilot
|
|
55
|
+
|
|
56
|
+
[](https://github.com/eyeinthesky6/indexpilot/actions/workflows/ci.yml)
|
|
57
|
+
[](https://github.com/eyeinthesky6/indexpilot/releases/tag/v1.1.0a2)
|
|
58
|
+
[](https://www.python.org/)
|
|
59
|
+
[](https://github.com/eyeinthesky6/indexpilot/blob/main/LICENSE)
|
|
60
|
+
|
|
61
|
+
## Make every proposed PostgreSQL index earn its benchmark before merge
|
|
62
|
+
|
|
63
|
+
**IndexPilot is open-source, production-informed code review for PostgreSQL index migrations.**
|
|
64
|
+
|
|
65
|
+
It checks each proposed `CREATE INDEX` against the queries your database actually runs,
|
|
66
|
+
comparable existing indexes, and optional hypothetical plans. You get a cautious verdict plus
|
|
67
|
+
JSON and Markdown evidence, with optional SARIF. It does not apply the migration or create a
|
|
68
|
+
physical index.
|
|
69
|
+
|
|
70
|
+
> **Alpha and advisory-only.** IndexPilot answers “does this exact index have enough evidence to
|
|
71
|
+
> deserve a benchmark?” It does not claim that planner cost equals production latency.
|
|
72
|
+
|
|
73
|
+
[Website](https://eyeinthesky6.github.io/indexpilot/) ·
|
|
74
|
+
[Quick start](#quick-start) · [How it works](#how-it-works) ·
|
|
75
|
+
[Verdicts](#verdicts) · [Trusted CI](#trusted-ci) ·
|
|
76
|
+
[Documentation](#documentation)
|
|
77
|
+
|
|
78
|
+
[](https://eyeinthesky6.github.io/indexpilot/)
|
|
79
|
+
|
|
80
|
+
<p align="center">
|
|
81
|
+
<img src="https://raw.githubusercontent.com/eyeinthesky6/indexpilot/main/ui/public/brand/indexpilot-demo.gif" alt="IndexPilot doctor and migration review terminal demonstration">
|
|
82
|
+
</p>
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
- **Review the exact migration** rather than a generic recommendation.
|
|
87
|
+
- **Use real workload evidence** from `pg_stat_statements` and PostgreSQL catalogs.
|
|
88
|
+
- **Leave a portable decision record** in Markdown, JSON, and SARIF.
|
|
89
|
+
|
|
90
|
+
## Why IndexPilot?
|
|
91
|
+
|
|
92
|
+
A `CREATE INDEX` pull request looks simple, but the index becomes a permanent cost on writes,
|
|
93
|
+
storage, cache, backups, and maintenance. The hard question is not merely whether PostgreSQL can
|
|
94
|
+
build it. The question is whether your real workload supports building it.
|
|
95
|
+
|
|
96
|
+
| Tool category | Question it answers |
|
|
97
|
+
|---|---|
|
|
98
|
+
| Migration linter | Is this DDL operationally safe to run? |
|
|
99
|
+
| Index adviser | What indexes might improve this workload? |
|
|
100
|
+
| **IndexPilot** | **Does the exact index in this migration have enough evidence to benchmark?** |
|
|
101
|
+
|
|
102
|
+
IndexPilot sits at the pull-request decision point. It helps backend and platform teams reject
|
|
103
|
+
duplicate, unsupported, or weakly evidenced proposals before they become production baggage.
|
|
104
|
+
|
|
105
|
+
## Quick start
|
|
106
|
+
|
|
107
|
+
### 1. Install the release
|
|
108
|
+
|
|
109
|
+
IndexPilot is not on PyPI yet. Install the published release artifact in an isolated environment:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
pipx install "https://github.com/eyeinthesky6/indexpilot/releases/download/v1.1.0a2/indexpilot-1.1.0a2-py3-none-any.whl"
|
|
113
|
+
indexpilot --version
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
You can also install from the release tag:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pipx install "git+https://github.com/eyeinthesky6/indexpilot.git@v1.1.0a2"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The core CLI needs Python 3.10+; it does not need Docker, Node.js, the dashboard, API dependencies,
|
|
123
|
+
or ML dependencies. See the [full installation guide](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/INSTALLATION.md)
|
|
124
|
+
for virtual environments and Windows setup.
|
|
125
|
+
|
|
126
|
+
### 2. Connect a read-only PostgreSQL role
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
export DB_HOST=database.example.com
|
|
130
|
+
export DB_PORT=5432
|
|
131
|
+
export DB_NAME=my_app
|
|
132
|
+
export DB_USER=indexpilot_reader
|
|
133
|
+
export DB_PASSWORD='replace-me'
|
|
134
|
+
export DB_SSLMODE=require
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The database must expose `pg_stat_statements`. A monitoring role commonly receives
|
|
138
|
+
`pg_read_all_stats`; optional planner review also needs `SELECT` on the referenced relations.
|
|
139
|
+
IndexPilot does not need `CREATE`, table writes, or ownership.
|
|
140
|
+
|
|
141
|
+
### 3. Check the evidence source
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
indexpilot doctor --schema public --min-calls 10
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`doctor` checks the connection, read-only transaction, PostgreSQL version,
|
|
148
|
+
`pg_stat_statements`, catalog visibility, representative workload, and HypoPG availability. A
|
|
149
|
+
real `--hypopg` review can still fail when relation or function privileges block `EXPLAIN`.
|
|
150
|
+
|
|
151
|
+
### 4. Review the migration
|
|
152
|
+
|
|
153
|
+
```sql
|
|
154
|
+
-- migrations/20260714_add_orders_index.sql
|
|
155
|
+
CREATE INDEX CONCURRENTLY idx_orders_tenant_created
|
|
156
|
+
ON public.orders (tenant_id, created_at);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
indexpilot review \
|
|
161
|
+
--migration-file migrations/20260714_add_orders_index.sql \
|
|
162
|
+
--hypopg \
|
|
163
|
+
--output artifacts/indexpilot.json \
|
|
164
|
+
--markdown-output artifacts/indexpilot.md \
|
|
165
|
+
--sarif-output artifacts/indexpilot.sarif
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
An illustrative successful review looks like this:
|
|
169
|
+
|
|
170
|
+
```text
|
|
171
|
+
IndexPilot migration review complete (advisory only).
|
|
172
|
+
Index statements reviewed: 1
|
|
173
|
+
Verdicts: {'worth_benchmarking': 1}
|
|
174
|
+
In-migration overlap findings: 0
|
|
175
|
+
JSON report: /work/artifacts/indexpilot.json
|
|
176
|
+
Markdown report: /work/artifacts/indexpilot.md
|
|
177
|
+
SARIF report: /work/artifacts/indexpilot.sarif
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
The positive verdict deliberately says **benchmark it**, not **ship it**.
|
|
181
|
+
|
|
182
|
+
## How it works
|
|
183
|
+
|
|
184
|
+
```mermaid
|
|
185
|
+
flowchart LR
|
|
186
|
+
M["CREATE INDEX migration"] --> P["SQLGlot PostgreSQL AST"]
|
|
187
|
+
P --> R["IndexPilot evidence review"]
|
|
188
|
+
W["pg_stat_statements"] --> R
|
|
189
|
+
C["PostgreSQL catalogs"] --> R
|
|
190
|
+
R -. "optional" .-> H["HypoPG EXPLAIN"]
|
|
191
|
+
H --> V["Cautious verdict"]
|
|
192
|
+
R --> V
|
|
193
|
+
V --> O["JSON · Markdown · SARIF"]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
1. **Parse the proposal.** SQLGlot reads PostgreSQL syntax locally. IndexPilot normalizes the
|
|
197
|
+
identifiers and never sends the supplied migration text to PostgreSQL.
|
|
198
|
+
2. **Read workload evidence.** Aggregate `pg_stat_statements` rows become query fingerprints;
|
|
199
|
+
raw workload SQL is not written to reports.
|
|
200
|
+
3. **Check the catalog.** Existing valid, ready, ordinary B-trees are compared for exact and
|
|
201
|
+
leading-prefix overlap.
|
|
202
|
+
4. **Test a hypothetical plan.** When requested, an already-installed HypoPG extension creates a
|
|
203
|
+
session-local hypothetical shape and IndexPilot runs `EXPLAIN`, never `ANALYZE`.
|
|
204
|
+
5. **Leave a review artifact.** Each proposal receives a stable verdict with its evidence,
|
|
205
|
+
limitations, and next step.
|
|
206
|
+
|
|
207
|
+
Migration files are reviewed in one pass. Proposals in the same schema share one catalog/workload
|
|
208
|
+
snapshot; a migration spanning schemas uses one snapshot per referenced schema. Non-index
|
|
209
|
+
statements are counted but never executed.
|
|
210
|
+
|
|
211
|
+
## What it catches
|
|
212
|
+
|
|
213
|
+
- an existing comparable index with the same leading prefix;
|
|
214
|
+
- exact duplicates, leading-prefix overlap, and duplicate index names inside one migration;
|
|
215
|
+
- no observed workload using the proposal's leading column;
|
|
216
|
+
- a hypothetical index the representative plan does not select;
|
|
217
|
+
- planner improvement below the current advisory threshold;
|
|
218
|
+
- missing, stale, or insufficient workload evidence;
|
|
219
|
+
- index shapes the current reviewer cannot represent faithfully.
|
|
220
|
+
|
|
221
|
+
Unsupported input fails with its statement number instead of being silently approximated.
|
|
222
|
+
|
|
223
|
+
## Verdicts
|
|
224
|
+
|
|
225
|
+
| Verdict | What the evidence says | Recommended next step |
|
|
226
|
+
|---|---|---|
|
|
227
|
+
| `worth_benchmarking` | The exact hypothetical index was selected and passed the advisory planner-cost threshold | Benchmark latency, writes, build time, size, cache behavior, and rollback on a production copy |
|
|
228
|
+
| `existing_overlap` | A comparable existing B-tree already has the same leading prefix | Inspect both shapes; this is manual-review evidence, never safe-to-drop proof |
|
|
229
|
+
| `not_supported_by_current_planner_evidence` | HypoPG completed, but the exact shape was unused or below the threshold | Inspect the plan or test another shape; do not infer that the index is harmful |
|
|
230
|
+
| `inconclusive` | Workload or planner evidence was missing or insufficient | Collect representative traffic, fix access, or enable optional HypoPG review |
|
|
231
|
+
|
|
232
|
+
Current HypoPG review plans one representative query per candidate. It is not a full workload
|
|
233
|
+
regression test.
|
|
234
|
+
|
|
235
|
+
Overlap inside one migration is recorded separately in `migration_overlap_findings`. It does not
|
|
236
|
+
change an individual proposal's verdict, but it does match `--fail-on existing_overlap`.
|
|
237
|
+
|
|
238
|
+
## Command map
|
|
239
|
+
|
|
240
|
+
| Command | Purpose | Database access |
|
|
241
|
+
|---|---|---|
|
|
242
|
+
| `indexpilot doctor` | Check whether the database can provide useful review evidence | Read-only |
|
|
243
|
+
| `indexpilot review --migration-file ...` | Review every supported index proposal in a migration | Read-only |
|
|
244
|
+
| `indexpilot review --candidate-sql ...` | Review one exact proposed index | Read-only |
|
|
245
|
+
| `indexpilot review` | Discover repeated equality-plus-range/order candidates | Read-only |
|
|
246
|
+
| `indexpilot audit` | Find cautious exact or leading-prefix overlap among existing B-trees | Catalog-only; `pg_stat_statements` is not required |
|
|
247
|
+
| `indexpilot compare before.json after.json` | Check offline whether PostgreSQL later recorded scans on the exact shape | None |
|
|
248
|
+
| `indexpilot dna` | Write the compatibility workload-DNA JSON report | Read-only |
|
|
249
|
+
| `indexpilot api` | Run the optional authenticated single-operator dashboard API | Separate optional surface |
|
|
250
|
+
|
|
251
|
+
Run `indexpilot <command> --help` for every option. The
|
|
252
|
+
[usage guide](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/USAGE.md)
|
|
253
|
+
documents report fields, exit codes, proposal syntax, and examples.
|
|
254
|
+
|
|
255
|
+
## Trusted CI
|
|
256
|
+
|
|
257
|
+
IndexPilot can turn weak evidence into an opt-in CI failure while still writing the reports:
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
indexpilot review \
|
|
261
|
+
--migration-file migrations/add_orders_index.sql \
|
|
262
|
+
--hypopg \
|
|
263
|
+
--output artifacts/indexpilot.json \
|
|
264
|
+
--markdown-output artifacts/indexpilot.md \
|
|
265
|
+
--sarif-output artifacts/indexpilot.sarif \
|
|
266
|
+
--fail-on existing_overlap \
|
|
267
|
+
--fail-on inconclusive
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
`--fail-on` is repeatable. A matched verdict exits with code `3` after the evidence artifacts
|
|
271
|
+
are written; ordinary completed advisory reports exit with code `0`.
|
|
272
|
+
|
|
273
|
+
> **Protect database credentials.** Do not expose a production or staging secret to code from an
|
|
274
|
+
> untrusted fork pull request. Run IndexPilot on a protected branch, with `workflow_dispatch`
|
|
275
|
+
> against a reviewed commit, or against a sanitized throwaway database.
|
|
276
|
+
|
|
277
|
+
Use the [trusted GitHub Actions recipe](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/GITHUB_ACTIONS.md)
|
|
278
|
+
for the complete least-privilege workflow.
|
|
279
|
+
|
|
280
|
+
## Safety and privacy contract
|
|
281
|
+
|
|
282
|
+
| Boundary | What IndexPilot does |
|
|
283
|
+
|---|---|
|
|
284
|
+
| Database transaction | Sets the evidence-collection transaction to read-only |
|
|
285
|
+
| Supplied SQL | Parses locally and rebuilds safe hypothetical SQL from normalized identifiers |
|
|
286
|
+
| Physical DDL | Never creates, drops, cleans up, or reindexes a physical index in the public review path |
|
|
287
|
+
| HypoPG | Uses session-local hypothetical indexes and resets them before and after review |
|
|
288
|
+
| Planner | Runs `EXPLAIN`, never `EXPLAIN ANALYZE` |
|
|
289
|
+
| Extensions | Uses `pg_stat_statements` and optional HypoPG only when already installed |
|
|
290
|
+
| Existing-index audit | Reports overlap and usage counters; never produces drop advice |
|
|
291
|
+
| Reports | Exclude raw workload SQL; include fingerprints, normalized proposals, object names, counts, and size metadata |
|
|
292
|
+
|
|
293
|
+
Generated artifacts can still reveal schema and workload metadata. Review them before posting them
|
|
294
|
+
publicly.
|
|
295
|
+
|
|
296
|
+
## Supported proposals
|
|
297
|
+
|
|
298
|
+
The alpha intentionally accepts a narrow shape:
|
|
299
|
+
|
|
300
|
+
```sql
|
|
301
|
+
CREATE INDEX [CONCURRENTLY] [IF NOT EXISTS] [name]
|
|
302
|
+
ON [schema.]table (column [, column ...]);
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
That means one non-unique, ascending B-tree with plain column keys. Partial, expression,
|
|
306
|
+
`INCLUDE`, `UNIQUE`, descending, and specialized index shapes are rejected because they carry
|
|
307
|
+
different physical meaning. See the [supported syntax](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/USAGE.md#supported-proposal-syntax)
|
|
308
|
+
for the full boundary.
|
|
309
|
+
|
|
310
|
+
## How IndexPilot fits with advanced tools
|
|
311
|
+
|
|
312
|
+
IndexPilot is designed to complement the PostgreSQL ecosystem:
|
|
313
|
+
|
|
314
|
+
| Tool | Reach for it when... |
|
|
315
|
+
|---|---|
|
|
316
|
+
| [Squawk](https://squawkhq.com/) | You want static migration-safety rules |
|
|
317
|
+
| [Dexter](https://github.com/ankane/dexter) | You want an automatic index candidate generator |
|
|
318
|
+
| [HypoPG](https://github.com/HypoPG/hypopg) | You want the raw hypothetical-index mechanism |
|
|
319
|
+
| [pganalyze Index Advisor](https://pganalyze.com/docs/index-advisor/getting-started) | You want managed, workload-wide monitoring and advice |
|
|
320
|
+
| **IndexPilot** | You want a local, inspectable evidence gate for the exact index in a migration |
|
|
321
|
+
|
|
322
|
+
The useful pairing is simple:
|
|
323
|
+
|
|
324
|
+
> A migration linter checks whether an index is safe to build. IndexPilot checks whether that exact
|
|
325
|
+
> index is justified enough to benchmark.
|
|
326
|
+
|
|
327
|
+
## Requirements and limits
|
|
328
|
+
|
|
329
|
+
- Python 3.10-3.13 is tested in CI.
|
|
330
|
+
- PostgreSQL with `pg_stat_statements` is required for workload review.
|
|
331
|
+
- PostgreSQL 16+ and an already-installed HypoPG extension are required only for the current
|
|
332
|
+
placeholder-safe planner comparison.
|
|
333
|
+
- Workload statistics must cover representative traffic; a quiet or recently reset window can
|
|
334
|
+
only produce weak evidence.
|
|
335
|
+
- IndexPilot does not yet measure real latency, write amplification, physical bloat, index build
|
|
336
|
+
duration, deployed size, cache effects, or rollback time.
|
|
337
|
+
- The optional API uses one shared operator token. It is not hosted multi-user authentication.
|
|
338
|
+
|
|
339
|
+
See the [roadmap](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/ROADMAP.md)
|
|
340
|
+
for production-copy replay, richer index shapes, offline workload snapshots, and PyPI Trusted
|
|
341
|
+
Publishing.
|
|
342
|
+
|
|
343
|
+
## Documentation
|
|
344
|
+
|
|
345
|
+
| Guide | Use it for |
|
|
346
|
+
|---|---|
|
|
347
|
+
| [Installation](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/INSTALLATION.md) | PostgreSQL setup, least-privilege access, HypoPG, and common errors |
|
|
348
|
+
| [CLI usage](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/USAGE.md) | Commands, verdicts, report fields, privacy, and exit codes |
|
|
349
|
+
| [Trusted CI](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/GITHUB_ACTIONS.md) | GitHub Actions without unsafe secret exposure |
|
|
350
|
+
| [Architecture](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/codebase/ARCHITECTURE.md) | Runtime flow and module ownership |
|
|
351
|
+
| [Known concerns](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/codebase/CONCERNS.md) | Honest launch gaps and technical risks |
|
|
352
|
+
| [Roadmap](https://github.com/eyeinthesky6/indexpilot/blob/main/docs/ROADMAP.md) | Planned evidence upgrades and deliberately deferred work |
|
|
353
|
+
| [Changelog](https://github.com/eyeinthesky6/indexpilot/blob/main/CHANGELOG.md) | Public package changes |
|
|
354
|
+
|
|
355
|
+
## Development
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
git clone https://github.com/eyeinthesky6/indexpilot.git
|
|
359
|
+
cd indexpilot
|
|
360
|
+
python -m venv .venv
|
|
361
|
+
python -m pip install -e ".[dev,api,ml]"
|
|
362
|
+
python -m pytest tests -q
|
|
363
|
+
python scripts/check_unsafe_db_access.py
|
|
364
|
+
python -m build
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Database-backed tests use the PostgreSQL service in `docker-compose.yml`. The optional dashboard
|
|
368
|
+
is tested separately under `ui/`.
|
|
369
|
+
|
|
370
|
+
IndexPilot is early, deliberately narrow, and open to contributors. A useful first change can be a
|
|
371
|
+
focused test, a clearer example, a PostgreSQL compatibility report, or a small fix. You do not need
|
|
372
|
+
to understand the historical research modules before helping with the supported CLI.
|
|
373
|
+
|
|
374
|
+
Start with [good first issues](https://github.com/eyeinthesky6/indexpilot/labels/good%20first%20issue)
|
|
375
|
+
or [help wanted](https://github.com/eyeinthesky6/indexpilot/labels/help%20wanted), then read
|
|
376
|
+
[CONTRIBUTING.md](https://github.com/eyeinthesky6/indexpilot/blob/main/CONTRIBUTING.md). Use the
|
|
377
|
+
[issue tracker](https://github.com/eyeinthesky6/indexpilot/issues) for bugs and proposals. Report
|
|
378
|
+
vulnerabilities privately through
|
|
379
|
+
[SECURITY.md](https://github.com/eyeinthesky6/indexpilot/blob/main/SECURITY.md).
|
|
380
|
+
|
|
381
|
+
## Release status
|
|
382
|
+
|
|
383
|
+
[`v1.1.0a2`](https://github.com/eyeinthesky6/indexpilot/releases/tag/v1.1.0a2) is the current
|
|
384
|
+
focused, installable evaluation release. It is an alpha, not a supported production service. The
|
|
385
|
+
older `v1.0.0-stable` tag predates the focused package contract and remains historical.
|
|
386
|
+
|
|
387
|
+
## License
|
|
388
|
+
|
|
389
|
+
IndexPilot is available under the [MIT License](https://github.com/eyeinthesky6/indexpilot/blob/main/LICENSE).
|