b3-prosaic-harness-postgres 0.4.0__tar.gz → 0.4.1__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.1}/PKG-INFO +30 -8
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/README.md +29 -7
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/pyproject.toml +1 -1
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1/src/b3_prosaic_harness_postgres.egg-info}/PKG-INFO +30 -8
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/src/b3_prosaic_harness_postgres.egg-info/SOURCES.txt +1 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/src/prosaic_harness_postgres/__init__.py +1 -1
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/src/prosaic_harness_postgres/cli.py +4 -2
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/src/prosaic_harness_postgres/session_store.py +2 -2
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/src/prosaic_harness_postgres/store.py +2 -2
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/src/prosaic_harness_postgres/transport.py +7 -2
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/support/local_cluster.py +3 -3
- b3_prosaic_harness_postgres-0.4.1/tests/test_durability_profiles.py +96 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_packaging.py +8 -7
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/LICENSE +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/MANIFEST.in +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/NOTICE +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/setup.cfg +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/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.1}/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.1}/src/b3_prosaic_harness_postgres.egg-info/requires.txt +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/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.1}/src/prosaic_harness_postgres/leases.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/src/prosaic_harness_postgres/schema.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/src/prosaic_harness_postgres/session_leases.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/src/prosaic_harness_postgres/session_schema.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/conftest.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/support/linux_wheel_smoke.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/support/model_server.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/support/session_documents.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/support/session_workers.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/support/tcp_proxy.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/support/workers.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_cli.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_durability.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_engine.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_examples.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_leases.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_local_cluster.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_native_factory.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_recovery.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_registration.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_routing.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_schema.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_session_context.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_session_fencing.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_session_recovery.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_session_schema.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_session_store.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_session_workers.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_store.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_transport.py +0 -0
- {b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_workers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: b3-prosaic-harness-postgres
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
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
|
|
@@ -24,13 +24,35 @@ Run on worker A, inspect/resume on worker B, without a shared writable run
|
|
|
24
24
|
directory. Core remains database-free; install this separate adapter only when
|
|
25
25
|
you need shared durable state. The API is synchronous; a private I/O thread
|
|
26
26
|
bounds network waits. Model execution holds no database connection/transaction.
|
|
27
|
-
The
|
|
28
|
-
`b3-prosaic-harness>=0.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
The adapter is independently versioned: `b3-prosaic-harness-postgres` **0.4.1**
|
|
28
|
+
requires `b3-prosaic-harness>=0.9,<0.10`. PostgreSQL drivers remain optional for
|
|
29
|
+
core Harness users. Imports and CLI names are unchanged.
|
|
30
|
+
|
|
31
|
+
## Durability profiles
|
|
32
|
+
|
|
33
|
+
The default `durability_profile="postgresql"` requires `full_page_writes=on`.
|
|
34
|
+
An operator who has independently verified an Amazon Aurora PostgreSQL cluster
|
|
35
|
+
may explicitly select `durability_profile="aurora-postgresql"` on both
|
|
36
|
+
`PostgresRunStore` and `PostgresSessionStore` (including `from_env`). This accepts
|
|
37
|
+
`full_page_writes=off` under Aurora's log-based storage contract. It does not
|
|
38
|
+
weaken fsync, synchronous commit, writable-primary, logged-table, lease or
|
|
39
|
+
unknown-commit checks. The guard runs for every operation and connection reuse.
|
|
40
|
+
Invalid profiles fail before connecting. This profile is an operator assertion,
|
|
41
|
+
not engine autodetection or proof that arbitrary storage is safe. NEVER select
|
|
42
|
+
it for ordinary PostgreSQL just to suppress a readiness failure.
|
|
43
|
+
|
|
44
|
+
For every CLI command, pass `--durability-profile aurora-postgresql` explicitly.
|
|
45
|
+
Migration and runtime must select the same profile. Verify the actual engine and
|
|
46
|
+
version with AWS RDS metadata/DBA evidence; AWS also documents `aurora_version()`.
|
|
47
|
+
Capture a failed SQL probe's actual error and inspect its schema/search path;
|
|
48
|
+
NEVER convert an unavailable probe into permission to bypass durability checks.
|
|
49
|
+
No AWS credentials or model calls are needed by the adapter.
|
|
50
|
+
|
|
51
|
+
AWS describes the storage contract in
|
|
52
|
+
[its architecture guide](https://aws.amazon.com/blogs/database/is-amazon-rds-for-postgresql-or-amazon-aurora-postgresql-a-better-choice-for-me/).
|
|
53
|
+
Native PostgreSQL tests qualify the policy and all existing recovery behavior;
|
|
54
|
+
they do not emulate Aurora storage. An actual Aurora deployment needs synthetic
|
|
55
|
+
persistence/restart/failover qualification before enabling production work.
|
|
34
56
|
|
|
35
57
|
## 1. Install and supply an existing database
|
|
36
58
|
|
|
@@ -4,13 +4,35 @@ Run on worker A, inspect/resume on worker B, without a shared writable run
|
|
|
4
4
|
directory. Core remains database-free; install this separate adapter only when
|
|
5
5
|
you need shared durable state. The API is synchronous; a private I/O thread
|
|
6
6
|
bounds network waits. Model execution holds no database connection/transaction.
|
|
7
|
-
The
|
|
8
|
-
`b3-prosaic-harness>=0.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
The adapter is independently versioned: `b3-prosaic-harness-postgres` **0.4.1**
|
|
8
|
+
requires `b3-prosaic-harness>=0.9,<0.10`. PostgreSQL drivers remain optional for
|
|
9
|
+
core Harness users. Imports and CLI names are unchanged.
|
|
10
|
+
|
|
11
|
+
## Durability profiles
|
|
12
|
+
|
|
13
|
+
The default `durability_profile="postgresql"` requires `full_page_writes=on`.
|
|
14
|
+
An operator who has independently verified an Amazon Aurora PostgreSQL cluster
|
|
15
|
+
may explicitly select `durability_profile="aurora-postgresql"` on both
|
|
16
|
+
`PostgresRunStore` and `PostgresSessionStore` (including `from_env`). This accepts
|
|
17
|
+
`full_page_writes=off` under Aurora's log-based storage contract. It does not
|
|
18
|
+
weaken fsync, synchronous commit, writable-primary, logged-table, lease or
|
|
19
|
+
unknown-commit checks. The guard runs for every operation and connection reuse.
|
|
20
|
+
Invalid profiles fail before connecting. This profile is an operator assertion,
|
|
21
|
+
not engine autodetection or proof that arbitrary storage is safe. NEVER select
|
|
22
|
+
it for ordinary PostgreSQL just to suppress a readiness failure.
|
|
23
|
+
|
|
24
|
+
For every CLI command, pass `--durability-profile aurora-postgresql` explicitly.
|
|
25
|
+
Migration and runtime must select the same profile. Verify the actual engine and
|
|
26
|
+
version with AWS RDS metadata/DBA evidence; AWS also documents `aurora_version()`.
|
|
27
|
+
Capture a failed SQL probe's actual error and inspect its schema/search path;
|
|
28
|
+
NEVER convert an unavailable probe into permission to bypass durability checks.
|
|
29
|
+
No AWS credentials or model calls are needed by the adapter.
|
|
30
|
+
|
|
31
|
+
AWS describes the storage contract in
|
|
32
|
+
[its architecture guide](https://aws.amazon.com/blogs/database/is-amazon-rds-for-postgresql-or-amazon-aurora-postgresql-a-better-choice-for-me/).
|
|
33
|
+
Native PostgreSQL tests qualify the policy and all existing recovery behavior;
|
|
34
|
+
they do not emulate Aurora storage. An actual Aurora deployment needs synthetic
|
|
35
|
+
persistence/restart/failover qualification before enabling production work.
|
|
14
36
|
|
|
15
37
|
## 1. Install and supply an existing database
|
|
16
38
|
|
|
@@ -4,7 +4,7 @@ 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.1"
|
|
8
8
|
description = "Explicit PostgreSQL run and conversation storage for Prosaic Harness"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
readme = "README.md"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: b3-prosaic-harness-postgres
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
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
|
|
@@ -24,13 +24,35 @@ Run on worker A, inspect/resume on worker B, without a shared writable run
|
|
|
24
24
|
directory. Core remains database-free; install this separate adapter only when
|
|
25
25
|
you need shared durable state. The API is synchronous; a private I/O thread
|
|
26
26
|
bounds network waits. Model execution holds no database connection/transaction.
|
|
27
|
-
The
|
|
28
|
-
`b3-prosaic-harness>=0.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
The adapter is independently versioned: `b3-prosaic-harness-postgres` **0.4.1**
|
|
28
|
+
requires `b3-prosaic-harness>=0.9,<0.10`. PostgreSQL drivers remain optional for
|
|
29
|
+
core Harness users. Imports and CLI names are unchanged.
|
|
30
|
+
|
|
31
|
+
## Durability profiles
|
|
32
|
+
|
|
33
|
+
The default `durability_profile="postgresql"` requires `full_page_writes=on`.
|
|
34
|
+
An operator who has independently verified an Amazon Aurora PostgreSQL cluster
|
|
35
|
+
may explicitly select `durability_profile="aurora-postgresql"` on both
|
|
36
|
+
`PostgresRunStore` and `PostgresSessionStore` (including `from_env`). This accepts
|
|
37
|
+
`full_page_writes=off` under Aurora's log-based storage contract. It does not
|
|
38
|
+
weaken fsync, synchronous commit, writable-primary, logged-table, lease or
|
|
39
|
+
unknown-commit checks. The guard runs for every operation and connection reuse.
|
|
40
|
+
Invalid profiles fail before connecting. This profile is an operator assertion,
|
|
41
|
+
not engine autodetection or proof that arbitrary storage is safe. NEVER select
|
|
42
|
+
it for ordinary PostgreSQL just to suppress a readiness failure.
|
|
43
|
+
|
|
44
|
+
For every CLI command, pass `--durability-profile aurora-postgresql` explicitly.
|
|
45
|
+
Migration and runtime must select the same profile. Verify the actual engine and
|
|
46
|
+
version with AWS RDS metadata/DBA evidence; AWS also documents `aurora_version()`.
|
|
47
|
+
Capture a failed SQL probe's actual error and inspect its schema/search path;
|
|
48
|
+
NEVER convert an unavailable probe into permission to bypass durability checks.
|
|
49
|
+
No AWS credentials or model calls are needed by the adapter.
|
|
50
|
+
|
|
51
|
+
AWS describes the storage contract in
|
|
52
|
+
[its architecture guide](https://aws.amazon.com/blogs/database/is-amazon-rds-for-postgresql-or-amazon-aurora-postgresql-a-better-choice-for-me/).
|
|
53
|
+
Native PostgreSQL tests qualify the policy and all existing recovery behavior;
|
|
54
|
+
they do not emulate Aurora storage. An actual Aurora deployment needs synthetic
|
|
55
|
+
persistence/restart/failover qualification before enabling production work.
|
|
34
56
|
|
|
35
57
|
## 1. Install and supply an existing database
|
|
36
58
|
|
|
@@ -47,18 +47,20 @@ def main(argv=None):
|
|
|
47
47
|
for name in ('init', 'doctor', 'migrate-conversations'):
|
|
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')
|
|
50
52
|
if name == 'doctor':
|
|
51
53
|
command.add_argument('--check-write', action='store_true', help='explicit disposable write test; DELETE credentials required')
|
|
52
54
|
args = parser.parse_args(argv)
|
|
53
55
|
try:
|
|
54
56
|
if args.command == 'migrate-conversations':
|
|
55
57
|
from .session_store import PostgresSessionStore
|
|
56
|
-
with PostgresSessionStore.from_env(args.dsn_env, namespace='conversation-migration') as store:
|
|
58
|
+
with PostgresSessionStore.from_env(args.dsn_env, namespace='conversation-migration', durability_profile=args.durability_profile) as store:
|
|
57
59
|
store.migrate_context_storage()
|
|
58
60
|
print(json.dumps({'migrated': True, 'conversation_storage_contract': 2}))
|
|
59
61
|
return 0
|
|
60
62
|
namespace = 'prosaic-diagnostic-' + uuid.uuid4().hex
|
|
61
|
-
with PostgresRunStore.from_env(args.dsn_env, namespace=namespace) as store:
|
|
63
|
+
with PostgresRunStore.from_env(args.dsn_env, namespace=namespace, durability_profile=args.durability_profile) as store:
|
|
62
64
|
if args.command == 'init':
|
|
63
65
|
store.initialize()
|
|
64
66
|
result = {'initialized': True, 'schema_version': 1}
|
|
@@ -33,7 +33,7 @@ class PostgresSessionStore:
|
|
|
33
33
|
|
|
34
34
|
def __init__(self, dsn, *, namespace, lease_s=60, renew_s=15,
|
|
35
35
|
operation_timeout_s=10, pool_timeout_s=5, connect_timeout_s=5,
|
|
36
|
-
lock_timeout_s=1, statement_timeout_s=5, pool_size=8, max_active_leases=4):
|
|
36
|
+
lock_timeout_s=1, statement_timeout_s=5, pool_size=8, max_active_leases=4, durability_profile="postgresql"):
|
|
37
37
|
self._namespace = validate_namespace(namespace)
|
|
38
38
|
positive(lease_s, 'lease_s')
|
|
39
39
|
positive(renew_s, 'renew_s')
|
|
@@ -49,7 +49,7 @@ class PostgresSessionStore:
|
|
|
49
49
|
self._transport = PostgresTransport(dsn, operation_timeout_s=operation_timeout_s,
|
|
50
50
|
pool_timeout_s=pool_timeout_s, connect_timeout_s=connect_timeout_s,
|
|
51
51
|
lock_timeout_s=lock_timeout_s, statement_timeout_s=statement_timeout_s,
|
|
52
|
-
pool_size=pool_size, max_active_leases=max_active_leases)
|
|
52
|
+
pool_size=pool_size, max_active_leases=max_active_leases, durability_profile=durability_profile)
|
|
53
53
|
|
|
54
54
|
@property
|
|
55
55
|
def namespace(self):
|
|
@@ -29,7 +29,7 @@ class PostgresRunStore:
|
|
|
29
29
|
|
|
30
30
|
def __init__(self, dsn, *, namespace, lease_s=60, renew_s=15,
|
|
31
31
|
operation_timeout_s=10, pool_timeout_s=5, connect_timeout_s=5,
|
|
32
|
-
lock_timeout_s=1, statement_timeout_s=5, pool_size=8, max_active_leases=4):
|
|
32
|
+
lock_timeout_s=1, statement_timeout_s=5, pool_size=8, max_active_leases=4, durability_profile="postgresql"):
|
|
33
33
|
self.namespace = validate_namespace(namespace)
|
|
34
34
|
positive(lease_s, 'lease_s')
|
|
35
35
|
positive(renew_s, 'renew_s')
|
|
@@ -46,7 +46,7 @@ class PostgresRunStore:
|
|
|
46
46
|
self._transport = PostgresTransport(dsn, operation_timeout_s=operation_timeout_s,
|
|
47
47
|
pool_timeout_s=pool_timeout_s, connect_timeout_s=connect_timeout_s,
|
|
48
48
|
lock_timeout_s=lock_timeout_s, statement_timeout_s=statement_timeout_s,
|
|
49
|
-
pool_size=pool_size, max_active_leases=max_active_leases)
|
|
49
|
+
pool_size=pool_size, max_active_leases=max_active_leases, durability_profile=durability_profile)
|
|
50
50
|
|
|
51
51
|
def initialize(self):
|
|
52
52
|
schema.initialize(self._transport)
|
|
@@ -47,7 +47,10 @@ class _Operation:
|
|
|
47
47
|
class PostgresTransport:
|
|
48
48
|
def __init__(self, dsn, *, operation_timeout_s=10, pool_timeout_s=5,
|
|
49
49
|
connect_timeout_s=5, lock_timeout_s=1, statement_timeout_s=5,
|
|
50
|
-
pool_size=8, max_active_leases=4):
|
|
50
|
+
pool_size=8, max_active_leases=4, durability_profile="postgresql"):
|
|
51
|
+
if type(durability_profile) is not str or durability_profile not in {'postgresql', 'aurora-postgresql'}:
|
|
52
|
+
raise ValueError('durability_profile must be postgresql or aurora-postgresql')
|
|
53
|
+
self.durability_profile = durability_profile
|
|
51
54
|
for name, value in locals().copy().items():
|
|
52
55
|
if name.endswith('_s'):
|
|
53
56
|
positive(value, name)
|
|
@@ -138,7 +141,9 @@ class PostgresTransport:
|
|
|
138
141
|
pg_catalog.current_setting('transaction_read_only'),
|
|
139
142
|
pg_catalog.current_setting('fsync'), pg_catalog.current_setting('full_page_writes'),
|
|
140
143
|
pg_catalog.current_setting('synchronous_commit')""")).fetchone()
|
|
141
|
-
|
|
144
|
+
full_page_values = {'on', 'off'} if self.durability_profile == 'aurora-postgresql' else {'on'}
|
|
145
|
+
if (not row or row[0] or row[1:3] != ('off', 'on')
|
|
146
|
+
or row[3] not in full_page_values or row[4] not in {'on', 'remote_apply'}):
|
|
142
147
|
raise StoreIncompatible('require writable primary, logged durability and safe WAL settings')
|
|
143
148
|
|
|
144
149
|
async def _sql(self, operation, callback, renewal, budget):
|
|
@@ -40,7 +40,7 @@ def candidate_wheels(root):
|
|
|
40
40
|
spec.loader.exec_module(release)
|
|
41
41
|
release.verify_upstream(Path(receipt_directory).resolve(strict=True), wheelhouse)
|
|
42
42
|
return [wheelhouse / 'b3_prosaic-0.4.1-py3-none-any.whl',
|
|
43
|
-
wheelhouse / 'b3_prosaic_runtime-0.9.
|
|
43
|
+
wheelhouse / 'b3_prosaic_runtime-0.9.7-py3-none-any.whl']
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
class LocalCluster:
|
|
@@ -177,12 +177,12 @@ class LocalCluster:
|
|
|
177
177
|
set -eu
|
|
178
178
|
apt-get update -qq
|
|
179
179
|
python -m venv /tmp/core
|
|
180
|
-
/tmp/core/bin/python -m pip install /core-wheels/b3_prosaic_harness-0.9.
|
|
180
|
+
/tmp/core/bin/python -m pip install /core-wheels/b3_prosaic_harness-0.9.4-py3-none-any.whl >/dev/null
|
|
181
181
|
/tmp/core/bin/python -I -c 'import importlib.util,prosaic_harness; assert importlib.util.find_spec("psycopg") is None; assert importlib.util.find_spec("prosaic_harness_postgres") is None'
|
|
182
182
|
/tmp/core/bin/python -I /fixture/workflow_factory_smoke.py
|
|
183
183
|
/tmp/core/bin/python -I /fixture/conversation_smoke.py
|
|
184
184
|
python -m venv /tmp/both
|
|
185
|
-
/tmp/both/bin/python -m pip install /core-wheels/b3_prosaic_harness-0.9.
|
|
185
|
+
/tmp/both/bin/python -m pip install /core-wheels/b3_prosaic_harness-0.9.4-py3-none-any.whl /adapter-wheels/b3_prosaic_harness_postgres-0.4.1-py3-none-any.whl >/dev/null
|
|
186
186
|
/tmp/both/bin/python -I /fixture/linux_wheel_smoke.py
|
|
187
187
|
'''
|
|
188
188
|
if dependencies:
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""An explicit storage contract changes only the full-page-write guard."""
|
|
2
|
+
import asyncio
|
|
3
|
+
from unittest.mock import AsyncMock
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from prosaic_harness import StoreIncompatible
|
|
7
|
+
from prosaic_harness_postgres.transport import PostgresTransport
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@pytest.mark.parametrize('profile', ['postgresql', 'aurora-postgresql'])
|
|
11
|
+
@pytest.mark.parametrize('row,accepted', [
|
|
12
|
+
((False, 'off', 'on', 'on', 'on'), True),
|
|
13
|
+
((False, 'off', 'on', 'off', 'on'), 'aurora'),
|
|
14
|
+
((False, 'off', 'off', 'off', 'on'), False),
|
|
15
|
+
((False, 'off', 'on', 'off', 'off'), False),
|
|
16
|
+
((True, 'off', 'on', 'off', 'on'), False),
|
|
17
|
+
((False, 'on', 'on', 'off', 'on'), False),
|
|
18
|
+
((False, 'off', 'on', 'on', 'remote_apply'), True),
|
|
19
|
+
((False, 'off', 'on', 'on', 'local'), False),
|
|
20
|
+
((False, 'off', 'on', 'invalid', 'on'), False),
|
|
21
|
+
(None, False),
|
|
22
|
+
])
|
|
23
|
+
def test_profile_changes_only_full_page_requirement(profile, row, accepted):
|
|
24
|
+
transport = object.__new__(PostgresTransport)
|
|
25
|
+
transport.durability_profile = profile
|
|
26
|
+
cursor = AsyncMock()
|
|
27
|
+
cursor.fetchone.return_value = row
|
|
28
|
+
connection = AsyncMock()
|
|
29
|
+
connection.execute.return_value = cursor
|
|
30
|
+
allowed = accepted is True or (accepted == 'aurora' and profile == 'aurora-postgresql')
|
|
31
|
+
if allowed:
|
|
32
|
+
asyncio.run(transport._guard(connection))
|
|
33
|
+
else:
|
|
34
|
+
with pytest.raises(StoreIncompatible):
|
|
35
|
+
asyncio.run(transport._guard(connection))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@pytest.mark.parametrize('profile', ['', 'storage', 'Aurora', None, True])
|
|
39
|
+
def test_unknown_profile_rejected_before_connection(profile):
|
|
40
|
+
with pytest.raises(ValueError, match='durability_profile'):
|
|
41
|
+
PostgresTransport('unused', durability_profile=profile)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@pytest.mark.parametrize('module_name,class_name', [('store', 'PostgresRunStore'), ('session_store', 'PostgresSessionStore')])
|
|
45
|
+
def test_public_store_and_from_env_forward_profile(monkeypatch, module_name, class_name):
|
|
46
|
+
import importlib
|
|
47
|
+
module = importlib.import_module('prosaic_harness_postgres.' + module_name)
|
|
48
|
+
captured = []
|
|
49
|
+
monkeypatch.setattr(module, 'PostgresTransport', lambda dsn, **kw: captured.append(kw))
|
|
50
|
+
monkeypatch.setenv('SYNTHETIC_DSN', 'synthetic')
|
|
51
|
+
cls = getattr(module, class_name)
|
|
52
|
+
cls('synthetic', namespace='fixture')
|
|
53
|
+
cls.from_env('SYNTHETIC_DSN', namespace='fixture', durability_profile='aurora-postgresql')
|
|
54
|
+
assert [kw['durability_profile'] for kw in captured] == ['postgresql', 'aurora-postgresql']
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.mark.parametrize('command', ['init', 'doctor', 'migrate-conversations'])
|
|
58
|
+
def test_cli_forwards_explicit_profile(monkeypatch, command):
|
|
59
|
+
from prosaic_harness_postgres import cli, session_store
|
|
60
|
+
calls = []
|
|
61
|
+
class Store:
|
|
62
|
+
def __enter__(self): return self
|
|
63
|
+
def __exit__(self, *args): pass
|
|
64
|
+
def initialize(self): pass
|
|
65
|
+
def check_ready(self): pass
|
|
66
|
+
def migrate_context_storage(self): pass
|
|
67
|
+
def create(name, **kwargs):
|
|
68
|
+
calls.append(kwargs['durability_profile'])
|
|
69
|
+
return Store()
|
|
70
|
+
monkeypatch.setattr(cli.PostgresRunStore, 'from_env', create)
|
|
71
|
+
monkeypatch.setattr(session_store.PostgresSessionStore, 'from_env', create)
|
|
72
|
+
assert cli.main([command, '--dsn-env', 'SYNTHETIC_DSN', '--durability-profile', 'aurora-postgresql']) == 0
|
|
73
|
+
assert calls == ['aurora-postgresql']
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@pytest.mark.parametrize('class_name', ['PostgresRunStore', 'PostgresSessionStore'])
|
|
77
|
+
def test_explicit_profile_retains_real_connection_guards(db_admin_dsn, class_name):
|
|
78
|
+
import prosaic_harness_postgres
|
|
79
|
+
cls = getattr(prosaic_harness_postgres, class_name)
|
|
80
|
+
with cls(db_admin_dsn, namespace='fixture', durability_profile='aurora-postgresql', pool_size=1) as store:
|
|
81
|
+
store.initialize()
|
|
82
|
+
store.check_ready()
|
|
83
|
+
store._transport.call(lambda conn: conn.execute('SET synchronous_commit=off'))
|
|
84
|
+
with pytest.raises(StoreIncompatible):
|
|
85
|
+
store.check_ready()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_public_version_matches_distribution():
|
|
89
|
+
import ast
|
|
90
|
+
from pathlib import Path
|
|
91
|
+
import tomllib
|
|
92
|
+
root = Path(__file__).resolve().parents[1]
|
|
93
|
+
version = tomllib.loads((root/'pyproject.toml').read_text())['project']['version']
|
|
94
|
+
module = ast.parse((root/'src/prosaic_harness_postgres/__init__.py').read_text())
|
|
95
|
+
assert next(ast.literal_eval(n.value) for n in module.body if isinstance(n, ast.Assign)
|
|
96
|
+
and any(isinstance(t, ast.Name) and t.id=='__version__' for t in n.targets)) == version
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_packaging.py
RENAMED
|
@@ -13,8 +13,8 @@ import pytest
|
|
|
13
13
|
import yaml
|
|
14
14
|
|
|
15
15
|
ROOT = Path(__file__).resolve().parents[3]
|
|
16
|
-
CORE = ROOT / 'dist/b3_prosaic_harness-0.9.
|
|
17
|
-
ADAPTER = ROOT / 'adapters/postgres/dist/b3_prosaic_harness_postgres-0.4.
|
|
16
|
+
CORE = ROOT / 'dist/b3_prosaic_harness-0.9.4-py3-none-any.whl'
|
|
17
|
+
ADAPTER = ROOT / 'adapters/postgres/dist/b3_prosaic_harness_postgres-0.4.1-py3-none-any.whl'
|
|
18
18
|
|
|
19
19
|
def test_owned_fixture_uses_free_explicit_subnet_when_default_pool_is_exhausted():
|
|
20
20
|
from support.local_cluster import owned_subnet
|
|
@@ -73,12 +73,12 @@ def metadata(path):
|
|
|
73
73
|
def test_wheel_contents_and_dependency_boundaries():
|
|
74
74
|
core, names = metadata(CORE)
|
|
75
75
|
assert core['Name'] == 'b3-prosaic-harness'
|
|
76
|
-
assert core['Version'] == '0.9.
|
|
76
|
+
assert core['Version'] == '0.9.4'
|
|
77
77
|
assert not any(name.startswith('prosaic_harness_postgres/') for name in names)
|
|
78
78
|
assert not any('psycopg' in value.lower() for value in core.get_all('Requires-Dist'))
|
|
79
79
|
adapter, names = metadata(ADAPTER)
|
|
80
80
|
assert adapter['Name'] == 'b3-prosaic-harness-postgres'
|
|
81
|
-
assert adapter['Version'] == '0.4.
|
|
81
|
+
assert adapter['Version'] == '0.4.1'
|
|
82
82
|
assert any(value.startswith('b3-prosaic-harness<0.10,>=0.9') for value in adapter.get_all('Requires-Dist'))
|
|
83
83
|
assert 'prosaic_harness_postgres/cli.py' in names
|
|
84
84
|
assert any(value.startswith('psycopg[binary]<4,>=3.2.3')
|
|
@@ -134,7 +134,8 @@ def test_installed_memory_file_conversations_and_saved_receipt_recovery(wheel_en
|
|
|
134
134
|
report = json.loads(result.stdout)
|
|
135
135
|
assert set(report['stores']) == {'memory', 'file'}
|
|
136
136
|
for evidence in report['stores'].values():
|
|
137
|
-
assert evidence['providerRequests'] ==
|
|
137
|
+
assert evidence['providerRequests'] == 6
|
|
138
|
+
assert evidence['sameMessageFailedRetry'] is True
|
|
138
139
|
assert evidence['savedReceiptAdoptedWithoutDispatch'] is True
|
|
139
140
|
assert evidence['failedCorrectionRetained'] is True
|
|
140
141
|
|
|
@@ -184,7 +185,7 @@ def curated_candidates(release_tool, tmp_path):
|
|
|
184
185
|
candidates = []
|
|
185
186
|
for repo, expected in (
|
|
186
187
|
('B3Cognition/prosaic', {'b3-prosaic': '0.4.1'}),
|
|
187
|
-
('B3Cognition/prosaic-runtime', {'b3-prosaic-runtime': '0.9.
|
|
188
|
+
('B3Cognition/prosaic-runtime', {'b3-prosaic-runtime': '0.9.7',
|
|
188
189
|
'b3-prosaic-runtime-postgres': '0.3.0'})):
|
|
189
190
|
artifacts = []
|
|
190
191
|
for name, version in expected.items():
|
|
@@ -252,4 +253,4 @@ def test_container_mounts_verified_dependency_bytes_read_only(
|
|
|
252
253
|
create = calls[0]
|
|
253
254
|
assert str(wheelhouse) + ':/candidate-wheels:ro' in create
|
|
254
255
|
assert 'PIP_FIND_LINKS=/candidate-wheels' in create[-1]
|
|
255
|
-
assert '/candidate-wheels/b3_prosaic_runtime-0.9.
|
|
256
|
+
assert '/candidate-wheels/b3_prosaic_runtime-0.9.7-py3-none-any.whl' in create[-1]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/support/tcp_proxy.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/support/workers.py
RENAMED
|
File without changes
|
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_durability.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_engine.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_examples.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_leases.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_local_cluster.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_native_factory.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_recovery.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_registration.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_routing.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_schema.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_session_schema.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_session_store.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_transport.py
RENAMED
|
File without changes
|
{b3_prosaic_harness_postgres-0.4.0 → b3_prosaic_harness_postgres-0.4.1}/tests/test_workers.py
RENAMED
|
File without changes
|