b3-prosaic-harness-postgres 0.4.0__tar.gz → 0.4.2__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.
- {b3_prosaic_harness_postgres-0.4.0/src/b3_prosaic_harness_postgres.egg-info → b3_prosaic_harness_postgres-0.4.2}/PKG-INFO +84 -17
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/README.md +82 -15
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/pyproject.toml +2 -2
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2/src/b3_prosaic_harness_postgres.egg-info}/PKG-INFO +84 -17
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/b3_prosaic_harness_postgres.egg-info/SOURCES.txt +6 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/b3_prosaic_harness_postgres.egg-info/requires.txt +1 -1
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/__init__.py +1 -1
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/cli.py +13 -3
- b3_prosaic_harness_postgres-0.4.2/src/prosaic_harness_postgres/pack_schema.py +31 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/schema.py +17 -5
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/session_schema.py +17 -5
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/session_store.py +18 -6
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/store.py +19 -4
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/transport.py +14 -3
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/local_cluster.py +40 -9
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/session_documents.py +46 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/session_workers.py +2 -1
- b3_prosaic_harness_postgres-0.4.2/tests/test_context_pack_migrations.py +96 -0
- b3_prosaic_harness_postgres-0.4.2/tests/test_context_pack_platform.py +21 -0
- b3_prosaic_harness_postgres-0.4.2/tests/test_context_pack_recovery.py +112 -0
- b3_prosaic_harness_postgres-0.4.2/tests/test_durability_profiles.py +96 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_packaging.py +27 -9
- b3_prosaic_harness_postgres-0.4.2/tests/test_renewal_contention.py +39 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/LICENSE +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/MANIFEST.in +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/NOTICE +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/setup.cfg +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/b3_prosaic_harness_postgres.egg-info/dependency_links.txt +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/b3_prosaic_harness_postgres.egg-info/entry_points.txt +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/b3_prosaic_harness_postgres.egg-info/top_level.txt +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/leases.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/session_leases.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/conftest.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/linux_wheel_smoke.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/model_server.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/tcp_proxy.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/workers.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_cli.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_durability.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_engine.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_examples.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_leases.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_local_cluster.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_native_factory.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_recovery.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_registration.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_routing.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_schema.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_context.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_fencing.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_recovery.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_schema.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_store.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_workers.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_store.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_transport.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_workers.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: b3-prosaic-harness-postgres
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Explicit PostgreSQL run and conversation storage for Prosaic Harness
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.11
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
License-File: NOTICE
|
|
10
|
-
Requires-Dist: b3-prosaic-harness<0.10,>=0.9
|
|
10
|
+
Requires-Dist: b3-prosaic-harness<0.10,>=0.9.13
|
|
11
11
|
Requires-Dist: psycopg[binary]<4,>=3.2.3
|
|
12
12
|
Requires-Dist: psycopg-pool<4,>=3.2
|
|
13
13
|
Provides-Extra: test
|
|
@@ -20,28 +20,58 @@ Dynamic: license-file
|
|
|
20
20
|
|
|
21
21
|
# PostgreSQL persistence for Prosaic Harness
|
|
22
22
|
|
|
23
|
+
PostgreSQL adapter **0.4.2** requires Harness **0.9.13** or later
|
|
24
|
+
in the compatible family. Explicit owner migration enables
|
|
25
|
+
workflow storage contract2 or conversation contract3; readiness performs no DDL.
|
|
26
|
+
See [context-pack migration and rollback](../../docs/context-packs.md#current-authorization-and-durable-storage).
|
|
27
|
+
|
|
28
|
+
See [0.4.2 release and migration notes](../../docs/release-postgres-0.4.2.md)
|
|
29
|
+
and [compatible SDK versions](https://github.com/B3Cognition/prosaic-harness/blob/main/docs/releases.md).
|
|
30
|
+
|
|
23
31
|
Run on worker A, inspect/resume on worker B, without a shared writable run
|
|
24
32
|
directory. Core remains database-free; install this separate adapter only when
|
|
25
33
|
you need shared durable state. The API is synchronous; a private I/O thread
|
|
26
34
|
bounds network waits. Model execution holds no database connection/transaction.
|
|
27
|
-
The
|
|
28
|
-
`b3-prosaic-harness>=0.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
The adapter is independently versioned: `b3-prosaic-harness-postgres` **0.4.2**
|
|
36
|
+
requires `b3-prosaic-harness>=0.9.13,<0.10`. PostgreSQL drivers remain optional for
|
|
37
|
+
core Harness users. Imports and CLI names are unchanged.
|
|
38
|
+
|
|
39
|
+
## Durability profiles
|
|
40
|
+
|
|
41
|
+
The default `durability_profile="postgresql"` requires `full_page_writes=on`.
|
|
42
|
+
An operator who has independently verified an Amazon Aurora PostgreSQL cluster
|
|
43
|
+
may explicitly select `durability_profile="aurora-postgresql"` on both
|
|
44
|
+
`PostgresRunStore` and `PostgresSessionStore` (including `from_env`). This accepts
|
|
45
|
+
`full_page_writes=off` under Aurora's log-based storage contract. It does not
|
|
46
|
+
weaken fsync, synchronous commit, writable-primary, logged-table, lease or
|
|
47
|
+
unknown-commit checks. The guard runs for every operation and connection reuse.
|
|
48
|
+
Invalid profiles fail before connecting. This profile is an operator assertion,
|
|
49
|
+
not engine autodetection or proof that arbitrary storage is safe. NEVER select
|
|
50
|
+
it for ordinary PostgreSQL just to suppress a readiness failure.
|
|
51
|
+
|
|
52
|
+
For every CLI command, pass `--durability-profile aurora-postgresql` explicitly.
|
|
53
|
+
Migration and runtime must select the same profile. Verify the actual engine and
|
|
54
|
+
version with AWS RDS metadata/DBA evidence; AWS also documents `aurora_version()`.
|
|
55
|
+
Capture a failed SQL probe's actual error and inspect its schema/search path;
|
|
56
|
+
NEVER convert an unavailable probe into permission to bypass durability checks.
|
|
57
|
+
No AWS credentials or model calls are needed by the adapter.
|
|
58
|
+
|
|
59
|
+
AWS describes the storage contract in
|
|
60
|
+
[its architecture guide](https://aws.amazon.com/blogs/database/is-amazon-rds-for-postgresql-or-amazon-aurora-postgresql-a-better-choice-for-me/).
|
|
61
|
+
Native PostgreSQL tests qualify the policy and all existing recovery behavior;
|
|
62
|
+
they do not emulate Aurora storage. An actual Aurora deployment needs synthetic
|
|
63
|
+
persistence/restart/failover qualification before enabling production work.
|
|
34
64
|
|
|
35
65
|
## 1. Install and supply an existing database
|
|
36
66
|
|
|
37
67
|
Python 3.11+, PostgreSQL 16 or 18 on a writable primary, and libpq 17+ are
|
|
38
68
|
required. `psycopg[binary]` supplies libpq; older libpq is rejected.
|
|
39
|
-
|
|
40
|
-
wheelhouse containing only the manifest-selected b3 candidate wheels:
|
|
69
|
+
Use a fresh environment and the published compatible SDKs:
|
|
41
70
|
|
|
42
71
|
```sh
|
|
43
72
|
python3 -m venv .venv-postgres
|
|
44
|
-
.venv-postgres/bin/python -m pip install
|
|
73
|
+
.venv-postgres/bin/python -m pip install 'b3-prosaic-harness==0.9.11' \
|
|
74
|
+
'b3-prosaic-runtime==0.9.19' 'b3-prosaic-harness-postgres==0.4.2'
|
|
45
75
|
export PATH="$PWD/.venv-postgres/bin:$PATH"
|
|
46
76
|
prosaic --version
|
|
47
77
|
prosaic-harness-postgres --help
|
|
@@ -49,8 +79,13 @@ prosaic-harness-postgres --help
|
|
|
49
79
|
|
|
50
80
|
ALWAYS migrate using a fresh environment or image; NEVER install legacy and b3
|
|
51
81
|
distributions together because they own the same import paths. See
|
|
52
|
-
[package migration](../../docs/package-migration.md).
|
|
53
|
-
|
|
82
|
+
[package migration](../../docs/package-migration.md). For reproducible installs,
|
|
83
|
+
verify the complete selected manifest's wheel hashes before installation.
|
|
84
|
+
|
|
85
|
+
Agent reasoning effort is passed through Harness to Runtime; this store does
|
|
86
|
+
not turn thinking on or prove provider compliance. Frozen prose/configuration
|
|
87
|
+
and workflow identity still govern resume. See [reasoning effort](../../docs/reasoning-effort.md)
|
|
88
|
+
and the Integration Lab's separate blueprint and control-check lane.
|
|
54
89
|
|
|
55
90
|
Harness does **not** provision PostgreSQL, create databases/users, start a
|
|
56
91
|
service, or fall back to files. Your operator supplies two DSNs through a secret
|
|
@@ -159,6 +194,10 @@ remain supported; the adapter adds no new workflow interpreter.
|
|
|
159
194
|
budget 10s, pool/connect 5s, row lock 1s, statement 5s. Deadlines cover pool,
|
|
160
195
|
network and COMMIT waits. Stalled connections are quarantined; unresolved
|
|
161
196
|
operations retain capacity and prevent unsafe close.
|
|
197
|
+
- Ordinary operations use the configured short lock timeout. Dedicated renewal
|
|
198
|
+
operations can wait for a same-owner write within the configured statement
|
|
199
|
+
and total operation deadlines. Failed renewal remains sticky; ownership and
|
|
200
|
+
generation checks still fence every write.
|
|
162
201
|
- Default lazy pool bounds per store/process: 8 ordinary + 4 renewal connections,
|
|
163
202
|
maximum 4 active leases. Renewal has reserved capacity. Multiply capacity
|
|
164
203
|
across replicas/namespaces; do not create a pool per HTTP request. Applications
|
|
@@ -213,7 +252,7 @@ python adapters/postgres/tests/support/local_cluster.py stop --manifest "$FIXTUR
|
|
|
213
252
|
Repeat with version 18. Stop validates exact IDs/names/ownership labels before
|
|
214
253
|
removing only owned containers/volumes/network. Generated fixture networks and
|
|
215
254
|
loopback ports use synthetic trust authentication, never production defaults.
|
|
216
|
-
# Lease registration
|
|
255
|
+
# Lease registration
|
|
217
256
|
|
|
218
257
|
The adapter transfers acquisition capacity into registered
|
|
219
258
|
session capacity atomically under the existing store mutex. A registering lease
|
|
@@ -223,7 +262,7 @@ an owned PostgreSQL 16/18 race regression cover the transition.
|
|
|
223
262
|
|
|
224
263
|
## Optional conversation sessions
|
|
225
264
|
|
|
226
|
-
|
|
265
|
+
Conversation storage provides `PostgresSessionStore` to this same optional
|
|
227
266
|
distribution. It implements the public Harness `SessionStore` contract and uses
|
|
228
267
|
the independent, logged `prosaic_harness_conversations` schema, storage version 1.
|
|
229
268
|
Existing `PostgresRunStore` tables, grants and CLI `init`/`doctor` behavior remain
|
|
@@ -315,7 +354,7 @@ The required adapter suite includes both the existing workflow backend and the
|
|
|
315
354
|
conversation backend. Run the owned PostgreSQL 16 and 18 fixtures shown above
|
|
316
355
|
with `--require-postgres`. Missing infrastructure or any skipped required case
|
|
317
356
|
fails qualification. Installed Linux AMD64 and ARM64 acceptance is required
|
|
318
|
-
before
|
|
357
|
+
before treating a conversation deployment as ready for production.
|
|
319
358
|
|
|
320
359
|
## Optional context storage contract
|
|
321
360
|
|
|
@@ -335,3 +374,31 @@ cannot update schema metadata. Old workers reject the upgraded storage contract.
|
|
|
335
374
|
Keep migration-owner credentials separate from runtime credentials. Enable host
|
|
336
375
|
context policies only after Runtime, Harness and store advertise the capability.
|
|
337
376
|
No production token counter is bundled or certified by this storage adapter.
|
|
377
|
+
|
|
378
|
+
## Context pack storage contracts
|
|
379
|
+
|
|
380
|
+
Context packs require workflow storage contract 2 or conversation storage
|
|
381
|
+
contract 3. A fresh installation can explicitly use
|
|
382
|
+
`store.initialize(context_packs=True)`. On an existing installation this call
|
|
383
|
+
refuses to upgrade: drain **all writers to the affected shared schema**, then
|
|
384
|
+
run the owner-only migration:
|
|
385
|
+
|
|
386
|
+
```sh
|
|
387
|
+
prosaic-harness-postgres migrate-context-packs --store workflows --dsn-env HARNESS_MIGRATION_DSN
|
|
388
|
+
prosaic-harness-postgres migrate-context-packs --store conversations --dsn-env HARNESS_MIGRATION_DSN
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
`store.migrate_context_pack_storage()` is the equivalent API for either store.
|
|
392
|
+
ALWAYS use migration-owner credentials and drain writers across namespaces.
|
|
393
|
+
NEVER migrate from a worker, readiness check, or model invocation. An active
|
|
394
|
+
lease in any namespace refuses migration. The schema-wide advisory lock and
|
|
395
|
+
transaction preserve existing record bytes, revisions and grants. Repeating a
|
|
396
|
+
completed migration is safe; older binaries reject the new schema version.
|
|
397
|
+
New workers continue reading legacy records. Runtime credentials cannot migrate.
|
|
398
|
+
|
|
399
|
+
The `context_packs_v1` capability appears only after explicit opt-in. Pack-aware
|
|
400
|
+
workflow documents use canonical UTF-8 JSON; existing workflow document bytes
|
|
401
|
+
and the conversation codec remain unchanged. Private snapshots and validation
|
|
402
|
+
facts remain inside the bounded checkpoint/receipt, subject to host scope and
|
|
403
|
+
retained-read authorization. No new database, blob table or automatic retention
|
|
404
|
+
policy is introduced.
|
|
@@ -1,27 +1,57 @@
|
|
|
1
1
|
# PostgreSQL persistence for Prosaic Harness
|
|
2
2
|
|
|
3
|
+
PostgreSQL adapter **0.4.2** requires Harness **0.9.13** or later
|
|
4
|
+
in the compatible family. Explicit owner migration enables
|
|
5
|
+
workflow storage contract2 or conversation contract3; readiness performs no DDL.
|
|
6
|
+
See [context-pack migration and rollback](../../docs/context-packs.md#current-authorization-and-durable-storage).
|
|
7
|
+
|
|
8
|
+
See [0.4.2 release and migration notes](../../docs/release-postgres-0.4.2.md)
|
|
9
|
+
and [compatible SDK versions](https://github.com/B3Cognition/prosaic-harness/blob/main/docs/releases.md).
|
|
10
|
+
|
|
3
11
|
Run on worker A, inspect/resume on worker B, without a shared writable run
|
|
4
12
|
directory. Core remains database-free; install this separate adapter only when
|
|
5
13
|
you need shared durable state. The API is synchronous; a private I/O thread
|
|
6
14
|
bounds network waits. Model execution holds no database connection/transaction.
|
|
7
|
-
The
|
|
8
|
-
`b3-prosaic-harness>=0.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
The adapter is independently versioned: `b3-prosaic-harness-postgres` **0.4.2**
|
|
16
|
+
requires `b3-prosaic-harness>=0.9.13,<0.10`. PostgreSQL drivers remain optional for
|
|
17
|
+
core Harness users. Imports and CLI names are unchanged.
|
|
18
|
+
|
|
19
|
+
## Durability profiles
|
|
20
|
+
|
|
21
|
+
The default `durability_profile="postgresql"` requires `full_page_writes=on`.
|
|
22
|
+
An operator who has independently verified an Amazon Aurora PostgreSQL cluster
|
|
23
|
+
may explicitly select `durability_profile="aurora-postgresql"` on both
|
|
24
|
+
`PostgresRunStore` and `PostgresSessionStore` (including `from_env`). This accepts
|
|
25
|
+
`full_page_writes=off` under Aurora's log-based storage contract. It does not
|
|
26
|
+
weaken fsync, synchronous commit, writable-primary, logged-table, lease or
|
|
27
|
+
unknown-commit checks. The guard runs for every operation and connection reuse.
|
|
28
|
+
Invalid profiles fail before connecting. This profile is an operator assertion,
|
|
29
|
+
not engine autodetection or proof that arbitrary storage is safe. NEVER select
|
|
30
|
+
it for ordinary PostgreSQL just to suppress a readiness failure.
|
|
31
|
+
|
|
32
|
+
For every CLI command, pass `--durability-profile aurora-postgresql` explicitly.
|
|
33
|
+
Migration and runtime must select the same profile. Verify the actual engine and
|
|
34
|
+
version with AWS RDS metadata/DBA evidence; AWS also documents `aurora_version()`.
|
|
35
|
+
Capture a failed SQL probe's actual error and inspect its schema/search path;
|
|
36
|
+
NEVER convert an unavailable probe into permission to bypass durability checks.
|
|
37
|
+
No AWS credentials or model calls are needed by the adapter.
|
|
38
|
+
|
|
39
|
+
AWS describes the storage contract in
|
|
40
|
+
[its architecture guide](https://aws.amazon.com/blogs/database/is-amazon-rds-for-postgresql-or-amazon-aurora-postgresql-a-better-choice-for-me/).
|
|
41
|
+
Native PostgreSQL tests qualify the policy and all existing recovery behavior;
|
|
42
|
+
they do not emulate Aurora storage. An actual Aurora deployment needs synthetic
|
|
43
|
+
persistence/restart/failover qualification before enabling production work.
|
|
14
44
|
|
|
15
45
|
## 1. Install and supply an existing database
|
|
16
46
|
|
|
17
47
|
Python 3.11+, PostgreSQL 16 or 18 on a writable primary, and libpq 17+ are
|
|
18
48
|
required. `psycopg[binary]` supplies libpq; older libpq is rejected.
|
|
19
|
-
|
|
20
|
-
wheelhouse containing only the manifest-selected b3 candidate wheels:
|
|
49
|
+
Use a fresh environment and the published compatible SDKs:
|
|
21
50
|
|
|
22
51
|
```sh
|
|
23
52
|
python3 -m venv .venv-postgres
|
|
24
|
-
.venv-postgres/bin/python -m pip install
|
|
53
|
+
.venv-postgres/bin/python -m pip install 'b3-prosaic-harness==0.9.11' \
|
|
54
|
+
'b3-prosaic-runtime==0.9.19' 'b3-prosaic-harness-postgres==0.4.2'
|
|
25
55
|
export PATH="$PWD/.venv-postgres/bin:$PATH"
|
|
26
56
|
prosaic --version
|
|
27
57
|
prosaic-harness-postgres --help
|
|
@@ -29,8 +59,13 @@ prosaic-harness-postgres --help
|
|
|
29
59
|
|
|
30
60
|
ALWAYS migrate using a fresh environment or image; NEVER install legacy and b3
|
|
31
61
|
distributions together because they own the same import paths. See
|
|
32
|
-
[package migration](../../docs/package-migration.md).
|
|
33
|
-
|
|
62
|
+
[package migration](../../docs/package-migration.md). For reproducible installs,
|
|
63
|
+
verify the complete selected manifest's wheel hashes before installation.
|
|
64
|
+
|
|
65
|
+
Agent reasoning effort is passed through Harness to Runtime; this store does
|
|
66
|
+
not turn thinking on or prove provider compliance. Frozen prose/configuration
|
|
67
|
+
and workflow identity still govern resume. See [reasoning effort](../../docs/reasoning-effort.md)
|
|
68
|
+
and the Integration Lab's separate blueprint and control-check lane.
|
|
34
69
|
|
|
35
70
|
Harness does **not** provision PostgreSQL, create databases/users, start a
|
|
36
71
|
service, or fall back to files. Your operator supplies two DSNs through a secret
|
|
@@ -139,6 +174,10 @@ remain supported; the adapter adds no new workflow interpreter.
|
|
|
139
174
|
budget 10s, pool/connect 5s, row lock 1s, statement 5s. Deadlines cover pool,
|
|
140
175
|
network and COMMIT waits. Stalled connections are quarantined; unresolved
|
|
141
176
|
operations retain capacity and prevent unsafe close.
|
|
177
|
+
- Ordinary operations use the configured short lock timeout. Dedicated renewal
|
|
178
|
+
operations can wait for a same-owner write within the configured statement
|
|
179
|
+
and total operation deadlines. Failed renewal remains sticky; ownership and
|
|
180
|
+
generation checks still fence every write.
|
|
142
181
|
- Default lazy pool bounds per store/process: 8 ordinary + 4 renewal connections,
|
|
143
182
|
maximum 4 active leases. Renewal has reserved capacity. Multiply capacity
|
|
144
183
|
across replicas/namespaces; do not create a pool per HTTP request. Applications
|
|
@@ -193,7 +232,7 @@ python adapters/postgres/tests/support/local_cluster.py stop --manifest "$FIXTUR
|
|
|
193
232
|
Repeat with version 18. Stop validates exact IDs/names/ownership labels before
|
|
194
233
|
removing only owned containers/volumes/network. Generated fixture networks and
|
|
195
234
|
loopback ports use synthetic trust authentication, never production defaults.
|
|
196
|
-
# Lease registration
|
|
235
|
+
# Lease registration
|
|
197
236
|
|
|
198
237
|
The adapter transfers acquisition capacity into registered
|
|
199
238
|
session capacity atomically under the existing store mutex. A registering lease
|
|
@@ -203,7 +242,7 @@ an owned PostgreSQL 16/18 race regression cover the transition.
|
|
|
203
242
|
|
|
204
243
|
## Optional conversation sessions
|
|
205
244
|
|
|
206
|
-
|
|
245
|
+
Conversation storage provides `PostgresSessionStore` to this same optional
|
|
207
246
|
distribution. It implements the public Harness `SessionStore` contract and uses
|
|
208
247
|
the independent, logged `prosaic_harness_conversations` schema, storage version 1.
|
|
209
248
|
Existing `PostgresRunStore` tables, grants and CLI `init`/`doctor` behavior remain
|
|
@@ -295,7 +334,7 @@ The required adapter suite includes both the existing workflow backend and the
|
|
|
295
334
|
conversation backend. Run the owned PostgreSQL 16 and 18 fixtures shown above
|
|
296
335
|
with `--require-postgres`. Missing infrastructure or any skipped required case
|
|
297
336
|
fails qualification. Installed Linux AMD64 and ARM64 acceptance is required
|
|
298
|
-
before
|
|
337
|
+
before treating a conversation deployment as ready for production.
|
|
299
338
|
|
|
300
339
|
## Optional context storage contract
|
|
301
340
|
|
|
@@ -315,3 +354,31 @@ cannot update schema metadata. Old workers reject the upgraded storage contract.
|
|
|
315
354
|
Keep migration-owner credentials separate from runtime credentials. Enable host
|
|
316
355
|
context policies only after Runtime, Harness and store advertise the capability.
|
|
317
356
|
No production token counter is bundled or certified by this storage adapter.
|
|
357
|
+
|
|
358
|
+
## Context pack storage contracts
|
|
359
|
+
|
|
360
|
+
Context packs require workflow storage contract 2 or conversation storage
|
|
361
|
+
contract 3. A fresh installation can explicitly use
|
|
362
|
+
`store.initialize(context_packs=True)`. On an existing installation this call
|
|
363
|
+
refuses to upgrade: drain **all writers to the affected shared schema**, then
|
|
364
|
+
run the owner-only migration:
|
|
365
|
+
|
|
366
|
+
```sh
|
|
367
|
+
prosaic-harness-postgres migrate-context-packs --store workflows --dsn-env HARNESS_MIGRATION_DSN
|
|
368
|
+
prosaic-harness-postgres migrate-context-packs --store conversations --dsn-env HARNESS_MIGRATION_DSN
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
`store.migrate_context_pack_storage()` is the equivalent API for either store.
|
|
372
|
+
ALWAYS use migration-owner credentials and drain writers across namespaces.
|
|
373
|
+
NEVER migrate from a worker, readiness check, or model invocation. An active
|
|
374
|
+
lease in any namespace refuses migration. The schema-wide advisory lock and
|
|
375
|
+
transaction preserve existing record bytes, revisions and grants. Repeating a
|
|
376
|
+
completed migration is safe; older binaries reject the new schema version.
|
|
377
|
+
New workers continue reading legacy records. Runtime credentials cannot migrate.
|
|
378
|
+
|
|
379
|
+
The `context_packs_v1` capability appears only after explicit opt-in. Pack-aware
|
|
380
|
+
workflow documents use canonical UTF-8 JSON; existing workflow document bytes
|
|
381
|
+
and the conversation codec remain unchanged. Private snapshots and validation
|
|
382
|
+
facts remain inside the bounded checkpoint/receipt, subject to host scope and
|
|
383
|
+
retained-read authorization. No new database, blob table or automatic retention
|
|
384
|
+
policy is introduced.
|
|
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "b3-prosaic-harness-postgres"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.2"
|
|
8
8
|
description = "Explicit PostgreSQL run and conversation storage for Prosaic Harness"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
license = "Apache-2.0"
|
|
12
12
|
license-files = ["LICENSE", "NOTICE"]
|
|
13
|
-
dependencies = ["b3-prosaic-harness>=0.9,<0.10", "psycopg[binary]>=3.2.3,<4", "psycopg-pool>=3.2,<4"]
|
|
13
|
+
dependencies = ["b3-prosaic-harness>=0.9.13,<0.10", "psycopg[binary]>=3.2.3,<4", "psycopg-pool>=3.2,<4"]
|
|
14
14
|
|
|
15
15
|
[project.optional-dependencies]
|
|
16
16
|
test = ["pytest>=8", "build>=1", "setuptools>=77", "wheel", "packaging"]
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: b3-prosaic-harness-postgres
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Explicit PostgreSQL run and conversation storage for Prosaic Harness
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.11
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
License-File: NOTICE
|
|
10
|
-
Requires-Dist: b3-prosaic-harness<0.10,>=0.9
|
|
10
|
+
Requires-Dist: b3-prosaic-harness<0.10,>=0.9.13
|
|
11
11
|
Requires-Dist: psycopg[binary]<4,>=3.2.3
|
|
12
12
|
Requires-Dist: psycopg-pool<4,>=3.2
|
|
13
13
|
Provides-Extra: test
|
|
@@ -20,28 +20,58 @@ Dynamic: license-file
|
|
|
20
20
|
|
|
21
21
|
# PostgreSQL persistence for Prosaic Harness
|
|
22
22
|
|
|
23
|
+
PostgreSQL adapter **0.4.2** requires Harness **0.9.13** or later
|
|
24
|
+
in the compatible family. Explicit owner migration enables
|
|
25
|
+
workflow storage contract2 or conversation contract3; readiness performs no DDL.
|
|
26
|
+
See [context-pack migration and rollback](../../docs/context-packs.md#current-authorization-and-durable-storage).
|
|
27
|
+
|
|
28
|
+
See [0.4.2 release and migration notes](../../docs/release-postgres-0.4.2.md)
|
|
29
|
+
and [compatible SDK versions](https://github.com/B3Cognition/prosaic-harness/blob/main/docs/releases.md).
|
|
30
|
+
|
|
23
31
|
Run on worker A, inspect/resume on worker B, without a shared writable run
|
|
24
32
|
directory. Core remains database-free; install this separate adapter only when
|
|
25
33
|
you need shared durable state. The API is synchronous; a private I/O thread
|
|
26
34
|
bounds network waits. Model execution holds no database connection/transaction.
|
|
27
|
-
The
|
|
28
|
-
`b3-prosaic-harness>=0.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
The adapter is independently versioned: `b3-prosaic-harness-postgres` **0.4.2**
|
|
36
|
+
requires `b3-prosaic-harness>=0.9.13,<0.10`. PostgreSQL drivers remain optional for
|
|
37
|
+
core Harness users. Imports and CLI names are unchanged.
|
|
38
|
+
|
|
39
|
+
## Durability profiles
|
|
40
|
+
|
|
41
|
+
The default `durability_profile="postgresql"` requires `full_page_writes=on`.
|
|
42
|
+
An operator who has independently verified an Amazon Aurora PostgreSQL cluster
|
|
43
|
+
may explicitly select `durability_profile="aurora-postgresql"` on both
|
|
44
|
+
`PostgresRunStore` and `PostgresSessionStore` (including `from_env`). This accepts
|
|
45
|
+
`full_page_writes=off` under Aurora's log-based storage contract. It does not
|
|
46
|
+
weaken fsync, synchronous commit, writable-primary, logged-table, lease or
|
|
47
|
+
unknown-commit checks. The guard runs for every operation and connection reuse.
|
|
48
|
+
Invalid profiles fail before connecting. This profile is an operator assertion,
|
|
49
|
+
not engine autodetection or proof that arbitrary storage is safe. NEVER select
|
|
50
|
+
it for ordinary PostgreSQL just to suppress a readiness failure.
|
|
51
|
+
|
|
52
|
+
For every CLI command, pass `--durability-profile aurora-postgresql` explicitly.
|
|
53
|
+
Migration and runtime must select the same profile. Verify the actual engine and
|
|
54
|
+
version with AWS RDS metadata/DBA evidence; AWS also documents `aurora_version()`.
|
|
55
|
+
Capture a failed SQL probe's actual error and inspect its schema/search path;
|
|
56
|
+
NEVER convert an unavailable probe into permission to bypass durability checks.
|
|
57
|
+
No AWS credentials or model calls are needed by the adapter.
|
|
58
|
+
|
|
59
|
+
AWS describes the storage contract in
|
|
60
|
+
[its architecture guide](https://aws.amazon.com/blogs/database/is-amazon-rds-for-postgresql-or-amazon-aurora-postgresql-a-better-choice-for-me/).
|
|
61
|
+
Native PostgreSQL tests qualify the policy and all existing recovery behavior;
|
|
62
|
+
they do not emulate Aurora storage. An actual Aurora deployment needs synthetic
|
|
63
|
+
persistence/restart/failover qualification before enabling production work.
|
|
34
64
|
|
|
35
65
|
## 1. Install and supply an existing database
|
|
36
66
|
|
|
37
67
|
Python 3.11+, PostgreSQL 16 or 18 on a writable primary, and libpq 17+ are
|
|
38
68
|
required. `psycopg[binary]` supplies libpq; older libpq is rejected.
|
|
39
|
-
|
|
40
|
-
wheelhouse containing only the manifest-selected b3 candidate wheels:
|
|
69
|
+
Use a fresh environment and the published compatible SDKs:
|
|
41
70
|
|
|
42
71
|
```sh
|
|
43
72
|
python3 -m venv .venv-postgres
|
|
44
|
-
.venv-postgres/bin/python -m pip install
|
|
73
|
+
.venv-postgres/bin/python -m pip install 'b3-prosaic-harness==0.9.11' \
|
|
74
|
+
'b3-prosaic-runtime==0.9.19' 'b3-prosaic-harness-postgres==0.4.2'
|
|
45
75
|
export PATH="$PWD/.venv-postgres/bin:$PATH"
|
|
46
76
|
prosaic --version
|
|
47
77
|
prosaic-harness-postgres --help
|
|
@@ -49,8 +79,13 @@ prosaic-harness-postgres --help
|
|
|
49
79
|
|
|
50
80
|
ALWAYS migrate using a fresh environment or image; NEVER install legacy and b3
|
|
51
81
|
distributions together because they own the same import paths. See
|
|
52
|
-
[package migration](../../docs/package-migration.md).
|
|
53
|
-
|
|
82
|
+
[package migration](../../docs/package-migration.md). For reproducible installs,
|
|
83
|
+
verify the complete selected manifest's wheel hashes before installation.
|
|
84
|
+
|
|
85
|
+
Agent reasoning effort is passed through Harness to Runtime; this store does
|
|
86
|
+
not turn thinking on or prove provider compliance. Frozen prose/configuration
|
|
87
|
+
and workflow identity still govern resume. See [reasoning effort](../../docs/reasoning-effort.md)
|
|
88
|
+
and the Integration Lab's separate blueprint and control-check lane.
|
|
54
89
|
|
|
55
90
|
Harness does **not** provision PostgreSQL, create databases/users, start a
|
|
56
91
|
service, or fall back to files. Your operator supplies two DSNs through a secret
|
|
@@ -159,6 +194,10 @@ remain supported; the adapter adds no new workflow interpreter.
|
|
|
159
194
|
budget 10s, pool/connect 5s, row lock 1s, statement 5s. Deadlines cover pool,
|
|
160
195
|
network and COMMIT waits. Stalled connections are quarantined; unresolved
|
|
161
196
|
operations retain capacity and prevent unsafe close.
|
|
197
|
+
- Ordinary operations use the configured short lock timeout. Dedicated renewal
|
|
198
|
+
operations can wait for a same-owner write within the configured statement
|
|
199
|
+
and total operation deadlines. Failed renewal remains sticky; ownership and
|
|
200
|
+
generation checks still fence every write.
|
|
162
201
|
- Default lazy pool bounds per store/process: 8 ordinary + 4 renewal connections,
|
|
163
202
|
maximum 4 active leases. Renewal has reserved capacity. Multiply capacity
|
|
164
203
|
across replicas/namespaces; do not create a pool per HTTP request. Applications
|
|
@@ -213,7 +252,7 @@ python adapters/postgres/tests/support/local_cluster.py stop --manifest "$FIXTUR
|
|
|
213
252
|
Repeat with version 18. Stop validates exact IDs/names/ownership labels before
|
|
214
253
|
removing only owned containers/volumes/network. Generated fixture networks and
|
|
215
254
|
loopback ports use synthetic trust authentication, never production defaults.
|
|
216
|
-
# Lease registration
|
|
255
|
+
# Lease registration
|
|
217
256
|
|
|
218
257
|
The adapter transfers acquisition capacity into registered
|
|
219
258
|
session capacity atomically under the existing store mutex. A registering lease
|
|
@@ -223,7 +262,7 @@ an owned PostgreSQL 16/18 race regression cover the transition.
|
|
|
223
262
|
|
|
224
263
|
## Optional conversation sessions
|
|
225
264
|
|
|
226
|
-
|
|
265
|
+
Conversation storage provides `PostgresSessionStore` to this same optional
|
|
227
266
|
distribution. It implements the public Harness `SessionStore` contract and uses
|
|
228
267
|
the independent, logged `prosaic_harness_conversations` schema, storage version 1.
|
|
229
268
|
Existing `PostgresRunStore` tables, grants and CLI `init`/`doctor` behavior remain
|
|
@@ -315,7 +354,7 @@ The required adapter suite includes both the existing workflow backend and the
|
|
|
315
354
|
conversation backend. Run the owned PostgreSQL 16 and 18 fixtures shown above
|
|
316
355
|
with `--require-postgres`. Missing infrastructure or any skipped required case
|
|
317
356
|
fails qualification. Installed Linux AMD64 and ARM64 acceptance is required
|
|
318
|
-
before
|
|
357
|
+
before treating a conversation deployment as ready for production.
|
|
319
358
|
|
|
320
359
|
## Optional context storage contract
|
|
321
360
|
|
|
@@ -335,3 +374,31 @@ cannot update schema metadata. Old workers reject the upgraded storage contract.
|
|
|
335
374
|
Keep migration-owner credentials separate from runtime credentials. Enable host
|
|
336
375
|
context policies only after Runtime, Harness and store advertise the capability.
|
|
337
376
|
No production token counter is bundled or certified by this storage adapter.
|
|
377
|
+
|
|
378
|
+
## Context pack storage contracts
|
|
379
|
+
|
|
380
|
+
Context packs require workflow storage contract 2 or conversation storage
|
|
381
|
+
contract 3. A fresh installation can explicitly use
|
|
382
|
+
`store.initialize(context_packs=True)`. On an existing installation this call
|
|
383
|
+
refuses to upgrade: drain **all writers to the affected shared schema**, then
|
|
384
|
+
run the owner-only migration:
|
|
385
|
+
|
|
386
|
+
```sh
|
|
387
|
+
prosaic-harness-postgres migrate-context-packs --store workflows --dsn-env HARNESS_MIGRATION_DSN
|
|
388
|
+
prosaic-harness-postgres migrate-context-packs --store conversations --dsn-env HARNESS_MIGRATION_DSN
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
`store.migrate_context_pack_storage()` is the equivalent API for either store.
|
|
392
|
+
ALWAYS use migration-owner credentials and drain writers across namespaces.
|
|
393
|
+
NEVER migrate from a worker, readiness check, or model invocation. An active
|
|
394
|
+
lease in any namespace refuses migration. The schema-wide advisory lock and
|
|
395
|
+
transaction preserve existing record bytes, revisions and grants. Repeating a
|
|
396
|
+
completed migration is safe; older binaries reject the new schema version.
|
|
397
|
+
New workers continue reading legacy records. Runtime credentials cannot migrate.
|
|
398
|
+
|
|
399
|
+
The `context_packs_v1` capability appears only after explicit opt-in. Pack-aware
|
|
400
|
+
workflow documents use canonical UTF-8 JSON; existing workflow document bytes
|
|
401
|
+
and the conversation codec remain unchanged. Private snapshots and validation
|
|
402
|
+
facts remain inside the bounded checkpoint/receipt, subject to host scope and
|
|
403
|
+
retained-read authorization. No new database, blob table or automatic retention
|
|
404
|
+
policy is introduced.
|
|
@@ -12,6 +12,7 @@ src/b3_prosaic_harness_postgres.egg-info/top_level.txt
|
|
|
12
12
|
src/prosaic_harness_postgres/__init__.py
|
|
13
13
|
src/prosaic_harness_postgres/cli.py
|
|
14
14
|
src/prosaic_harness_postgres/leases.py
|
|
15
|
+
src/prosaic_harness_postgres/pack_schema.py
|
|
15
16
|
src/prosaic_harness_postgres/schema.py
|
|
16
17
|
src/prosaic_harness_postgres/session_leases.py
|
|
17
18
|
src/prosaic_harness_postgres/session_schema.py
|
|
@@ -20,7 +21,11 @@ src/prosaic_harness_postgres/store.py
|
|
|
20
21
|
src/prosaic_harness_postgres/transport.py
|
|
21
22
|
tests/conftest.py
|
|
22
23
|
tests/test_cli.py
|
|
24
|
+
tests/test_context_pack_migrations.py
|
|
25
|
+
tests/test_context_pack_platform.py
|
|
26
|
+
tests/test_context_pack_recovery.py
|
|
23
27
|
tests/test_durability.py
|
|
28
|
+
tests/test_durability_profiles.py
|
|
24
29
|
tests/test_engine.py
|
|
25
30
|
tests/test_examples.py
|
|
26
31
|
tests/test_leases.py
|
|
@@ -29,6 +34,7 @@ tests/test_native_factory.py
|
|
|
29
34
|
tests/test_packaging.py
|
|
30
35
|
tests/test_recovery.py
|
|
31
36
|
tests/test_registration.py
|
|
37
|
+
tests/test_renewal_contention.py
|
|
32
38
|
tests/test_routing.py
|
|
33
39
|
tests/test_schema.py
|
|
34
40
|
tests/test_session_context.py
|
|
@@ -44,21 +44,31 @@ def check_write(store):
|
|
|
44
44
|
def main(argv=None):
|
|
45
45
|
parser = argparse.ArgumentParser(description='Initialize/check an existing Harness database')
|
|
46
46
|
commands = parser.add_subparsers(dest='command', required=True)
|
|
47
|
-
for name in ('init', 'doctor', 'migrate-conversations'):
|
|
47
|
+
for name in ('init', 'doctor', 'migrate-conversations','migrate-context-packs'):
|
|
48
48
|
command = commands.add_parser(name)
|
|
49
49
|
command.add_argument('--dsn-env', required=True, help='name of the DSN environment variable, never its value')
|
|
50
|
+
command.add_argument('--durability-profile', choices=['postgresql', 'aurora-postgresql'],
|
|
51
|
+
default='postgresql', help='explicit operator-verified database storage contract')
|
|
52
|
+
if name=='migrate-context-packs': command.add_argument('--store',choices=['workflows','conversations'],required=True)
|
|
50
53
|
if name == 'doctor':
|
|
51
54
|
command.add_argument('--check-write', action='store_true', help='explicit disposable write test; DELETE credentials required')
|
|
52
55
|
args = parser.parse_args(argv)
|
|
53
56
|
try:
|
|
57
|
+
if args.command=='migrate-context-packs':
|
|
58
|
+
from .session_store import PostgresSessionStore
|
|
59
|
+
cls=PostgresRunStore if args.store=='workflows' else PostgresSessionStore
|
|
60
|
+
with cls.from_env(args.dsn_env,namespace='pack-migration',durability_profile=args.durability_profile) as store:
|
|
61
|
+
store.migrate_context_pack_storage()
|
|
62
|
+
print(json.dumps({'migrated':True,'store':args.store,'storage_contract':2 if args.store=='workflows' else 3}))
|
|
63
|
+
return 0
|
|
54
64
|
if args.command == 'migrate-conversations':
|
|
55
65
|
from .session_store import PostgresSessionStore
|
|
56
|
-
with PostgresSessionStore.from_env(args.dsn_env, namespace='conversation-migration') as store:
|
|
66
|
+
with PostgresSessionStore.from_env(args.dsn_env, namespace='conversation-migration', durability_profile=args.durability_profile) as store:
|
|
57
67
|
store.migrate_context_storage()
|
|
58
68
|
print(json.dumps({'migrated': True, 'conversation_storage_contract': 2}))
|
|
59
69
|
return 0
|
|
60
70
|
namespace = 'prosaic-diagnostic-' + uuid.uuid4().hex
|
|
61
|
-
with PostgresRunStore.from_env(args.dsn_env, namespace=namespace) as store:
|
|
71
|
+
with PostgresRunStore.from_env(args.dsn_env, namespace=namespace, durability_profile=args.durability_profile) as store:
|
|
62
72
|
if args.command == 'init':
|
|
63
73
|
store.initialize()
|
|
64
74
|
result = {'initialized': True, 'schema_version': 1}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Owner-only, schema-wide opt-in; never rewrite run or receipt documents."""
|
|
2
|
+
from prosaic_harness import StoreIncompatible,StoreUninitialized,StoreBusy
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def migrate(transport,*,schema,target,versions,lock,ready):
|
|
6
|
+
# These identifiers are internal constants, never user/model data.
|
|
7
|
+
if (schema,target) not in {('prosaic_harness',2),('prosaic_harness_conversations',3)}:
|
|
8
|
+
raise StoreIncompatible()
|
|
9
|
+
async def operation(conn):
|
|
10
|
+
await conn.execute("SELECT pg_catalog.set_config('lock_timeout','25000ms',true), "
|
|
11
|
+
"pg_catalog.set_config('statement_timeout','28000ms',true)")
|
|
12
|
+
await conn.execute('SELECT pg_catalog.pg_advisory_xact_lock(%s)',(lock,))
|
|
13
|
+
owner=await (await conn.execute("SELECT pg_catalog.pg_has_role(nspowner,'USAGE') "
|
|
14
|
+
'FROM pg_catalog.pg_namespace WHERE nspname=%s',(schema,))).fetchone()
|
|
15
|
+
if owner is None: raise StoreUninitialized('initialize storage explicitly first')
|
|
16
|
+
if owner[0] is not True: raise StoreIncompatible('migration role must own the adapter schema')
|
|
17
|
+
current=await (await conn.execute('SELECT schema_version,storage_contract_version FROM '+schema+'.schema_version')).fetchall()
|
|
18
|
+
if len(current)!=1 or current[0] not in versions: raise StoreIncompatible('migration requires intact known storage')
|
|
19
|
+
await ready(conn,expected_versions=current[0])
|
|
20
|
+
if current[0]==(target,target): return
|
|
21
|
+
# Includes every namespace. This transaction is brief and never spans
|
|
22
|
+
# inference, a counter, a validator or any host callback.
|
|
23
|
+
await conn.execute('LOCK TABLE '+schema+'.leases IN EXCLUSIVE MODE')
|
|
24
|
+
active=await (await conn.execute('SELECT EXISTS(SELECT 1 FROM '+schema+'.leases '
|
|
25
|
+
'WHERE owner IS NOT NULL AND expires_at>pg_catalog.clock_timestamp())')).fetchone()
|
|
26
|
+
if active[0]: raise StoreBusy('drain all writers to the shared schema before migration')
|
|
27
|
+
changed=await conn.execute('UPDATE '+schema+'.schema_version '
|
|
28
|
+
'SET schema_version=%s,storage_contract_version=%s WHERE singleton IS TRUE',(target,target))
|
|
29
|
+
if changed.rowcount!=1: raise StoreIncompatible()
|
|
30
|
+
await ready(conn,expected_versions=(target,target))
|
|
31
|
+
return transport.call(operation,timeout_s=30)
|