From e080e9b30761895a9f37df028964279160bf307e Mon Sep 17 00:00:00 2001 From: Patrick Stinson Date: Sat, 16 May 2026 23:00:46 -0800 Subject: [PATCH 1/2] ci: run btcopilot unit tests on PRs to master Mirrors the proven test invocation from release.yml's post-merge job (pytest --pyargs btcopilot.tests, e2e auto-skipped) but on pull_request so it can gate merges via branch protection. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..e7a3af16 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + pull_request: + branches: + - master + workflow_dispatch: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + unit-tests: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: pip + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install .[app,test] + + - name: Verify test package import + run: python -c "import btcopilot.tests; print(btcopilot.tests)" + + - name: Run unit tests + run: pytest -svv --disable-warnings --pyargs btcopilot.tests From 3432ab3ab66984de21e113755e5c538ed5dbc8fb Mon Sep 17 00:00:00 2001 From: Patrick Stinson Date: Sat, 16 May 2026 23:15:04 -0800 Subject: [PATCH 2/2] fix: repair 4 stale unit tests - test_claude_backend (3): the mocked Anthropic client's close() must be awaitable; production code correctly awaits client.close(). - test_validate_deltas_allows_offspring_without_spouse (1): FD-329 (4fa19f8) intentionally rejects person==child birth self-references; test predates it and used person==1,child==1. Use a distinct child id, preserving the no-spouse intent. Full btcopilot.tests suite: 685 passed, 0 failed. Co-Authored-By: Claude Opus 4.7 (1M context) --- btcopilot/tests/personal/test_claude_backend.py | 3 +++ btcopilot/tests/schema/test_validation.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/btcopilot/tests/personal/test_claude_backend.py b/btcopilot/tests/personal/test_claude_backend.py index 8b9fd18d..3c6ed6c0 100644 --- a/btcopilot/tests/personal/test_claude_backend.py +++ b/btcopilot/tests/personal/test_claude_backend.py @@ -94,6 +94,7 @@ async def test_claude_text_with_turns(): with patch("btcopilot.llmutil._anthropic_client") as mock_client_fn: mock_client = MagicMock() mock_client.messages.create = mock_create + mock_client.close = AsyncMock() mock_client_fn.return_value = mock_client result = await claude_text( @@ -119,6 +120,7 @@ async def test_claude_text_with_simple_prompt(): with patch("btcopilot.llmutil._anthropic_client") as mock_client_fn: mock_client = MagicMock() mock_client.messages.create = mock_create + mock_client.close = AsyncMock() mock_client_fn.return_value = mock_client result = await claude_text(prompt="What is 2+2?") @@ -136,6 +138,7 @@ def test_claude_text_sync(): with patch("btcopilot.llmutil._anthropic_client") as mock_client_fn: mock_client = MagicMock() mock_client.messages.create = mock_create + mock_client.close = AsyncMock() mock_client_fn.return_value = mock_client result = claude_text_sync(prompt="Hello") diff --git a/btcopilot/tests/schema/test_validation.py b/btcopilot/tests/schema/test_validation.py index 0f9fe642..f05f7a81 100644 --- a/btcopilot/tests/schema/test_validation.py +++ b/btcopilot/tests/schema/test_validation.py @@ -232,7 +232,7 @@ def test_validate_deltas_allows_offspring_without_spouse(): deltas = PDPDeltas( events=[ Event( - id=-1, kind=kind, person=1, child=1, spouse=None, description="x", dateTime="2025-01-01" + id=-1, kind=kind, person=1, child=2, spouse=None, description="x", dateTime="2025-01-01" ) ] )