b3-prosaic-harness-postgres 0.4.1__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.1/src/b3_prosaic_harness_postgres.egg-info → b3_prosaic_harness_postgres-0.4.2}/PKG-INFO +57 -12
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/README.md +55 -10
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/pyproject.toml +2 -2
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2/src/b3_prosaic_harness_postgres.egg-info}/PKG-INFO +57 -12
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/src/b3_prosaic_harness_postgres.egg-info/SOURCES.txt +5 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/src/b3_prosaic_harness_postgres.egg-info/requires.txt +1 -1
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/__init__.py +1 -1
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/cli.py +9 -1
- b3_prosaic_harness_postgres-0.4.2/src/prosaic_harness_postgres/pack_schema.py +31 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/schema.py +17 -5
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/session_schema.py +17 -5
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/session_store.py +16 -4
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/store.py +17 -2
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/transport.py +7 -1
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/support/local_cluster.py +40 -9
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/support/session_documents.py +46 -0
- {b3_prosaic_harness_postgres-0.4.1 → 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.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_packaging.py +25 -8
- b3_prosaic_harness_postgres-0.4.2/tests/test_renewal_contention.py +39 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/LICENSE +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/MANIFEST.in +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/NOTICE +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/setup.cfg +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → 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.1 → 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.1 → 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.1 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/leases.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/session_leases.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/conftest.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/support/linux_wheel_smoke.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/support/model_server.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/support/tcp_proxy.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/support/workers.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_cli.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_durability.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_durability_profiles.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_engine.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_examples.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_leases.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_local_cluster.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_native_factory.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_recovery.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_registration.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_routing.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_schema.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_context.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_fencing.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_recovery.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_schema.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_store.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_workers.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_store.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → b3_prosaic_harness_postgres-0.4.2}/tests/test_transport.py +0 -0
- {b3_prosaic_harness_postgres-0.4.1 → 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,12 +20,20 @@ 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 adapter is independently versioned: `b3-prosaic-harness-postgres` **0.4.
|
|
28
|
-
requires `b3-prosaic-harness>=0.9,<0.10`. PostgreSQL drivers remain optional for
|
|
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
|
|
29
37
|
core Harness users. Imports and CLI names are unchanged.
|
|
30
38
|
|
|
31
39
|
## Durability profiles
|
|
@@ -58,12 +66,12 @@ persistence/restart/failover qualification before enabling production work.
|
|
|
58
66
|
|
|
59
67
|
Python 3.11+, PostgreSQL 16 or 18 on a writable primary, and libpq 17+ are
|
|
60
68
|
required. `psycopg[binary]` supplies libpq; older libpq is rejected.
|
|
61
|
-
|
|
62
|
-
wheelhouse containing only the manifest-selected b3 candidate wheels:
|
|
69
|
+
Use a fresh environment and the published compatible SDKs:
|
|
63
70
|
|
|
64
71
|
```sh
|
|
65
72
|
python3 -m venv .venv-postgres
|
|
66
|
-
.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'
|
|
67
75
|
export PATH="$PWD/.venv-postgres/bin:$PATH"
|
|
68
76
|
prosaic --version
|
|
69
77
|
prosaic-harness-postgres --help
|
|
@@ -71,8 +79,13 @@ prosaic-harness-postgres --help
|
|
|
71
79
|
|
|
72
80
|
ALWAYS migrate using a fresh environment or image; NEVER install legacy and b3
|
|
73
81
|
distributions together because they own the same import paths. See
|
|
74
|
-
[package migration](../../docs/package-migration.md).
|
|
75
|
-
|
|
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.
|
|
76
89
|
|
|
77
90
|
Harness does **not** provision PostgreSQL, create databases/users, start a
|
|
78
91
|
service, or fall back to files. Your operator supplies two DSNs through a secret
|
|
@@ -181,6 +194,10 @@ remain supported; the adapter adds no new workflow interpreter.
|
|
|
181
194
|
budget 10s, pool/connect 5s, row lock 1s, statement 5s. Deadlines cover pool,
|
|
182
195
|
network and COMMIT waits. Stalled connections are quarantined; unresolved
|
|
183
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.
|
|
184
201
|
- Default lazy pool bounds per store/process: 8 ordinary + 4 renewal connections,
|
|
185
202
|
maximum 4 active leases. Renewal has reserved capacity. Multiply capacity
|
|
186
203
|
across replicas/namespaces; do not create a pool per HTTP request. Applications
|
|
@@ -235,7 +252,7 @@ python adapters/postgres/tests/support/local_cluster.py stop --manifest "$FIXTUR
|
|
|
235
252
|
Repeat with version 18. Stop validates exact IDs/names/ownership labels before
|
|
236
253
|
removing only owned containers/volumes/network. Generated fixture networks and
|
|
237
254
|
loopback ports use synthetic trust authentication, never production defaults.
|
|
238
|
-
# Lease registration
|
|
255
|
+
# Lease registration
|
|
239
256
|
|
|
240
257
|
The adapter transfers acquisition capacity into registered
|
|
241
258
|
session capacity atomically under the existing store mutex. A registering lease
|
|
@@ -245,7 +262,7 @@ an owned PostgreSQL 16/18 race regression cover the transition.
|
|
|
245
262
|
|
|
246
263
|
## Optional conversation sessions
|
|
247
264
|
|
|
248
|
-
|
|
265
|
+
Conversation storage provides `PostgresSessionStore` to this same optional
|
|
249
266
|
distribution. It implements the public Harness `SessionStore` contract and uses
|
|
250
267
|
the independent, logged `prosaic_harness_conversations` schema, storage version 1.
|
|
251
268
|
Existing `PostgresRunStore` tables, grants and CLI `init`/`doctor` behavior remain
|
|
@@ -337,7 +354,7 @@ The required adapter suite includes both the existing workflow backend and the
|
|
|
337
354
|
conversation backend. Run the owned PostgreSQL 16 and 18 fixtures shown above
|
|
338
355
|
with `--require-postgres`. Missing infrastructure or any skipped required case
|
|
339
356
|
fails qualification. Installed Linux AMD64 and ARM64 acceptance is required
|
|
340
|
-
before
|
|
357
|
+
before treating a conversation deployment as ready for production.
|
|
341
358
|
|
|
342
359
|
## Optional context storage contract
|
|
343
360
|
|
|
@@ -357,3 +374,31 @@ cannot update schema metadata. Old workers reject the upgraded storage contract.
|
|
|
357
374
|
Keep migration-owner credentials separate from runtime credentials. Enable host
|
|
358
375
|
context policies only after Runtime, Harness and store advertise the capability.
|
|
359
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,11 +1,19 @@
|
|
|
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 adapter is independently versioned: `b3-prosaic-harness-postgres` **0.4.
|
|
8
|
-
requires `b3-prosaic-harness>=0.9,<0.10`. PostgreSQL drivers remain optional for
|
|
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
|
|
9
17
|
core Harness users. Imports and CLI names are unchanged.
|
|
10
18
|
|
|
11
19
|
## Durability profiles
|
|
@@ -38,12 +46,12 @@ persistence/restart/failover qualification before enabling production work.
|
|
|
38
46
|
|
|
39
47
|
Python 3.11+, PostgreSQL 16 or 18 on a writable primary, and libpq 17+ are
|
|
40
48
|
required. `psycopg[binary]` supplies libpq; older libpq is rejected.
|
|
41
|
-
|
|
42
|
-
wheelhouse containing only the manifest-selected b3 candidate wheels:
|
|
49
|
+
Use a fresh environment and the published compatible SDKs:
|
|
43
50
|
|
|
44
51
|
```sh
|
|
45
52
|
python3 -m venv .venv-postgres
|
|
46
|
-
.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'
|
|
47
55
|
export PATH="$PWD/.venv-postgres/bin:$PATH"
|
|
48
56
|
prosaic --version
|
|
49
57
|
prosaic-harness-postgres --help
|
|
@@ -51,8 +59,13 @@ prosaic-harness-postgres --help
|
|
|
51
59
|
|
|
52
60
|
ALWAYS migrate using a fresh environment or image; NEVER install legacy and b3
|
|
53
61
|
distributions together because they own the same import paths. See
|
|
54
|
-
[package migration](../../docs/package-migration.md).
|
|
55
|
-
|
|
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.
|
|
56
69
|
|
|
57
70
|
Harness does **not** provision PostgreSQL, create databases/users, start a
|
|
58
71
|
service, or fall back to files. Your operator supplies two DSNs through a secret
|
|
@@ -161,6 +174,10 @@ remain supported; the adapter adds no new workflow interpreter.
|
|
|
161
174
|
budget 10s, pool/connect 5s, row lock 1s, statement 5s. Deadlines cover pool,
|
|
162
175
|
network and COMMIT waits. Stalled connections are quarantined; unresolved
|
|
163
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.
|
|
164
181
|
- Default lazy pool bounds per store/process: 8 ordinary + 4 renewal connections,
|
|
165
182
|
maximum 4 active leases. Renewal has reserved capacity. Multiply capacity
|
|
166
183
|
across replicas/namespaces; do not create a pool per HTTP request. Applications
|
|
@@ -215,7 +232,7 @@ python adapters/postgres/tests/support/local_cluster.py stop --manifest "$FIXTUR
|
|
|
215
232
|
Repeat with version 18. Stop validates exact IDs/names/ownership labels before
|
|
216
233
|
removing only owned containers/volumes/network. Generated fixture networks and
|
|
217
234
|
loopback ports use synthetic trust authentication, never production defaults.
|
|
218
|
-
# Lease registration
|
|
235
|
+
# Lease registration
|
|
219
236
|
|
|
220
237
|
The adapter transfers acquisition capacity into registered
|
|
221
238
|
session capacity atomically under the existing store mutex. A registering lease
|
|
@@ -225,7 +242,7 @@ an owned PostgreSQL 16/18 race regression cover the transition.
|
|
|
225
242
|
|
|
226
243
|
## Optional conversation sessions
|
|
227
244
|
|
|
228
|
-
|
|
245
|
+
Conversation storage provides `PostgresSessionStore` to this same optional
|
|
229
246
|
distribution. It implements the public Harness `SessionStore` contract and uses
|
|
230
247
|
the independent, logged `prosaic_harness_conversations` schema, storage version 1.
|
|
231
248
|
Existing `PostgresRunStore` tables, grants and CLI `init`/`doctor` behavior remain
|
|
@@ -317,7 +334,7 @@ The required adapter suite includes both the existing workflow backend and the
|
|
|
317
334
|
conversation backend. Run the owned PostgreSQL 16 and 18 fixtures shown above
|
|
318
335
|
with `--require-postgres`. Missing infrastructure or any skipped required case
|
|
319
336
|
fails qualification. Installed Linux AMD64 and ARM64 acceptance is required
|
|
320
|
-
before
|
|
337
|
+
before treating a conversation deployment as ready for production.
|
|
321
338
|
|
|
322
339
|
## Optional context storage contract
|
|
323
340
|
|
|
@@ -337,3 +354,31 @@ cannot update schema metadata. Old workers reject the upgraded storage contract.
|
|
|
337
354
|
Keep migration-owner credentials separate from runtime credentials. Enable host
|
|
338
355
|
context policies only after Runtime, Harness and store advertise the capability.
|
|
339
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,12 +20,20 @@ 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 adapter is independently versioned: `b3-prosaic-harness-postgres` **0.4.
|
|
28
|
-
requires `b3-prosaic-harness>=0.9,<0.10`. PostgreSQL drivers remain optional for
|
|
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
|
|
29
37
|
core Harness users. Imports and CLI names are unchanged.
|
|
30
38
|
|
|
31
39
|
## Durability profiles
|
|
@@ -58,12 +66,12 @@ persistence/restart/failover qualification before enabling production work.
|
|
|
58
66
|
|
|
59
67
|
Python 3.11+, PostgreSQL 16 or 18 on a writable primary, and libpq 17+ are
|
|
60
68
|
required. `psycopg[binary]` supplies libpq; older libpq is rejected.
|
|
61
|
-
|
|
62
|
-
wheelhouse containing only the manifest-selected b3 candidate wheels:
|
|
69
|
+
Use a fresh environment and the published compatible SDKs:
|
|
63
70
|
|
|
64
71
|
```sh
|
|
65
72
|
python3 -m venv .venv-postgres
|
|
66
|
-
.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'
|
|
67
75
|
export PATH="$PWD/.venv-postgres/bin:$PATH"
|
|
68
76
|
prosaic --version
|
|
69
77
|
prosaic-harness-postgres --help
|
|
@@ -71,8 +79,13 @@ prosaic-harness-postgres --help
|
|
|
71
79
|
|
|
72
80
|
ALWAYS migrate using a fresh environment or image; NEVER install legacy and b3
|
|
73
81
|
distributions together because they own the same import paths. See
|
|
74
|
-
[package migration](../../docs/package-migration.md).
|
|
75
|
-
|
|
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.
|
|
76
89
|
|
|
77
90
|
Harness does **not** provision PostgreSQL, create databases/users, start a
|
|
78
91
|
service, or fall back to files. Your operator supplies two DSNs through a secret
|
|
@@ -181,6 +194,10 @@ remain supported; the adapter adds no new workflow interpreter.
|
|
|
181
194
|
budget 10s, pool/connect 5s, row lock 1s, statement 5s. Deadlines cover pool,
|
|
182
195
|
network and COMMIT waits. Stalled connections are quarantined; unresolved
|
|
183
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.
|
|
184
201
|
- Default lazy pool bounds per store/process: 8 ordinary + 4 renewal connections,
|
|
185
202
|
maximum 4 active leases. Renewal has reserved capacity. Multiply capacity
|
|
186
203
|
across replicas/namespaces; do not create a pool per HTTP request. Applications
|
|
@@ -235,7 +252,7 @@ python adapters/postgres/tests/support/local_cluster.py stop --manifest "$FIXTUR
|
|
|
235
252
|
Repeat with version 18. Stop validates exact IDs/names/ownership labels before
|
|
236
253
|
removing only owned containers/volumes/network. Generated fixture networks and
|
|
237
254
|
loopback ports use synthetic trust authentication, never production defaults.
|
|
238
|
-
# Lease registration
|
|
255
|
+
# Lease registration
|
|
239
256
|
|
|
240
257
|
The adapter transfers acquisition capacity into registered
|
|
241
258
|
session capacity atomically under the existing store mutex. A registering lease
|
|
@@ -245,7 +262,7 @@ an owned PostgreSQL 16/18 race regression cover the transition.
|
|
|
245
262
|
|
|
246
263
|
## Optional conversation sessions
|
|
247
264
|
|
|
248
|
-
|
|
265
|
+
Conversation storage provides `PostgresSessionStore` to this same optional
|
|
249
266
|
distribution. It implements the public Harness `SessionStore` contract and uses
|
|
250
267
|
the independent, logged `prosaic_harness_conversations` schema, storage version 1.
|
|
251
268
|
Existing `PostgresRunStore` tables, grants and CLI `init`/`doctor` behavior remain
|
|
@@ -337,7 +354,7 @@ The required adapter suite includes both the existing workflow backend and the
|
|
|
337
354
|
conversation backend. Run the owned PostgreSQL 16 and 18 fixtures shown above
|
|
338
355
|
with `--require-postgres`. Missing infrastructure or any skipped required case
|
|
339
356
|
fails qualification. Installed Linux AMD64 and ARM64 acceptance is required
|
|
340
|
-
before
|
|
357
|
+
before treating a conversation deployment as ready for production.
|
|
341
358
|
|
|
342
359
|
## Optional context storage contract
|
|
343
360
|
|
|
@@ -357,3 +374,31 @@ cannot update schema metadata. Old workers reject the upgraded storage contract.
|
|
|
357
374
|
Keep migration-owner credentials separate from runtime credentials. Enable host
|
|
358
375
|
context policies only after Runtime, Harness and store advertise the capability.
|
|
359
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,6 +21,9 @@ 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
|
|
24
28
|
tests/test_durability_profiles.py
|
|
25
29
|
tests/test_engine.py
|
|
@@ -30,6 +34,7 @@ tests/test_native_factory.py
|
|
|
30
34
|
tests/test_packaging.py
|
|
31
35
|
tests/test_recovery.py
|
|
32
36
|
tests/test_registration.py
|
|
37
|
+
tests/test_renewal_contention.py
|
|
33
38
|
tests/test_routing.py
|
|
34
39
|
tests/test_schema.py
|
|
35
40
|
tests/test_session_context.py
|
|
@@ -44,15 +44,23 @@ 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
50
|
command.add_argument('--durability-profile', choices=['postgresql', 'aurora-postgresql'],
|
|
51
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)
|
|
52
53
|
if name == 'doctor':
|
|
53
54
|
command.add_argument('--check-write', action='store_true', help='explicit disposable write test; DELETE credentials required')
|
|
54
55
|
args = parser.parse_args(argv)
|
|
55
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
|
|
56
64
|
if args.command == 'migrate-conversations':
|
|
57
65
|
from .session_store import PostgresSessionStore
|
|
58
66
|
with PostgresSessionStore.from_env(args.dsn_env, namespace='conversation-migration', durability_profile=args.durability_profile) as store:
|
|
@@ -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)
|
|
@@ -57,7 +57,7 @@ CONSTRAINTS = {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
async def ready_on_connection(conn):
|
|
60
|
+
async def ready_on_connection(conn,*,expected_versions=None):
|
|
61
61
|
exists = await (await conn.execute("SELECT pg_catalog.to_regclass('prosaic_harness.schema_version')")).fetchone()
|
|
62
62
|
if not exists or exists[0] is None:
|
|
63
63
|
raise StoreUninitialized('run init with migration credentials before accepting work')
|
|
@@ -95,7 +95,8 @@ async def ready_on_connection(conn):
|
|
|
95
95
|
if actual_constraints != CONSTRAINTS:
|
|
96
96
|
raise StoreIncompatible('adapter schema constraints are incompatible')
|
|
97
97
|
version = await (await conn.execute('SELECT schema_version, storage_contract_version FROM prosaic_harness.schema_version')).fetchall()
|
|
98
|
-
if
|
|
98
|
+
allowed=[expected_versions] if expected_versions is not None else [(1,1),(2,2)]
|
|
99
|
+
if len(version)!=1 or version[0] not in allowed:
|
|
99
100
|
raise StoreIncompatible('deploy a compatible adapter/schema; no automatic downgrade')
|
|
100
101
|
for table in COLUMNS:
|
|
101
102
|
privileges = ['SELECT']
|
|
@@ -108,13 +109,15 @@ async def ready_on_connection(conn):
|
|
|
108
109
|
('prosaic_harness.' + table, privilege))).fetchone()
|
|
109
110
|
if not allowed or not allowed[0]:
|
|
110
111
|
raise StoreIncompatible('grant required runtime table privileges before accepting work')
|
|
112
|
+
return version[0]
|
|
111
113
|
|
|
112
114
|
|
|
113
115
|
def check_ready(transport):
|
|
114
|
-
transport.call(ready_on_connection)
|
|
116
|
+
return transport.call(ready_on_connection)
|
|
115
117
|
|
|
116
118
|
|
|
117
|
-
def initialize(transport):
|
|
119
|
+
def initialize(transport,*,context_packs=False):
|
|
120
|
+
if type(context_packs) is not bool: raise ValueError('context_packs must be boolean')
|
|
118
121
|
async def migrate(conn):
|
|
119
122
|
await conn.execute("SELECT pg_catalog.set_config('lock_timeout','25000ms',true), "
|
|
120
123
|
"pg_catalog.set_config('statement_timeout','28000ms',true)")
|
|
@@ -128,8 +131,17 @@ def initialize(transport):
|
|
|
128
131
|
count = await (await conn.execute('SELECT count(*) FROM pg_catalog.pg_class WHERE relnamespace=%s',
|
|
129
132
|
(namespace[0],))).fetchone()
|
|
130
133
|
if count[0]:
|
|
131
|
-
await ready_on_connection(conn)
|
|
134
|
+
actual=await ready_on_connection(conn)
|
|
135
|
+
if context_packs and actual!=(2,2): raise StoreIncompatible('migrate context pack storage explicitly')
|
|
132
136
|
return
|
|
133
137
|
await conn.execute(DDL)
|
|
138
|
+
if context_packs:
|
|
139
|
+
await conn.execute('UPDATE prosaic_harness.schema_version SET schema_version=2,storage_contract_version=2')
|
|
134
140
|
await ready_on_connection(conn)
|
|
135
141
|
transport.call(migrate, timeout_s=30)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def migrate_context_pack_storage(transport):
|
|
145
|
+
from .pack_schema import migrate
|
|
146
|
+
return migrate(transport,schema='prosaic_harness',target=2,versions={(1,1),(2,2)},
|
|
147
|
+
lock=MIGRATION_LOCK,ready=ready_on_connection)
|
|
@@ -154,15 +154,18 @@ async def ready_on_connection(conn, *, expected_versions=None):
|
|
|
154
154
|
raise StoreIncompatible('use least-privilege conversation runtime grants')
|
|
155
155
|
versions = await (await conn.execute('SELECT schema_version,storage_contract_version '
|
|
156
156
|
'FROM prosaic_harness_conversations.schema_version')).fetchall()
|
|
157
|
-
if
|
|
157
|
+
allowed=[expected_versions] if expected_versions is not None else [(2,2),(3,3)]
|
|
158
|
+
if len(versions)!=1 or versions[0] not in allowed:
|
|
158
159
|
raise StoreIncompatible('conversation schema version is incompatible; no automatic migration')
|
|
160
|
+
return versions[0]
|
|
159
161
|
|
|
160
162
|
|
|
161
163
|
def check_ready(transport):
|
|
162
|
-
transport.call(ready_on_connection)
|
|
164
|
+
return transport.call(ready_on_connection)
|
|
163
165
|
|
|
164
166
|
|
|
165
|
-
def initialize(transport):
|
|
167
|
+
def initialize(transport,*,context_packs=False):
|
|
168
|
+
if type(context_packs) is not bool: raise ValueError('context_packs must be boolean')
|
|
166
169
|
async def migrate(conn):
|
|
167
170
|
await conn.execute("SELECT pg_catalog.set_config('lock_timeout','25000ms',true), "
|
|
168
171
|
"pg_catalog.set_config('statement_timeout','28000ms',true)")
|
|
@@ -176,11 +179,14 @@ def initialize(transport):
|
|
|
176
179
|
(namespace[0],))).fetchone()
|
|
177
180
|
if count[0]:
|
|
178
181
|
try:
|
|
179
|
-
await ready_on_connection(conn)
|
|
182
|
+
actual=await ready_on_connection(conn)
|
|
183
|
+
if context_packs and actual!=(3,3): raise StoreIncompatible('migrate context pack storage explicitly')
|
|
180
184
|
except StoreUninitialized:
|
|
181
185
|
raise StoreIncompatible('partial conversation schema requires operator repair') from None
|
|
182
186
|
return
|
|
183
187
|
await conn.execute(DDL)
|
|
188
|
+
if context_packs:
|
|
189
|
+
await conn.execute('UPDATE prosaic_harness_conversations.schema_version SET schema_version=3,storage_contract_version=3')
|
|
184
190
|
await ready_on_connection(conn)
|
|
185
191
|
transport.call(migrate, timeout_s=30)
|
|
186
192
|
|
|
@@ -198,7 +204,7 @@ def migrate_context_storage(transport):
|
|
|
198
204
|
raise StoreIncompatible('migration role must own conversation schema')
|
|
199
205
|
versions = await (await conn.execute('SELECT schema_version,storage_contract_version '
|
|
200
206
|
'FROM prosaic_harness_conversations.schema_version')).fetchall()
|
|
201
|
-
if versions
|
|
207
|
+
if versions in ([(2,2)],[(3,3)]):
|
|
202
208
|
await ready_on_connection(conn)
|
|
203
209
|
return
|
|
204
210
|
if versions != [(1, 1)]:
|
|
@@ -210,3 +216,9 @@ def migrate_context_storage(transport):
|
|
|
210
216
|
raise StoreIncompatible('conversation version metadata is incompatible')
|
|
211
217
|
await ready_on_connection(conn)
|
|
212
218
|
transport.call(migrate, timeout_s=30)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def migrate_context_pack_storage(transport):
|
|
222
|
+
from .pack_schema import migrate
|
|
223
|
+
return migrate(transport,schema=SCHEMA,target=3,versions={(1,1),(2,2),(3,3)},
|
|
224
|
+
lock=MIGRATION_LOCK,ready=ready_on_connection)
|