pg-play 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. pg_play-0.2.0/LICENSE +21 -0
  2. pg_play-0.2.0/PKG-INFO +394 -0
  3. pg_play-0.2.0/README.md +355 -0
  4. pg_play-0.2.0/pyproject.toml +84 -0
  5. pg_play-0.2.0/setup.cfg +4 -0
  6. pg_play-0.2.0/src/pg_play/__init__.py +5 -0
  7. pg_play-0.2.0/src/pg_play/__main__.py +5 -0
  8. pg_play-0.2.0/src/pg_play/cli.py +133 -0
  9. pg_play-0.2.0/src/pg_play/contract.py +162 -0
  10. pg_play-0.2.0/src/pg_play/manifest.py +550 -0
  11. pg_play-0.2.0/src/pg_play/mcp_server.py +174 -0
  12. pg_play-0.2.0/src/pg_play/report.py +168 -0
  13. pg_play-0.2.0/src/pg_play/runner.py +110 -0
  14. pg_play-0.2.0/src/pg_play/schema/pg_play-v1.schema.json +174 -0
  15. pg_play-0.2.0/src/pg_play/service.py +1378 -0
  16. pg_play-0.2.0/src/pg_play/skills/analyze-postgres-experiment/SKILL.md +37 -0
  17. pg_play-0.2.0/src/pg_play/skills/analyze-postgres-experiment/agents/openai.yaml +4 -0
  18. pg_play-0.2.0/src/pg_play/skills/analyze-postgres-experiment/references/interpretation.md +18 -0
  19. pg_play-0.2.0/src/pg_play/skills/run-postgres-experiment/SKILL.md +27 -0
  20. pg_play-0.2.0/src/pg_play/skills/run-postgres-experiment/agents/openai.yaml +4 -0
  21. pg_play-0.2.0/src/pg_play/skills/run-postgres-experiment/references/manifest.md +84 -0
  22. pg_play-0.2.0/src/pg_play/state.py +41 -0
  23. pg_play-0.2.0/src/pg_play/version.py +3 -0
  24. pg_play-0.2.0/src/pg_play.egg-info/PKG-INFO +394 -0
  25. pg_play-0.2.0/src/pg_play.egg-info/SOURCES.txt +36 -0
  26. pg_play-0.2.0/src/pg_play.egg-info/dependency_links.txt +1 -0
  27. pg_play-0.2.0/src/pg_play.egg-info/entry_points.txt +3 -0
  28. pg_play-0.2.0/src/pg_play.egg-info/requires.txt +13 -0
  29. pg_play-0.2.0/src/pg_play.egg-info/top_level.txt +1 -0
  30. pg_play-0.2.0/tests/test_cli.py +45 -0
  31. pg_play-0.2.0/tests/test_component_interfaces.py +28 -0
  32. pg_play-0.2.0/tests/test_contract.py +82 -0
  33. pg_play-0.2.0/tests/test_manifest.py +250 -0
  34. pg_play-0.2.0/tests/test_mcp_server.py +35 -0
  35. pg_play-0.2.0/tests/test_package_assets.py +41 -0
  36. pg_play-0.2.0/tests/test_report.py +63 -0
  37. pg_play-0.2.0/tests/test_runner.py +47 -0
  38. pg_play-0.2.0/tests/test_service.py +356 -0
pg_play-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 O2eg
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.
pg_play-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,394 @@
1
+ Metadata-Version: 2.4
2
+ Name: pg-play
3
+ Version: 0.2.0
4
+ Summary: PostgreSQL experiment orchestrator
5
+ Author-email: O2eg <oleg.ispu@yandex.ru>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/O2eg/pg_play
8
+ Project-URL: Repository, https://github.com/O2eg/pg_play
9
+ Project-URL: Issues, https://github.com/O2eg/pg_play/issues
10
+ Keywords: postgresql,orchestration,diagnostics,testing,dba
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: System Administrators
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Database
22
+ Classifier: Topic :: Software Development :: Testing
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: mcp<2,>=1.28
27
+ Requires-Dist: pg-configurator<1,>=0.9.1
28
+ Requires-Dist: pg-diag<1,>=0.10.3
29
+ Requires-Dist: pg-perf-bench<1,>=0.2
30
+ Requires-Dist: pg-stand<1,>=0.2.1
31
+ Requires-Dist: pg-workload<1,>=0.3.0
32
+ Requires-Dist: PyYAML<7,>=6.0
33
+ Provides-Extra: dev
34
+ Requires-Dist: build<2,>=1.2; extra == "dev"
35
+ Requires-Dist: pytest<9,>=8.3; extra == "dev"
36
+ Requires-Dist: ruff<1,>=0.12; extra == "dev"
37
+ Requires-Dist: twine<7,>=6; extra == "dev"
38
+ Dynamic: license-file
39
+
40
+ # pg_play
41
+
42
+ `pg_play` is the AI-ready orchestration layer for reproducible PostgreSQL
43
+ experiments.
44
+
45
+ - Recreates the same PostgreSQL stand, backend activity, and diagnostic window.
46
+ - Applies a versioned `pg_configurator` candidate only through a reviewed
47
+ `pg_stand` plan.
48
+ - Keeps human-facing component CLIs small while exposing a typed MCP workflow
49
+ to an AI agent.
50
+ - Records immutable plan hashes, run state, component versions, and artifact
51
+ hashes.
52
+ - Validates and compares `pg_diag` JSON reports without treating a partial
53
+ collection as a successful complete run.
54
+ - Plans and runs `pg_perf_bench` only against an explicitly selected disposable
55
+ database, then validates and compares benchmark artifacts and TPS evidence.
56
+ - Installs every component while preserving their independent use.
57
+
58
+ The independently installable components are:
59
+
60
+ - [`pg_stand`](https://github.com/O2eg/pg_stand) — reproducible PostgreSQL
61
+ stands;
62
+ - [`pg_workload`](https://github.com/O2eg/pg_workload) — profile-driven backend
63
+ activity emulation;
64
+ - [`pg_diag`](https://github.com/O2eg/pg_diag) — diagnostic JSON and HTML
65
+ artifacts;
66
+ - [`pg_configurator`](https://github.com/O2eg/pg_configurator) — version-aware
67
+ PostgreSQL configuration candidates.
68
+ - [`pg_perf_bench`](https://github.com/O2eg/pg_perf_bench) — controlled pgbench
69
+ execution and environment evidence.
70
+
71
+ ## How it works
72
+
73
+ ```text
74
+ pg_play
75
+ |
76
+ +-------------+-------------+
77
+ | |
78
+ v |
79
+ pg_configurator |
80
+ | versioned config |
81
+ v |
82
+ pg_stand ------------------------+
83
+ |
84
+ v
85
+ PostgreSQL stand
86
+ / | \
87
+ v v v
88
+ pg_workload pg_perf_bench pg_diag
89
+ | | |
90
+ | benchmark report |
91
+ +--------- run ----------+----> diagnostic report
92
+ |
93
+ change one reviewed input
94
+ |
95
+ +----> rebuild, rerun, compare
96
+ ```
97
+
98
+ The control layers are deliberately separate:
99
+
100
+ ```text
101
+ agent skills workflow and interpretation rules
102
+ |
103
+ v
104
+ pg-play-mcp thirteen typed, high-level operations
105
+ |
106
+ v
107
+ pg_play core validation, planning, state, comparison
108
+ |
109
+ v
110
+ component adapters argv arrays + strict JSON envelopes
111
+ |
112
+ +---- pg_configurator
113
+ +---- pg_stand
114
+ +---- pg_workload
115
+ +---- pg_diag
116
+ `---- pg_perf_bench
117
+ ```
118
+
119
+ MCP does not expose arbitrary shell, SQL, Docker, or raw component-command
120
+ tools. Each component remains pleasant to use directly: orchestration flags
121
+ are hidden from its primary help and its normal human output is unchanged.
122
+
123
+ ## Installation
124
+
125
+ ```bash
126
+ python -m pip install pg-play
127
+ ```
128
+
129
+ This installs compatible versions of all five component distributions. They
130
+ remain available through their own commands:
131
+
132
+ ```bash
133
+ pg-stand --help
134
+ pg-workload --help
135
+ pg-diag --help
136
+ pg-configurator --help
137
+ pg-perf-bench --help
138
+ ```
139
+
140
+ ## Experiment manifest
141
+
142
+ `pg_play/v1` is strict: unknown fields, secret-bearing configurator inputs,
143
+ missing projects, invalid profile names, and invalid diagnostic windows are
144
+ errors.
145
+
146
+ ```yaml
147
+ api_version: pg_play/v1
148
+ kind: PostgreSQLExperiment
149
+ metadata:
150
+ id: pg18-mixed-baseline
151
+ spec:
152
+ artifact_root: .pg_play/experiments/pg18-mixed-baseline
153
+ stand:
154
+ config: ../pg_stand/configs/single.yaml
155
+ project: ./stand
156
+ configurator:
157
+ inputs:
158
+ db_cpu: 4
159
+ db_ram: 8Gi
160
+ pg_version: "18"
161
+ db_duty: mixed
162
+ workload:
163
+ project: ./workload
164
+ profiles: [pagila, simple_stock]
165
+ scale: 1.0
166
+ database: workload_db
167
+ user: workload_user
168
+ install: true
169
+ stop_after_report: true
170
+ pgbench_duration_seconds: 30
171
+ job_interval_seconds: 5
172
+ resource_guard:
173
+ disk_max_used_pct: 90
174
+ mem_min_available_pct: 10
175
+ mem_min_available_mb: 2048
176
+ cpu_max_pct: 90
177
+ cpu_window_seconds: 60
178
+ check_interval: 5
179
+ diagnostics:
180
+ mode: snapshots
181
+ collection_mode: remote-db-only
182
+ duration_seconds: 60
183
+ interval_seconds: 10
184
+ report_name: pg18-mixed-diagnostics
185
+ benchmark: # optional
186
+ database: pg_perf_bench_test # dedicated and disposable
187
+ report_name: pg18-mixed-benchmark
188
+ benchmark_type: default
189
+ clients: [1, 4, 16] # or times_seconds, never both
190
+ init_command: >-
191
+ ARG_PGBENCH_PATH -i -s 10 -h ARG_PG_HOST -p ARG_PG_PORT
192
+ -U ARG_PG_USER ARG_PG_DATABASE
193
+ workload_command: >-
194
+ ARG_PGBENCH_PATH -T 60 -c ARG_PGBENCH_CLIENTS -j ARG_PGBENCH_CLIENTS
195
+ -h ARG_PG_HOST -p ARG_PG_PORT -U ARG_PG_USER ARG_PG_DATABASE
196
+ command_timeout: 120
197
+ system_metrics_interval: 1
198
+ drop_os_caches: false
199
+ collect_pg_logs: true
200
+ phases:
201
+ benchmark: true
202
+ workload_diagnostics: true
203
+ recreate_workload_database: true
204
+ ```
205
+
206
+ To use a packaged `pg_perf_bench` maximum-TPS profile, replace
207
+ `benchmark_type`, `init_command`, `workload_command`, and `workload_path` with:
208
+
209
+ ```yaml
210
+ workload_profile: imdb # imdb or pagila
211
+ workload_scale: 1.0
212
+ workload_duration_seconds: 30
213
+ clients: [1, 2, 4, 8, 16]
214
+ ```
215
+
216
+ The profile supplies its schema, deterministic generator, SQL query set and
217
+ command templates. `pg_play` includes the selected profile and scale in the
218
+ reviewed benchmark plan. `pg_perf_bench` selects the newest local pgbench/psql
219
+ pair automatically; optional `pgbench_path` and `psql_path` overrides are
220
+ accepted only when they are not older than the newest installed clients. The
221
+ pg_diag OS sampler runs during every benchmark window; use
222
+ `system_metrics_interval` to control its cadence and
223
+ `system_metrics_duration` only when a custom command has no pgbench `-T` or
224
+ `--time` option.
225
+
226
+ Paths are resolved relative to the manifest. `spec.stand.project` defaults to
227
+ the manifest directory and fixes where `pg_stand` stores state, credentials,
228
+ and storage regardless of the caller's current directory. Credentials never
229
+ belong in this file. `pg_play` obtains the stand-owned administrator credential, creates a
230
+ random workload credential, and stores project-local passfiles with mode
231
+ `0600`.
232
+
233
+ The workload resource guard is always enabled by `pg_play`. Its thresholds are
234
+ manifest inputs and therefore part of the reviewed plan hash; override them
235
+ only when the host policy is explicitly known.
236
+
237
+ The packaged JSON Schema is available as the MCP resource
238
+ `pgplay://experiment-schema`.
239
+
240
+ ## Shared CLI conventions
241
+
242
+ `pg_diag` naming is the reference for equivalent options. Components now use
243
+ `--host`, `--port`, `--database`, `--user`, `--password`, `--out`, and
244
+ `--pg-version` wherever those concepts apply. Existing `pg_perf_bench --pg-*`,
245
+ `pg_workload --pg-major`/`--workload-user`, `pg_stand --postgres-version`, and
246
+ `pg_configurator --output-file-name` spellings remain compatibility aliases.
247
+ Secrets are the deliberate exception: `pg_workload` continues to accept
248
+ passwords only through environment/passfile mechanisms.
249
+
250
+ All five components use the same hidden orchestration options:
251
+ `--machine`, `--request-id`, and `--component-capabilities`. Their advertised
252
+ `machine_interface` object makes these names machine-verifiable.
253
+
254
+ ## Human CLI
255
+
256
+ The `pg-play` CLI contains only complete experiment operations:
257
+
258
+ | Command | Effect |
259
+ | --- | --- |
260
+ | `capabilities` | Read installed component contracts |
261
+ | `validate MANIFEST` | Validate the manifest and non-mutating component inputs |
262
+ | `plan MANIFEST` | Calculate the current read-only plan and its hash |
263
+ | `run MANIFEST --plan-hash HASH --run-id ID` | Execute exactly that plan |
264
+ | `status MANIFEST --run-id ID` | Read durable run state |
265
+ | `inspect-report REPORT.json` | Validate and summarize one diagnostic artifact |
266
+ | `compare-reports BASELINE.json CANDIDATE.json` | Produce deterministic summary deltas |
267
+ | `inspect-benchmark-report REPORT.json` | Validate and summarize one benchmark artifact |
268
+ | `compare-benchmark-reports BASELINE.json CANDIDATE.json` | Check server, environment and methodology identity, then produce TPS deltas |
269
+ | `benchmark-profiles` | List packaged maximum-TPS workload profiles |
270
+ | `benchmark-join-tasks` | List documented benchmark JOIN scenarios |
271
+ | `join-benchmark-reports --report ... --join-task TASK --out DIR --report-name NAME` | Join only the explicitly named benchmark reports |
272
+ | `teardown MANIFEST [--clear-stand-data]` | Stop workload processes and remove the managed stand |
273
+
274
+ Typical flow:
275
+
276
+ ```bash
277
+ mkdir -p stand workload
278
+ pg-workload init --directory workload
279
+
280
+ pg-play validate experiment.yaml
281
+ pg-play plan experiment.yaml > plan.json
282
+
283
+ # Copy plan_hash from the reviewed plan.
284
+ pg-play run experiment.yaml \
285
+ --plan-hash sha256:... \
286
+ --run-id baseline-001
287
+
288
+ pg-play status experiment.yaml --run-id baseline-001
289
+ pg-play inspect-report .pg_play/experiments/pg18-mixed-baseline/baseline-001/report.json
290
+ ```
291
+
292
+ `run` recalculates the plan and rejects a stale hash. A run id is immutable;
293
+ retry a changed or failed experiment under a new id.
294
+
295
+ ## MCP server
296
+
297
+ Start the stdio server with:
298
+
299
+ ```bash
300
+ pg-play-mcp
301
+ ```
302
+
303
+ Configure an MCP client to launch that executable with no shell wrapper. The
304
+ server exposes only:
305
+
306
+ - `component_capabilities`
307
+ - `validate_experiment`
308
+ - `plan_experiment`
309
+ - `run_experiment`
310
+ - `experiment_status`
311
+ - `inspect_diagnostic_report`
312
+ - `compare_diagnostic_reports`
313
+ - `inspect_benchmark_report`
314
+ - `compare_benchmark_reports`
315
+ - `benchmark_profiles`
316
+ - `benchmark_join_tasks`
317
+ - `join_benchmark_reports`
318
+ - `teardown_experiment`
319
+
320
+ An agent should validate, plan, show the mutation to the user, and then call
321
+ `run_experiment` with the unchanged hash and a new run id. The implementation
322
+ uses the stable [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)
323
+ 1.x line and intentionally excludes the 2.x prerelease API.
324
+
325
+ ## Agent skills
326
+
327
+ The wheel contains two optional workflow skills under `pg_play/skills/`:
328
+
329
+ - `run-postgres-experiment` — validate, plan, execute, and recover a run;
330
+ - `analyze-postgres-experiment` — inspect reports, compare controlled runs,
331
+ and design the next single-variable iteration.
332
+
333
+ Skills contain procedural guidance; they do not reimplement orchestration or
334
+ invoke raw component commands. Skill registration is agent-runtime-specific,
335
+ so installing a Python wheel does not automatically activate them in every
336
+ agent product.
337
+
338
+ ## Determinism and safety
339
+
340
+ - Every component returns the exact `pg_play/component/v1` envelope in hidden
341
+ machine mode and advertises `pg_play/capabilities/v1` through the common
342
+ `--component-capabilities` flag.
343
+ - Plans hash normalized configuration, workload profile contents, scheduler
344
+ state, and current stand state.
345
+ - Parameters owned by stand topology, TLS, fixed CSV logging, or diagnostic
346
+ preloads remain under `pg_stand`; the plan records those candidate values
347
+ separately and passes only non-owned parameters to `pg_stand`.
348
+ - Managed TLS stands are rejected during validation in `pg_play/v1`: the
349
+ component contract does not yet provision a client certificate for the
350
+ dedicated workload role. Direct TLS use of each component remains available.
351
+ - `pg_stand apply` verifies its component plan hash; `pg_play run` verifies the
352
+ combined plan hash. Machine-mode `pg_perf_bench benchmark` independently
353
+ verifies a content-sensitive benchmark plan hash before resetting its database.
354
+ - Subprocesses receive argument arrays with `shell=False`.
355
+ - Password-bearing CLI arguments and password-bearing machine output are
356
+ rejected.
357
+ - Background workload stop verifies PID ownership before signaling a process.
358
+ - A failed cleanup cannot hide the original collection failure; a cleanup
359
+ failure after successful diagnostics marks the run partial.
360
+ - `pg_diag` partial artifacts are retained and explicitly marked partial.
361
+ - `pg_play` never automatically destroys a stand.
362
+
363
+ Remote OS collection uses strict SSH host verification. For a newly created
364
+ local `pg_stand`, `pg_play` captures its host key into the run directory before
365
+ starting `pg_diag`; the captured file is permission-restricted and retained as
366
+ run evidence.
367
+
368
+ ## Current scope
369
+
370
+ The first contract covers one configuration candidate, one managed stand,
371
+ an optional controlled benchmark, selected workload profiles, a one-shot or
372
+ snapshots report, and deterministic diagnostic and benchmark comparison.
373
+ Automatic extraction of OS facts and generation or
374
+ application of TuneD/systemd artifacts remains a roadmap item; it is not
375
+ silently approximated by the current implementation.
376
+
377
+ ## Development
378
+
379
+ ```bash
380
+ python3 -m venv .venv
381
+ .venv/bin/pip install -e ../pg_stand -e ../pg_workload -e ../pg_diag \
382
+ -e ../pg_configurator -e ../pg_perf_bench
383
+ .venv/bin/pip install -e '.[dev]'
384
+ .venv/bin/ruff check .
385
+ .venv/bin/ruff format --check .
386
+ .venv/bin/pytest
387
+ ```
388
+
389
+ For coordinated releases, publish the component distributions before tagging
390
+ `pg_play`: first `pg_configurator`, `pg_diag`, `pg_stand`, and `pg_workload`,
391
+ then `pg_perf_bench` (which depends on `pg_diag`), and finally `pg_play`.
392
+ Ordinary branch CI checks out the component sources so a coordinated source
393
+ change can be tested before those versions reach PyPI. Tagged publish jobs use
394
+ the package index deliberately and therefore enforce this release order.