amfs-adapter-postgres 0.2.42__tar.gz → 0.2.43__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 (30) hide show
  1. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/PKG-INFO +2 -2
  2. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/pyproject.toml +2 -2
  3. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/adapter.py +29 -4
  4. amfs_adapter_postgres-0.2.43/src/amfs_postgres/migrations/014_outcome_covariates.sql +20 -0
  5. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/.gitignore +0 -0
  6. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/__init__.py +0 -0
  7. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/_fts.py +0 -0
  8. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/async_adapter.py +0 -0
  9. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/evidence_sql.py +0 -0
  10. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/knn.py +0 -0
  11. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/001_initial.sql +0 -0
  12. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/002_artifact_refs.sql +0 -0
  13. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/002_search_indexes.sql +0 -0
  14. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/003_knowledge_graph.sql +0 -0
  15. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/004_agent_groups.sql +0 -0
  16. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/005_configurable_embedding_dim.sql +0 -0
  17. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/006_is_artifact.sql +0 -0
  18. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/006_outcome_confidence_semantics.sql +0 -0
  19. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/007_outcome_propagation_row_copy.sql +0 -0
  20. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/008_outcome_evidence.sql +0 -0
  21. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/009_action_priors.sql +0 -0
  22. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/010_local_evidence.sql +0 -0
  23. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/011_outcome_task_text.sql +0 -0
  24. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/012_evidence_from_model.sql +0 -0
  25. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/migrations/013_outcome_verified_by_backfill.sql +0 -0
  26. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/retention.py +0 -0
  27. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/schema.sql +0 -0
  28. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/tenant_context.py +0 -0
  29. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/tenant_gucs.py +0 -0
  30. {amfs_adapter_postgres-0.2.42 → amfs_adapter_postgres-0.2.43}/src/amfs_postgres/trace_partitions.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: amfs-adapter-postgres
3
- Version: 0.2.42
3
+ Version: 0.2.43
4
4
  Summary: AMFS Postgres adapter with back-propagation triggers
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.11
7
- Requires-Dist: amfs-core>=0.3.53
7
+ Requires-Dist: amfs-core>=0.3.54
8
8
  Requires-Dist: psycopg-pool>=3.1
9
9
  Requires-Dist: psycopg[binary]<4,>=3.1
@@ -1,13 +1,13 @@
1
1
  [project]
2
2
  name = "amfs-adapter-postgres"
3
- version = "0.2.42"
3
+ version = "0.2.43"
4
4
  description = "AMFS Postgres adapter with back-propagation triggers"
5
5
  requires-python = ">=3.11"
6
6
  license = "Apache-2.0"
7
7
  dependencies = [
8
8
  # 0.3.14 adds the capture fields this adapter now persists and selects back,
9
9
  # tool_calls among them.
10
- "amfs-core>=0.3.53",
10
+ "amfs-core>=0.3.54",
11
11
  "psycopg[binary]>=3.1,<4",
12
12
  "psycopg-pool>=3.1",
13
13
  ]
@@ -34,7 +34,7 @@ from amfs_core.exclusions import (
34
34
  AGENT_ID_NOT_EXCLUDED_SQL,
35
35
  ENTITY_PATH_NOT_EXCLUDED_SQL,
36
36
  )
37
- from amfs_core.actions import entity_paths_of, recorded_environment
37
+ from amfs_core.actions import entity_paths_of, recorded_covariates, recorded_environment
38
38
  from amfs_core.evidence import cited_entries, outcome_model, outcome_read_keys, outcome_verified_by
39
39
  from amfs_core.models import (
40
40
  OUTCOME_MULTIPLIERS,
@@ -313,6 +313,10 @@ _LOCAL_EVIDENCE_SQL = (
313
313
  _OUTCOME_TASK_TEXT_SQL = (
314
314
  Path(__file__).parent / "migrations" / "011_outcome_task_text.sql"
315
315
  ).read_text(encoding="utf-8")
316
+ #: Migration 014 — the covariates of the task on the outcome row.
317
+ _OUTCOME_COVARIATES_SQL = (
318
+ Path(__file__).parent / "migrations" / "014_outcome_covariates.sql"
319
+ ).read_text(encoding="utf-8")
316
320
  #: Migration 012 — the evidence functions rendered from ``amfs_core.evidence``
317
321
  #: (``evidence_sql.render_evidence_sql``), replacing the hand-written bodies
318
322
  #: of 008/009 with the same arithmetic read off the Python model. Applied
@@ -864,6 +868,7 @@ class PostgresAdapter(AdapterABC):
864
868
  self._has_outcome_embedding_col = False
865
869
  self._has_outcome_env_col = False
866
870
  self._has_task_text_col = False
871
+ self._has_covariates_col = False
867
872
  self._has_verified_by_col = False
868
873
  self._pgvector_version: tuple[int, ...] | None = None
869
874
  # When an embedder is provided, embeddings are computed at write time and
@@ -1375,6 +1380,12 @@ class PostgresAdapter(AdapterABC):
1375
1380
  ALTER TABLE amfs_outcomes
1376
1381
  ADD COLUMN IF NOT EXISTS environment JSONB
1377
1382
  """)
1383
+ # The covariates of the task — the run's declared attributes other
1384
+ # than its environment and situation (the customer's plan, the app
1385
+ # version a lookup showed) — so a contested situation's record can be
1386
+ # split by what separates the runs the old action still wins from the
1387
+ # ones it lost (amfs_core.actions.split_contested). See migration 014.
1388
+ cur.execute(_OUTCOME_COVARIATES_SQL)
1378
1389
  # Query-conditioned evidence: see migration 010.
1379
1390
  cur.execute(_LOCAL_EVIDENCE_SQL)
1380
1391
  # The task text on outcomes: see migration 011.
@@ -1845,7 +1856,7 @@ class PostgresAdapter(AdapterABC):
1845
1856
  WHERE table_name = 'amfs_outcomes'
1846
1857
  AND column_name IN (
1847
1858
  'actions_taken', 'task_embedding', 'environment', 'task_text',
1848
- 'verified_by'
1859
+ 'verified_by', 'covariates'
1849
1860
  )
1850
1861
  """,
1851
1862
  )
@@ -1855,6 +1866,7 @@ class PostgresAdapter(AdapterABC):
1855
1866
  self._has_outcome_env_col = "environment" in found
1856
1867
  self._has_task_text_col = "task_text" in found
1857
1868
  self._has_verified_by_col = "verified_by" in found
1869
+ self._has_covariates_col = "covariates" in found
1858
1870
 
1859
1871
  # ------------------------------------------------------------------
1860
1872
  # read
@@ -4248,6 +4260,15 @@ class PostgresAdapter(AdapterABC):
4248
4260
  columns.append("environment")
4249
4261
  placeholders.append("%s::jsonb")
4250
4262
  params.append(json.dumps(env))
4263
+ if getattr(self, "_has_covariates_col", False):
4264
+ covariates = recorded_covariates({
4265
+ "covariates": record.covariates or None,
4266
+ "session_metadata": record.session_metadata or {},
4267
+ })
4268
+ if covariates:
4269
+ columns.append("covariates")
4270
+ placeholders.append("%s::jsonb")
4271
+ params.append(json.dumps(covariates, default=str))
4251
4272
  task_embedding = self._outcome_embedding(record)
4252
4273
  if task_embedding is not None:
4253
4274
  columns.append("task_embedding")
@@ -4556,9 +4577,10 @@ class PostgresAdapter(AdapterABC):
4556
4577
  conditions.append("committed_at >= %s")
4557
4578
  params.append(since)
4558
4579
  env_col = ", environment" if getattr(self, "_has_outcome_env_col", False) else ""
4580
+ cov_col = ", covariates" if getattr(self, "_has_covariates_col", False) else ""
4559
4581
  sql = f"""
4560
4582
  SELECT outcome_ref, outcome_type, committed_at, agent_id, actions_taken, situation,
4561
- 1 - (task_embedding <=> %s::vector) AS similarity{env_col}
4583
+ 1 - (task_embedding <=> %s::vector) AS similarity{env_col}{cov_col}
4562
4584
  FROM amfs_outcomes
4563
4585
  WHERE {" AND ".join(conditions)}
4564
4586
  ORDER BY task_embedding <=> %s::vector
@@ -4581,6 +4603,7 @@ class PostgresAdapter(AdapterABC):
4581
4603
  "situation": row.get("situation"),
4582
4604
  "actions_taken": _jsonb(row.get("actions_taken"), []),
4583
4605
  "environment": _jsonb(row.get("environment"), {}) or {},
4606
+ "covariates": _jsonb(row.get("covariates"), {}) or {},
4584
4607
  "similarity": sim,
4585
4608
  })
4586
4609
  return out
@@ -4788,8 +4811,9 @@ class PostgresAdapter(AdapterABC):
4788
4811
  conditions.append("committed_at >= %s")
4789
4812
  params.append(since)
4790
4813
  env_col = ", environment" if getattr(self, "_has_outcome_env_col", False) else ""
4814
+ cov_col = ", covariates" if getattr(self, "_has_covariates_col", False) else ""
4791
4815
  sql = f"""
4792
- SELECT outcome_ref, outcome_type, committed_at, agent_id, actions_taken, situation{env_col}
4816
+ SELECT outcome_ref, outcome_type, committed_at, agent_id, actions_taken, situation{env_col}{cov_col}
4793
4817
  FROM amfs_outcomes
4794
4818
  WHERE {" AND ".join(conditions)}
4795
4819
  ORDER BY committed_at DESC
@@ -4807,6 +4831,7 @@ class PostgresAdapter(AdapterABC):
4807
4831
  "situation": row.get("situation"),
4808
4832
  "actions_taken": _jsonb(row.get("actions_taken"), []),
4809
4833
  "environment": _jsonb(row.get("environment"), {}) or {},
4834
+ "covariates": _jsonb(row.get("covariates"), {}) or {},
4810
4835
  "similarity": 1.0,
4811
4836
  } for row in rows]
4812
4837
 
@@ -0,0 +1,20 @@
1
+ -- Migration 014: the covariates of the task on the outcome row
2
+ --
3
+ -- An outcome records what was done (`actions_taken`) in what kind of task
4
+ -- (`situation`) under what runtime (`environment`). It did not record what
5
+ -- the task *was like*: the customer's plan, the app version the lookup
6
+ -- showed, the card's issuer country. When a rule changes for part of a
7
+ -- situation — the export fix stops working on paid plans and keeps working
8
+ -- on the free one — the situation's record turns contested (wins and losses
9
+ -- interleaved, no streak) and nothing in it says which runs the old action
10
+ -- still wins. On the 2026-10-21 regime study the recommendation kept the
11
+ -- stale action as `act` on 59 % of the first searches after such a change.
12
+ --
13
+ -- The covariates are the scalar attributes a run declared about the task
14
+ -- (`set_session_attributes`, `Run.begin(covariates=...)`) less its
15
+ -- environment keys and the situation label, copied here at commit from the
16
+ -- record so `amfs_core.actions.split_contested` can read them off the same
17
+ -- rows the priors are aggregated from. Scalars only; at most the attribute
18
+ -- bag's 20 keys. Written only when the record has any.
19
+
20
+ ALTER TABLE amfs_outcomes ADD COLUMN IF NOT EXISTS covariates JSONB;