From 8b6b5188a52ab882cda5b7bcabb76d907acfac15 Mon Sep 17 00:00:00 2001 From: Robert Date: Sat, 18 Jul 2026 01:16:49 -0300 Subject: [PATCH] Bridge legacy QuoteJudge database columns --- a2a.yaml | 2 +- agent.py | 19 +++++++++++++------ .../003_quotejudge_legacy_bridge.sql | 19 +++++++++++++++++++ tests/test_full_stack_contract.py | 5 +++++ 4 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 db/migrations/003_quotejudge_legacy_bridge.sql diff --git a/a2a.yaml b/a2a.yaml index 7839038..fd94d7d 100644 --- a/a2a.yaml +++ b/a2a.yaml @@ -1,5 +1,5 @@ name: quote-judge-studio-v1 -version: 0.1.4 +version: 0.1.5 entrypoint: agent:QuoteJudgeStudioV1 expose: public: false diff --git a/agent.py b/agent.py index 5ca93d9..462ee44 100644 --- a/agent.py +++ b/agent.py @@ -108,7 +108,7 @@ class QuoteJudgeStudioV1(A2AAgent[QuoteJudgeStudioV1Config, PlatformUserAuth]): "QuoteJudge compares vendor quotes with weighted price, delivery, and " "warranty scoring, persists per-user comparisons, and serves a one-page product UI." ) - version = "0.1.4" + version = "0.1.5" config_model = QuoteJudgeStudioV1Config auth_model = PlatformUserAuth @@ -574,11 +574,14 @@ async def _save_comparison(tenant_key: str, payload: dict[str, Any]) -> None: cur.execute( """ INSERT INTO quote_comparisons - (tenant_key, comparison_id, recommended_vendor, score, normalized_total, payload, updated_at) - VALUES (%s, %s, %s, %s, %s, %s, NOW()) + (tenant_key, comparison_id, recommended_vendor, recommendation_vendor, + score, weighted_score, normalized_total, payload, updated_at) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, NOW()) ON CONFLICT (tenant_key, comparison_id) DO UPDATE SET recommended_vendor = EXCLUDED.recommended_vendor, + recommendation_vendor = EXCLUDED.recommendation_vendor, score = EXCLUDED.score, + weighted_score = EXCLUDED.weighted_score, normalized_total = EXCLUDED.normalized_total, payload = EXCLUDED.payload, updated_at = NOW() @@ -587,6 +590,8 @@ async def _save_comparison(tenant_key: str, payload: dict[str, Any]) -> None: tenant_key, payload["comparison_id"], payload["recommendation"]["vendor"], + payload["recommendation"]["vendor"], + payload["recommendation"]["score"], payload["recommendation"]["score"], payload["recommendation"]["normalized_total"], json.dumps(payload), @@ -645,16 +650,18 @@ async def _persist_receipt( cur.execute( """ INSERT INTO quote_execution_receipts - (tenant_key, comparison_id, receipt_id, skill_name, status, input_hash, - result_hash, payload, created_at) - VALUES (%s, %s, %s, %s, %s, %s, %s, %s, NOW()) + (tenant_key, comparison_id, receipt_id, skill_name, tool_name, status, ok, + input_hash, result_hash, payload, created_at) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW()) """, ( tenant_key, comparison_id, receipt["receipt_id"], skill_name, + skill_name, status, + status == "ok", receipt["input_hash"], receipt["result_hash"], json.dumps(receipt), diff --git a/db/migrations/003_quotejudge_legacy_bridge.sql b/db/migrations/003_quotejudge_legacy_bridge.sql new file mode 100644 index 0000000..d6326bf --- /dev/null +++ b/db/migrations/003_quotejudge_legacy_bridge.sql @@ -0,0 +1,19 @@ +-- Bridge the earliest QuoteJudge schema and the current typed schema without +-- dropping data or weakening historical NOT NULL constraints. +ALTER TABLE quote_comparisons + ADD COLUMN IF NOT EXISTS recommendation_vendor TEXT, + ADD COLUMN IF NOT EXISTS weighted_score NUMERIC(10,4); + +UPDATE quote_comparisons +SET recommendation_vendor = COALESCE(recommendation_vendor, recommended_vendor), + weighted_score = COALESCE(weighted_score, score) +WHERE recommendation_vendor IS NULL OR weighted_score IS NULL; + +ALTER TABLE quote_execution_receipts + ADD COLUMN IF NOT EXISTS tool_name TEXT, + ADD COLUMN IF NOT EXISTS ok BOOLEAN; + +UPDATE quote_execution_receipts +SET tool_name = COALESCE(tool_name, skill_name), + ok = COALESCE(ok, status = 'ok') +WHERE tool_name IS NULL OR ok IS NULL; diff --git a/tests/test_full_stack_contract.py b/tests/test_full_stack_contract.py index a540889..5506eee 100644 --- a/tests/test_full_stack_contract.py +++ b/tests/test_full_stack_contract.py @@ -60,6 +60,11 @@ def test_full_stack_product_contract(): migrations = list((ROOT / "db" / "migrations").glob("*.sql")) assert migrations and all(path.read_text(encoding="utf-8").strip() for path in migrations) + compatibility = (ROOT / "db" / "migrations" / "003_quotejudge_legacy_bridge.sql").read_text() + assert "recommendation_vendor" in compatibility + assert "tool_name" in compatibility + assert "recommendation_vendor = EXCLUDED.recommendation_vendor" in source + assert "tool_name, status, ok" in source card = load_local_project(ROOT).agent_cls().card() skill_names = {skill.name for skill in card.skills}