fix(build): make uv sync work on fresh clones without the private indicium packages #117
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| lint: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Install ruff | |
| run: pip install ruff | |
| - name: Ruff (report-only, --exit-zero) | |
| run: ruff check src/ tests/ --exit-zero --statistics | |
| uv-resolve: | |
| # Issue #29: uv resolves every extra and every [tool.uv.sources] entry when | |
| # it locks, so one local-path source breaks `uv sync` on every fresh clone. | |
| # The `test` job below installs with pip, which ignores [tool.uv.sources] | |
| # outright and so cannot catch this. A GitHub runner never has the private | |
| # sibling checkouts, which is exactly an external user's environment. | |
| name: uv resolves on a clean checkout | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - uses: astral-sh/setup-uv@v5 | |
| - name: uv lock | |
| run: uv lock | |
| test: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Install package + dev deps | |
| run: pip install -e ".[dev]" | |
| - name: Smoke + config tests (fast, mocked) | |
| # Deselect tool-inventory params that can't run in CI: | |
| # * search_literature/web_search/general_web_search/search_skill_kb | |
| # invoke real external search APIs (SemanticScholar/web) — not | |
| # stubbed by the smoke MagicMock state, so they hit the network | |
| # and time out. | |
| # * build_claim_graph/claim_graph_status/query_claim_graph/ | |
| # get_claim_figures/get_claim_links/claim_graph_export need the | |
| # local-only indicium KG stack (indicium-adapters is not on PyPI). | |
| run: | | |
| pytest tests/integration/ -m "smoke or config" \ | |
| --deselect "tests/integration/test_mcp_smoke.py::test_tool_inventory[search_literature]" \ | |
| --deselect "tests/integration/test_mcp_smoke.py::test_tool_inventory[general_web_search]" \ | |
| --deselect "tests/integration/test_mcp_smoke.py::test_tool_inventory[search_skill_kb]" \ | |
| --deselect "tests/integration/test_mcp_smoke.py::test_tool_inventory[web_search]" \ | |
| --deselect "tests/integration/test_mcp_smoke.py::test_tool_inventory[build_claim_graph]" \ | |
| --deselect "tests/integration/test_mcp_smoke.py::test_tool_inventory[claim_graph_status]" \ | |
| --deselect "tests/integration/test_mcp_smoke.py::test_tool_inventory[query_claim_graph]" \ | |
| --deselect "tests/integration/test_mcp_smoke.py::test_tool_inventory[get_claim_figures]" \ | |
| --deselect "tests/integration/test_mcp_smoke.py::test_tool_inventory[get_claim_links]" \ | |
| --deselect "tests/integration/test_mcp_smoke.py::test_tool_inventory[claim_graph_export]" \ | |
| -v --timeout=30 --timeout-method=signal --no-header | |
| - name: Unit tests (safe subset) | |
| # The indicium knowledge-graph layer depends on the private sibling | |
| # packages indicium / indicium-adapters, which are unpublished and so | |
| # cannot be declared in pyproject.toml at all (see the comment there, | |
| # and issue #29). These modules cannot import under CI's plain | |
| # `pip install -e ".[dev]"`. Excluded here until CI provisions the | |
| # KG stack. | |
| # | |
| # The trailing --deselect block additionally drops individual tests | |
| # that cannot pass in CI without the KG stack or network: | |
| # * test_anchor.py (3) + test_claim_link_query.py — exercise the | |
| # verified path of anchor_claims(), which needs `indicium`'s | |
| # verify_quote kernel (absent here → everything "unverified"). | |
| # * test_web_search_telemetry_sink / test_domain_aggregator — make | |
| # real SemanticScholar calls (429 / timeout); not `live`-marked. | |
| run: | | |
| pytest tests/unit/ \ | |
| --ignore=tests/unit/test_embeddings.py \ | |
| --ignore=tests/unit/test_capsule_builder_orchestrator.py \ | |
| --ignore=tests/unit/test_fetch_doi_lookups.py \ | |
| --ignore=tests/unit/test_anchor_builder.py \ | |
| --ignore=tests/unit/test_builder.py \ | |
| --ignore=tests/unit/test_claim_graph_store.py \ | |
| --ignore=tests/unit/test_claims_extraction.py \ | |
| --ignore=tests/unit/test_claims_validation.py \ | |
| --ignore=tests/unit/test_extraction_anchor.py \ | |
| --ignore=tests/unit/test_invalidation.py \ | |
| --ignore=tests/unit/test_jats_figure_extraction.py \ | |
| --ignore=tests/unit/test_mcp_claim_graph_query_export.py \ | |
| --ignore=tests/unit/test_mcp_export_astra.py \ | |
| --ignore=tests/unit/test_mcp_extract_claims.py \ | |
| --ignore=tests/unit/test_mcp_generate_report_indicia.py \ | |
| --ignore=tests/unit/test_queries.py \ | |
| --ignore=tests/unit/test_queries_traversal.py \ | |
| --ignore=tests/unit/test_reasoning_mode_evidence_graded.py \ | |
| --ignore=tests/unit/test_reasoning_mode_graph.py \ | |
| --deselect tests/unit/test_capsule_reader_ingest.py::test_ingest_chunks_blocks_jsonl \ | |
| --deselect tests/unit/test_capsule_reader_ingest.py::test_ingest_propagates_resource_ids \ | |
| --deselect tests/unit/test_capsule_reader_ingest.py::test_ingest_finalize_false_skips_finish \ | |
| --deselect tests/unit/test_chunking_dispatch.py::test_chunk_falls_back_when_flag_disabled \ | |
| --deselect tests/unit/test_local_docs_capsule_reader_route.py::test_non_capsule_paths_route_to_files \ | |
| --deselect tests/unit/test_local_docs_capsule_reader_route.py::test_mixed_inputs_route_to_both \ | |
| --deselect tests/unit/test_local_docs_external_annotation.py::test_ipynb_outputs_stripped_before_chunking \ | |
| --deselect tests/unit/test_mcp_multi_kb_passthrough.py::test_generate_report_passes_kb_names_to_rag_request \ | |
| --deselect tests/unit/test_mcp_multi_kb_passthrough.py::test_generate_report_single_kb_names_collapses_to_kb_name \ | |
| --deselect tests/unit/test_provenance_engine_wiring.py::test_mcp_generate_report_wires_provenance_and_message_id \ | |
| --deselect tests/unit/test_zotero_ingest_worker.py::test_worker_dedups_by_doi_and_attaches_notes \ | |
| --deselect tests/unit/test_zotero_ingest_worker.py::test_worker_skips_existing_doi \ | |
| --deselect tests/unit/test_anchor.py::test_positional_bug_regression_binds_to_content_match \ | |
| --deselect tests/unit/test_anchor.py::test_strict_drops_unverified_failopen_keeps \ | |
| --deselect tests/unit/test_anchor.py::test_audit_sidecar_written_with_divergent_flag \ | |
| --deselect tests/unit/test_claim_link_query.py::test_get_claim_links_mcp_tool_response_structure \ | |
| --deselect tests/unit/test_domain_aggregator.py::test_retry_counts_as_one_circuit_failure \ | |
| --deselect tests/unit/test_web_search_telemetry_sink.py::test_list_telemetry_sink_receives_events \ | |
| --timeout=15 --timeout-method=signal \ | |
| --no-header --tb=line \ | |
| --cov=src/perspicacite --cov-report=xml --cov-report=term-missing \ | |
| --cov-fail-under=0 | |
| - name: Upload coverage report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report | |
| path: coverage.xml | |
| retention-days: 7 |