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.
Files changed (57) hide show
  1. {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
  2. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/README.md +82 -15
  3. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/pyproject.toml +2 -2
  4. {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
  5. {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
  6. {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
  7. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/__init__.py +1 -1
  8. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/cli.py +13 -3
  9. b3_prosaic_harness_postgres-0.4.2/src/prosaic_harness_postgres/pack_schema.py +31 -0
  10. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/schema.py +17 -5
  11. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/session_schema.py +17 -5
  12. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/session_store.py +18 -6
  13. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/store.py +19 -4
  14. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/transport.py +14 -3
  15. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/local_cluster.py +40 -9
  16. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/session_documents.py +46 -0
  17. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/session_workers.py +2 -1
  18. b3_prosaic_harness_postgres-0.4.2/tests/test_context_pack_migrations.py +96 -0
  19. b3_prosaic_harness_postgres-0.4.2/tests/test_context_pack_platform.py +21 -0
  20. b3_prosaic_harness_postgres-0.4.2/tests/test_context_pack_recovery.py +112 -0
  21. b3_prosaic_harness_postgres-0.4.2/tests/test_durability_profiles.py +96 -0
  22. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_packaging.py +27 -9
  23. b3_prosaic_harness_postgres-0.4.2/tests/test_renewal_contention.py +39 -0
  24. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/LICENSE +0 -0
  25. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/MANIFEST.in +0 -0
  26. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/NOTICE +0 -0
  27. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/setup.cfg +0 -0
  28. {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
  29. {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
  30. {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
  31. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/leases.py +0 -0
  32. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/src/prosaic_harness_postgres/session_leases.py +0 -0
  33. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/conftest.py +0 -0
  34. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/linux_wheel_smoke.py +0 -0
  35. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/model_server.py +0 -0
  36. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/tcp_proxy.py +0 -0
  37. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/support/workers.py +0 -0
  38. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_cli.py +0 -0
  39. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_durability.py +0 -0
  40. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_engine.py +0 -0
  41. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_examples.py +0 -0
  42. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_leases.py +0 -0
  43. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_local_cluster.py +0 -0
  44. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_native_factory.py +0 -0
  45. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_recovery.py +0 -0
  46. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_registration.py +0 -0
  47. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_routing.py +0 -0
  48. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_schema.py +0 -0
  49. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_context.py +0 -0
  50. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_fencing.py +0 -0
  51. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_recovery.py +0 -0
  52. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_schema.py +0 -0
  53. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_store.py +0 -0
  54. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_session_workers.py +0 -0
  55. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_store.py +0 -0
  56. {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.2}/tests/test_transport.py +0 -0
  57. {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.0
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 conversation candidate is `b3-prosaic-harness-postgres` **0.3.0**, selecting
28
- `b3-prosaic-harness>=0.8,<0.9`. The adapter is maintained in this repository but
29
- installed and versioned separately, keeping PostgreSQL drivers optional for
30
- Harness users. Imports and CLI names remain unchanged. Final qualification and
31
- publication of this conversation release train are pending. The historical
32
- [Harness v0.6.1 release](https://github.com/B3Cognition/prosaic-harness/releases/tag/v0.6.1)
33
- retains its original 0.6.1/0.1.1 package names and receipts.
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
- From the exact candidate Harness checkout, use a new environment and a curated
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 --find-links /absolute/path/to/curated-wheelhouse . ./adapters/postgres
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). The Runtime 0.9 candidate
53
- must be available before this installation can resolve.
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 candidate
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
- The conversation candidate adds `PostgresSessionStore` to this same optional
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 claiming the conversation candidate is ready for production.
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 conversation candidate is `b3-prosaic-harness-postgres` **0.3.0**, selecting
8
- `b3-prosaic-harness>=0.8,<0.9`. The adapter is maintained in this repository but
9
- installed and versioned separately, keeping PostgreSQL drivers optional for
10
- Harness users. Imports and CLI names remain unchanged. Final qualification and
11
- publication of this conversation release train are pending. The historical
12
- [Harness v0.6.1 release](https://github.com/B3Cognition/prosaic-harness/releases/tag/v0.6.1)
13
- retains its original 0.6.1/0.1.1 package names and receipts.
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
- From the exact candidate Harness checkout, use a new environment and a curated
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 --find-links /absolute/path/to/curated-wheelhouse . ./adapters/postgres
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). The Runtime 0.9 candidate
33
- must be available before this installation can resolve.
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 candidate
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
- The conversation candidate adds `PostgresSessionStore` to this same optional
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 claiming the conversation candidate is ready for production.
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.0"
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.0
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 conversation candidate is `b3-prosaic-harness-postgres` **0.3.0**, selecting
28
- `b3-prosaic-harness>=0.8,<0.9`. The adapter is maintained in this repository but
29
- installed and versioned separately, keeping PostgreSQL drivers optional for
30
- Harness users. Imports and CLI names remain unchanged. Final qualification and
31
- publication of this conversation release train are pending. The historical
32
- [Harness v0.6.1 release](https://github.com/B3Cognition/prosaic-harness/releases/tag/v0.6.1)
33
- retains its original 0.6.1/0.1.1 package names and receipts.
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
- From the exact candidate Harness checkout, use a new environment and a curated
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 --find-links /absolute/path/to/curated-wheelhouse . ./adapters/postgres
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). The Runtime 0.9 candidate
53
- must be available before this installation can resolve.
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 candidate
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
- The conversation candidate adds `PostgresSessionStore` to this same optional
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 claiming the conversation candidate is ready for production.
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
@@ -1,4 +1,4 @@
1
- b3-prosaic-harness<0.10,>=0.9
1
+ b3-prosaic-harness<0.10,>=0.9.13
2
2
  psycopg[binary]<4,>=3.2.3
3
3
  psycopg-pool<4,>=3.2
4
4
 
@@ -1,5 +1,5 @@
1
1
  """Separate PostgreSQL adapter for Prosaic Harness."""
2
- __version__ = '0.4.0'
2
+ __version__ = '0.4.2'
3
3
 
4
4
  from .store import PostgresRunStore
5
5
  from .session_store import PostgresSessionStore
@@ -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)