diff --git a/a2a.yaml b/a2a.yaml index a58e543..b58dc07 100644 --- a/a2a.yaml +++ b/a2a.yaml @@ -1,5 +1,5 @@ name: contract-clock-studio-v1 -version: 0.1.7 +version: 0.1.8 entrypoint: agent:ContractClockStudioV1 expose: public: false diff --git a/agent.py b/agent.py index b1078e5..7894932 100644 --- a/agent.py +++ b/agent.py @@ -108,7 +108,7 @@ class ContractClockStudioV1(A2AAgent[ContractClockStudioV1Config, PlatformUserAu "from contracts, persists user-scoped timelines, and serves a packed " "one-page React product at /app." ) - version = "0.1.7" + version = "0.1.8" config_model = ContractClockStudioV1Config auth_model = PlatformUserAuth diff --git a/db/migrations/002_reconcile_execution_receipts.sql b/db/migrations/002_reconcile_execution_receipts.sql index a697e34..775a914 100644 --- a/db/migrations/002_reconcile_execution_receipts.sql +++ b/db/migrations/002_reconcile_execution_receipts.sql @@ -19,6 +19,8 @@ BEGIN ) THEN EXECUTE 'UPDATE execution_receipts SET tool_name = COALESCE(tool_name, skill_name)'; + EXECUTE 'ALTER TABLE execution_receipts + ALTER COLUMN skill_name DROP NOT NULL'; END IF; END $$; diff --git a/db/migrations/003_relax_legacy_receipt_skill.sql b/db/migrations/003_relax_legacy_receipt_skill.sql new file mode 100644 index 0000000..45353c1 --- /dev/null +++ b/db/migrations/003_relax_legacy_receipt_skill.sql @@ -0,0 +1,18 @@ +-- Migration 002 may already have run on a legacy database before its +-- skill_name constraint reconciliation was added. Relax that obsolete column +-- in a separately versioned migration so current installations are repaired. +DO $$ +BEGIN + IF EXISTS ( + SELECT 1 + FROM information_schema.columns + WHERE table_schema = current_schema() + AND table_name = 'execution_receipts' + AND column_name = 'skill_name' + AND is_nullable = 'NO' + ) THEN + EXECUTE 'ALTER TABLE execution_receipts + ALTER COLUMN skill_name DROP NOT NULL'; + END IF; +END +$$; diff --git a/tests/test_full_stack_contract.py b/tests/test_full_stack_contract.py index 847addd..de27db7 100644 --- a/tests/test_full_stack_contract.py +++ b/tests/test_full_stack_contract.py @@ -26,7 +26,7 @@ def test_full_stack_product_contract_card_and_manifest(): frontend = (ROOT / "frontend" / "src" / "App.jsx").read_text(encoding="utf-8") a2a_client = (ROOT / "frontend" / "src" / "a2a.js").read_text(encoding="utf-8") - assert "version: 0.1.7" in manifest + assert "version: 0.1.8" in manifest assert "public: false" in manifest assert "frontend:" in manifest and "mount: /app" in manifest assert "resources:" in manifest and "databases:" in manifest @@ -44,7 +44,7 @@ def test_full_stack_product_contract_card_and_manifest(): assert migrations and all(path.read_text(encoding="utf-8").strip() for path in migrations) card = load_local_project(ROOT).agent_cls().card() - assert card.version == "0.1.7" + assert card.version == "0.1.8" skill_names = {skill.name for skill in card.skills} assert {"analyze_contract", "get_contract_deadlines", "analyze_contract_upload_base64", "analyze_contract_file"} <= skill_names analyze_schema = next(skill.input_schema for skill in card.skills if skill.name == "analyze_contract") @@ -63,8 +63,15 @@ def test_full_stack_product_contract_card_and_manifest(): ) assert "ADD COLUMN IF NOT EXISTS tool_name" in reconciliation assert "COALESCE(tool_name, skill_name)" in reconciliation + assert "ALTER COLUMN skill_name DROP NOT NULL" in reconciliation assert "ALTER COLUMN input_hash SET NOT NULL" in reconciliation + legacy_constraint_fix = ( + ROOT / "db" / "migrations" / "003_relax_legacy_receipt_skill.sql" + ).read_text(encoding="utf-8") + assert "column_name = 'skill_name'" in legacy_constraint_fix + assert "ALTER COLUMN skill_name DROP NOT NULL" in legacy_constraint_fix + def test_explicit_date_only_success_and_failure(): module = load_agent_module()