proofpath 0.2.1__tar.gz → 0.4.0__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.
- proofpath-0.4.0/.env.example +9 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/CHANGELOG.md +93 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/PKG-INFO +97 -10
- {proofpath-0.2.1 → proofpath-0.4.0}/README.md +96 -9
- proofpath-0.4.0/docs/eval/2026-09-15-judge-live.md +95 -0
- proofpath-0.4.0/docs/eval/2026-09-16-averitec.md +95 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/superpowers/OPEN-ITEMS.md +90 -7
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/superpowers/plans/2026-09-10-proofpath-implementation-plan.md +24 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/superpowers/specs/2026-09-10-proofpath-design.md +41 -5
- proofpath-0.4.0/scripts/eval_averitec.py +385 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/__init__.py +1 -1
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/cache.py +91 -4
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/claims.py +106 -2
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/cli.py +86 -13
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/document.py +10 -1
- proofpath-0.4.0/src/proofpath/eval/averitec.py +148 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/ingest.py +136 -1
- proofpath-0.4.0/src/proofpath/judge.py +781 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/polite.py +70 -4
- proofpath-0.4.0/src/proofpath/prompts/__init__.py +1 -0
- proofpath-0.4.0/src/proofpath/prompts/review.md +40 -0
- proofpath-0.4.0/src/proofpath/prompts/summarize.md +30 -0
- proofpath-0.4.0/src/proofpath/providers/__init__.py +318 -0
- proofpath-0.4.0/src/proofpath/providers/academic.py +117 -0
- proofpath-0.4.0/src/proofpath/providers/social.py +915 -0
- proofpath-0.4.0/src/proofpath/providers/web.py +120 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/report.py +272 -6
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/resolve.py +18 -1
- proofpath-0.4.0/src/proofpath/secrets.py +115 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/app.py +104 -3
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/runs.py +13 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/widgets/run_block.py +13 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/ui.py +72 -6
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/verify.py +720 -250
- proofpath-0.4.0/tests/data/verify-report-golden.json +630 -0
- proofpath-0.4.0/tests/fixtures/social/bsky-blocked.json +11 -0
- proofpath-0.4.0/tests/fixtures/social/bsky-not-found.json +4 -0
- proofpath-0.4.0/tests/fixtures/social/bsky-quote-blocked.json +28 -0
- proofpath-0.4.0/tests/fixtures/social/bsky-resolve-handle.json +3 -0
- proofpath-0.4.0/tests/fixtures/social/bsky-thread-gone.json +7 -0
- proofpath-0.4.0/tests/fixtures/social/bsky-thread.json +70 -0
- proofpath-0.4.0/tests/fixtures/social/hn-comment.json +8 -0
- proofpath-0.4.0/tests/fixtures/social/hn-dead.json +9 -0
- proofpath-0.4.0/tests/fixtures/social/hn-deleted.json +6 -0
- proofpath-0.4.0/tests/fixtures/social/hn-missing.json +1 -0
- proofpath-0.4.0/tests/fixtures/social/hn-story.json +11 -0
- proofpath-0.4.0/tests/fixtures/social/mastodon-login-required.json +1 -0
- proofpath-0.4.0/tests/fixtures/social/mastodon-status.json +12 -0
- proofpath-0.4.0/tests/fixtures/social/reddit-comment.json +38 -0
- proofpath-0.4.0/tests/fixtures/social/reddit-link-post.json +26 -0
- proofpath-0.4.0/tests/fixtures/social/reddit-nested-comment.json +55 -0
- proofpath-0.4.0/tests/fixtures/social/reddit-post.json +26 -0
- proofpath-0.4.0/tests/fixtures/social/reddit-removed.json +27 -0
- proofpath-0.4.0/tests/fixtures/social/reddit-token.json +6 -0
- proofpath-0.4.0/tests/test_averitec.py +221 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_cache.py +148 -5
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_check_cli.py +400 -8
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_claims.py +122 -1
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_document.py +7 -2
- proofpath-0.4.0/tests/test_eval_averitec.py +276 -0
- proofpath-0.4.0/tests/test_judge.py +959 -0
- proofpath-0.4.0/tests/test_providers.py +549 -0
- proofpath-0.4.0/tests/test_providers_social.py +1281 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_report.py +341 -1
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_sarif.py +30 -2
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_tui_app.py +161 -15
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_tui_runs.py +28 -7
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_ui.py +103 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_verify.py +563 -3
- proofpath-0.4.0/tests/test_verify_golden.py +239 -0
- proofpath-0.4.0/tests/test_verify_routing.py +255 -0
- proofpath-0.2.1/.env.example +0 -4
- proofpath-0.2.1/src/proofpath/judge.py +0 -149
- proofpath-0.2.1/tests/test_judge.py +0 -106
- {proofpath-0.2.1 → proofpath-0.4.0}/.editorconfig +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/.gitattributes +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/.github/ISSUE_TEMPLATE/wrong_verdict.yml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/.github/workflows/ci.yml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/.github/workflows/release.yml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/.gitignore +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/CLAUDE.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/CONTRIBUTING.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/LICENSE +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/SECURITY.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-11-coverage.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-11-ghosts.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-11-pairing.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-11-scifact-dev.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-12-ghosts.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-12-pairing-author-year.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-12-scifact-dev.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-12-tiers.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-12-v0.1-live.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-15-tui-v2-live.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/2026-09-15-v0.2-live.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/tui-v2-plain.svg +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/eval/tui-v2-rich.svg +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/research/2026-09-11-free-llm-api-tiers.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/superpowers/plans/2026-09-12-phases-9-10-plan.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/docs/superpowers/specs/2026-09-15-tui-v2-design.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/pyproject.toml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/scripts/eval_coverage.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/scripts/eval_ghosts.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/scripts/eval_pairing.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/scripts/eval_scifact.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/scripts/zero_network_check.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/browser.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/commands.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/config.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/device.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/entailment.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/eval/__init__.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/eval/metrics.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/eval/scifact.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/events.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/fetch.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/models.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/numerics.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/oa.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/paths.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/pipeline.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/py.typed +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/retrieval.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/sarif.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/__init__.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/banner.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/commands.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/pet.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/theme.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/verbs.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/widgets/__init__.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/widgets/_shared.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/widgets/banner.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/widgets/finding.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/widgets/footer.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/src/proofpath/tui/widgets/prompt.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/__init__.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/conftest.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/data/draft-author-year.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/data/draft-live.md +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/data/ghost_set.jsonl +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/data/pairing_author_year.jsonl +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/data/pairing_set.jsonl +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/data/sarif-schema-2.1.0.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fakes.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/crossref_work.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/crossref_work_no_abstract.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/europepmc_fulltext.xml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/europepmc_search.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/europepmc_search_empty.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/europepmc_search_not_in_epmc.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/openalex_work.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/s2_paper.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/s2_paper_no_abstract.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/unpaywall.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/unpaywall_closed.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/oa/unpaywall_landing_only.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/arxiv_id_roberta.xml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/arxiv_title_fabricated.xml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/arxiv_title_roberta.xml +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/crossref_alphafold.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/crossref_fabricated.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/crossref_numpy.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/crossref_rag.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/crossref_retracted_wakefield.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/crossref_roberta.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/crossref_work_alphafold.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/crossref_work_numpy.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/openalex_alphafold.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/openalex_fabricated.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/openalex_rag.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/openalex_retracted_wakefield.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/openalex_roberta.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/openlibrary_fabricated.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/openlibrary_using_language.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/s2_alphafold.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/s2_fabricated.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/s2_rag.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/fixtures/resolve/s2_roberta.json +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_browser.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_cache_cli.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_cli.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_commands.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_config.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_config_cli.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_device.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_entailment.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_eval_coverage.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_eval_pairing.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_eval_scifact.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_fetch.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_fetch_cli.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_ingest.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_metrics.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_models.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_numerics.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_oa.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_pipeline.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_polite.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_resolve.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_resolve_cli.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_retrieval.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_scifact.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_tui_banner.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_tui_commands.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_tui_pet.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_tui_rich.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_tui_theme.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/tests/test_version.py +0 -0
- {proofpath-0.2.1 → proofpath-0.4.0}/uv.lock +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Copy to .env (gitignored) and fill in. Only the optional LLM judge needs a key;
|
|
2
|
+
# everything else runs offline. See `proofpath judge` for where this file is read.
|
|
3
|
+
GROQ_API_KEY=
|
|
4
|
+
# GEMINI_API_KEY=
|
|
5
|
+
# A free Reddit app (https://www.reddit.com/prefs/apps, type "script"): its id.
|
|
6
|
+
REDDIT_CLIENT_ID=
|
|
7
|
+
# The same app's secret. Without both, a cited Reddit post is reported as
|
|
8
|
+
# UNVERIFIED (credentials missing) rather than silently skipped.
|
|
9
|
+
REDDIT_CLIENT_SECRET=
|
|
@@ -6,6 +6,99 @@ All notable changes to this project are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.0] - 2026-09-16
|
|
10
|
+
|
|
11
|
+
Sources that are not papers: a post's links, and the coverage block that finally says why
|
|
12
|
+
a source could not be read. Also the first end-to-end measurement on real web claims, which
|
|
13
|
+
says plainly that this is not yet the thing to point at a news story
|
|
14
|
+
(`docs/eval/2026-09-16-averitec.md`).
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- **`check --url`** reads a post and verifies **the links inside it**, never the post's own
|
|
18
|
+
words (spec §6.2). Bluesky (`public.api.bsky.app`) and Hacker News (the Firebase API) are
|
|
19
|
+
first-class and need no account; Reddit reads with a free app you register yourself
|
|
20
|
+
(`REDDIT_CLIENT_ID` / `REDDIT_CLIENT_SECRET` in `.env`); Mastodon is best effort per
|
|
21
|
+
instance; X cannot be read and says so, asking you to paste the text. Pasted text with
|
|
22
|
+
links in it is verified the same way.
|
|
23
|
+
- **`UNVERIFIED (credentials missing)`** (spec §15): a platform that reads only with a
|
|
24
|
+
credential this machine does not have is its own state, never "unreachable". No request is
|
|
25
|
+
made, both variable names are printed, and the secret itself never reaches a log, an error
|
|
26
|
+
or a `repr`.
|
|
27
|
+
- **The coverage block now prints a line per reason** on the terminal and in the markdown
|
|
28
|
+
report, not only in SARIF. `blocked: 3`, `credentials missing: 1`, `unreachable: 2` — a
|
|
29
|
+
source with no recorded reason is listed rather than dropped, so the lines account for
|
|
30
|
+
every unverified source. Product rule 6 on its main surface. The TUI footer does not carry
|
|
31
|
+
them yet.
|
|
32
|
+
- **A `providers/` package** (`academic`, `web`, `social`) behind the `EvidenceProvider`
|
|
33
|
+
protocol of spec §5.2, so a new source family no longer means touching the core. The
|
|
34
|
+
academic and web paths came through byte-identical, pinned by a golden report.
|
|
35
|
+
- **`docs/eval/2026-09-16-averitec.md`**: 100 AVeriTeC dev claims through the whole product.
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
- A bare DOI or arXiv **URL** is resolved as a record again instead of being fetched as a
|
|
39
|
+
web page, so it keeps its retraction check and its open-access full text.
|
|
40
|
+
- A `doi:` source is read through the open-access chain and retraction-checked by the
|
|
41
|
+
academic provider whoever resolved the entry — a warm cache could previously route both
|
|
42
|
+
to the web ladder, where a missing retraction notice was reported as "no notice".
|
|
43
|
+
- The `Resolving` stage no longer names Crossref and Semantic Scholar on a run that asked
|
|
44
|
+
neither.
|
|
45
|
+
- A document that cites by linking is never paired as if it printed a numbered bibliography,
|
|
46
|
+
and vice versa: a PDF with a bibliography and no detected marker could previously pair a
|
|
47
|
+
body sentence to a reference it never cited.
|
|
48
|
+
- `check --url` consults the network permission before reading anything; a denied run makes
|
|
49
|
+
no request at all.
|
|
50
|
+
|
|
51
|
+
### Measured
|
|
52
|
+
- AVeriTeC dev, 100 claims: **0.270 3-way accuracy against a 0.708 majority baseline**
|
|
53
|
+
(4-way 0.240). A third of the claims had no readable source; on the rest the score is
|
|
54
|
+
0.361. Every `Supported` claim was missed. Nothing was tuned after the measurement.
|
|
55
|
+
|
|
56
|
+
## [0.3.0] - 2026-09-15
|
|
57
|
+
|
|
58
|
+
The judge layer: an opt-in LLM second opinion and an opt-in model-written summary.
|
|
59
|
+
The default run still makes zero LLM calls, and nothing the model says can change a
|
|
60
|
+
verdict. Live run on Groq in `docs/eval/2026-09-15-judge-live.md`.
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
- **`check --judge`** (`judge.py`, `verify.py`). After the local verdicts are final, the
|
|
64
|
+
`low`-tier ones — never a numeric mismatch, never a claim without a quoted passage —
|
|
65
|
+
go to the model in batches of up to 20 items (about 7k tokens), each with its claim and
|
|
66
|
+
passage. The opinion (`SUPPORTED | REFUTED | NEI` plus a one-sentence rationale) is
|
|
67
|
+
attached beside the verdict: a `= judge (groq openai/gpt-oss-120b): …` line under a
|
|
68
|
+
finding it disagrees with, a `judge` column in the markdown `## Checked` table, and
|
|
69
|
+
`judge` fields in the JSON. The local `Verdict`, the finding kind and every state are
|
|
70
|
+
untouched (spec §11.1). Opinions are cached in the new `judgements` table (schema v4,
|
|
71
|
+
additive; wiped with the verdicts when a source's text changes), so a re-run asks
|
|
72
|
+
nothing, and `model_id` is untouched, so toggling `--judge` never invalidates a verdict.
|
|
73
|
+
- **`check --summarize`** and the TUI's **`/summarize`**: one extra call over the finished
|
|
74
|
+
markdown report, run after the report is final, off by default in both front-ends,
|
|
75
|
+
printed as `summary (model-written, groq openai/gpt-oss-120b) …` and as
|
|
76
|
+
`## Summary (model-written, …)` in the file. `--summarize` alone is exactly one call.
|
|
77
|
+
- **`JudgeClient`**: one adapter for Groq (default `openai/gpt-oss-120b`), Gemini and
|
|
78
|
+
Ollama over the OpenAI `chat/completions` shape; strict JSON-schema output with a
|
|
79
|
+
`json_object` fallback, `reasoning_effort=low` with a fallback for providers that
|
|
80
|
+
reject it, `Retry-After` on 429 (capped, accounted), exponential backoff on 5xx, then
|
|
81
|
+
`JudgeUnavailable`. The key comes from the environment or `.env`, never from config,
|
|
82
|
+
never appears in `repr`, errors or logs; provider bodies are never echoed. Prompts are
|
|
83
|
+
packaged template files (`proofpath/prompts/review.md`, `summarize.md`).
|
|
84
|
+
- **Cost on every surface**: the `Judging` and `Summarising` stage lines carry calls and
|
|
85
|
+
prompt/completion tokens; the footer counts the calls; `Report.judge_cost` and
|
|
86
|
+
`models["judge"]` land in the JSON.
|
|
87
|
+
- **An unanswered judge is reported, not hidden**: `judge unavailable after N calls
|
|
88
|
+
(HTTP 401 from …); local verdicts stand` in the stage line, the report header
|
|
89
|
+
(`judge status:` / `summary status:`), the JSON and an unsuppressed terminal line — a
|
|
90
|
+
`-q` or piped run cannot look like a judged-clean one. The SARIF log does not carry it.
|
|
91
|
+
The run never fails because of the judge.
|
|
92
|
+
- Gemini prints its data-use warning once per run (spec §11).
|
|
93
|
+
|
|
94
|
+
### Changed
|
|
95
|
+
- `check --judge` / `--summarize` no longer exit with `arrives in v0.3`.
|
|
96
|
+
- Cache schema **v4** (`judgements`); a v1 file still migrates through the whole chain.
|
|
97
|
+
- The markdown `## Checked` table always carries a `judge` column; without `--judge` every
|
|
98
|
+
cell is `—`, so a v0.2 report and a v0.3 one differ by that column alone.
|
|
99
|
+
- `--format json` gained `summary`, `summary_model`, `judge_cost` and per-result `judge`
|
|
100
|
+
fields; every one of them is `null` on a default run.
|
|
101
|
+
|
|
9
102
|
## [0.2.1] - 2026-09-15
|
|
10
103
|
|
|
11
104
|
The TUI's second look. No behaviour change: every state word, every honesty sentence,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: proofpath
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Check whether the sources behind a claim actually say what the claim says.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Yigtwxx/proofpath
|
|
6
6
|
Project-URL: Repository, https://github.com/Yigtwxx/proofpath
|
|
@@ -82,7 +82,7 @@ proofpath
|
|
|
82
82
|
╸┤ o o ╰~~~~~~~~~~~~~[PROOF]
|
|
83
83
|
╰─┬─┬────────────────────────────────────────────────────────────────┬─┬──╯
|
|
84
84
|
˘ ˘ ˘ ˘
|
|
85
|
-
proofpath v0.
|
|
85
|
+
proofpath v0.4.0 academic . online . coreml
|
|
86
86
|
paste a file path, a URL, or a claim. /help /config /quit
|
|
87
87
|
```
|
|
88
88
|
|
|
@@ -115,7 +115,7 @@ either, for screenshots and bug reports.
|
|
|
115
115
|
```
|
|
116
116
|
,_,
|
|
117
117
|
(o.o)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[PROOF]
|
|
118
|
-
" " proofpath v0.
|
|
118
|
+
" " proofpath v0.4.0 academic . online . coreml
|
|
119
119
|
paste a file path, a URL, or a claim. /help /config /quit
|
|
120
120
|
```
|
|
121
121
|
|
|
@@ -202,6 +202,7 @@ distinct, printed state (spec §15), never collapsed into a verdict:
|
|
|
202
202
|
| `UNVERIFIED (reached, no text extracted)` | 200 answered, nothing readable came back |
|
|
203
203
|
| `UNVERIFIED (network not permitted)` | `permissions.network = deny` |
|
|
204
204
|
| `UNVERIFIED (provider unavailable)` | API down, rate limited after backoff, or answering with a page instead of a record |
|
|
205
|
+
| `UNVERIFIED (credentials missing)` | the platform reads only with a credential this machine has none of — Reddit's free app, `REDDIT_CLIENT_ID` and `REDDIT_CLIENT_SECRET`. Nobody was asked, so it is not "unreachable"; the coverage block names both variables |
|
|
205
206
|
| `UNVERIFIED (not in bibliographic indexes)` | web page, blog, report — indexes do not cover it, so absence proves nothing |
|
|
206
207
|
| `AMBIGUOUS` | several plausible records, all listed |
|
|
207
208
|
| `NEI` | the source was read and neither supports nor contradicts |
|
|
@@ -239,7 +240,12 @@ runtime teardown); fixed in v0.1 — 20 of 20 piped runs exit `1`
|
|
|
239
240
|
counted as unreachable.
|
|
240
241
|
- **Coverage is not perfectly reproducible**: two runs minutes apart can read a
|
|
241
242
|
different number of sources, depending on which providers answered.
|
|
242
|
-
- The
|
|
243
|
+
- **The judge is a second opinion, not a second verdict.** `--judge` asks the model only
|
|
244
|
+
about the low-tier verdicts (1 of 10 on the live draft), and its answer is printed
|
|
245
|
+
beside the local verdict, never in place of it. `--summarize` is one extra call over
|
|
246
|
+
the finished report, labelled model-written; if the provider does not answer, the
|
|
247
|
+
markdown report, the JSON and the terminal say so (`judge status` / `summary status`
|
|
248
|
+
in the header). The SARIF log does not carry it — it is a findings document.
|
|
243
249
|
|
|
244
250
|
## Speed
|
|
245
251
|
|
|
@@ -273,13 +279,79 @@ TablePlus or DBeaver — plain tables, no extension. Raw publisher text expires
|
|
|
273
279
|
7 days; verdicts keep the passage they quote; a provider outage is never stored.
|
|
274
280
|
`proofpath resolve REF` and `proofpath fetch URL|DOI` run either half on its own.
|
|
275
281
|
|
|
276
|
-
##
|
|
282
|
+
## Posts and the links inside them (v0.4)
|
|
277
283
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
284
|
+
A social post is not a source. What proofpath checks is whether the **links inside it**
|
|
285
|
+
back what it says:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
proofpath check --url https://bsky.app/profile/bsky.app/post/3movpwtbjgs2d
|
|
289
|
+
proofpath check --url https://news.ycombinator.com/item?id=8863
|
|
290
|
+
proofpath check - # paste the text of a post that cannot be read
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Every sentence of the post is checked against the pages its links point to, and the post's
|
|
294
|
+
own words are never allowed to stand as their own evidence.
|
|
295
|
+
|
|
296
|
+
| Platform | How it is read |
|
|
297
|
+
|---|---|
|
|
298
|
+
| Bluesky | `public.api.bsky.app`, no account, first-class. Link cards, rich-text links and one level of quoted post |
|
|
299
|
+
| Hacker News | the official Firebase API, no account, first-class. A story's URL and the links in a comment |
|
|
300
|
+
| Reddit | with a **free app you register yourself**: put `REDDIT_CLIENT_ID` and `REDDIT_CLIENT_SECRET` in `.env`. Without them the run says `UNVERIFIED (credentials missing)` and names both variables — it never quietly skips the post |
|
|
301
|
+
| Mastodon | best effort, per instance. Many instances now require a login for the public API, and that answer is reported as `UNVERIFIED (blocked)`, not as a missing post |
|
|
302
|
+
| X / Twitter | cannot be read at all. `check --url` says so and asks you to paste the text; the links inside it are then verified normally |
|
|
303
|
+
|
|
304
|
+
The Reddit path is built against Reddit's documented shapes and covered by fixtures, but it
|
|
305
|
+
has never run against Reddit on this machine — nobody here has an app to register. Bluesky,
|
|
306
|
+
Hacker News and Mastodon were each read live before release.
|
|
307
|
+
|
|
308
|
+
## Optional LLM judge (v0.3)
|
|
309
|
+
|
|
310
|
+
Everything above runs locally, and the default run makes **zero** LLM calls. Two flags
|
|
311
|
+
add an LLM at the end, and only there:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
proofpath check paper.pdf --judge # a second opinion on the low-confidence verdicts
|
|
315
|
+
proofpath check paper.pdf --summarize # one model-written paragraph over the finished report
|
|
316
|
+
proofpath config check # proves the key works before you spend a run on it
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**What `--judge` does.** After the local verdicts are final, the verdicts the models
|
|
320
|
+
were least sure about — the `low` tier, never a numeric mismatch and never a claim
|
|
321
|
+
without a quoted passage — go to the model in batches of up to 20 (about 7k tokens),
|
|
322
|
+
each with its claim and the passage it was checked against. The model answers from the
|
|
323
|
+
passage alone, and its label and one-sentence rationale are printed **beside** the local
|
|
324
|
+
verdict: `= judge (groq openai/gpt-oss-120b): NEI — …`. The local verdict, the finding
|
|
325
|
+
kind and the report's states never change. Opinions are cached with the verdict, so a
|
|
326
|
+
re-run asks nothing.
|
|
327
|
+
|
|
328
|
+
**What it cannot do.** It never sees a source document, so it cannot introduce a claim
|
|
329
|
+
or an evidence passage of its own; it cannot turn `NEI` into `SUPPORTED`; it cannot
|
|
330
|
+
hide a source that could not be read. If the provider is down, rate-limited or the key
|
|
331
|
+
is wrong, the run finishes on the local verdicts and says so in the stage line, the
|
|
332
|
+
report header (`judge status:`) and the JSON — `-q` cannot hide it.
|
|
333
|
+
|
|
334
|
+
**What `--summarize` does.** One final call turns the finished markdown report into 3–5
|
|
335
|
+
plain sentences a reader can act on. It runs after the report is complete, its only
|
|
336
|
+
input is that report, it is off by default in the CLI and the TUI (`/summarize` there),
|
|
337
|
+
and the output is labelled `(model-written, <provider> <model>)`. `--summarize` alone
|
|
338
|
+
is exactly one call; with `--judge` the escalation runs first.
|
|
339
|
+
|
|
340
|
+
**Cost.** The footer counts the calls and the stage line the tokens:
|
|
341
|
+
`Judging … 1 of 10 verdicts reviewed, 1 call, 613 prompt · 193 completion tokens` and
|
|
342
|
+
`Summarising … 98 words, 1 call, 1,608 prompt · 343 completion tokens`
|
|
343
|
+
on the live draft ([details](docs/eval/2026-09-15-judge-live.md)). Groq's free tier
|
|
344
|
+
allows roughly one call a minute. Only the low-tier verdicts are sent — 1 of 10 on that
|
|
345
|
+
draft — and up to 20 go in one call, so a long bibliography costs a handful of calls, not
|
|
346
|
+
one per citation.
|
|
347
|
+
|
|
348
|
+
**Providers.** Default is Groq `openai/gpt-oss-120b` (free without a card, no training
|
|
349
|
+
on submitted data). `proofpath config set judge.provider gemini` switches to Gemini —
|
|
350
|
+
note that Google trains on free-tier prompts outside the EEA/UK/CH, and proofpath prints
|
|
351
|
+
that warning once per run. `judge.provider ollama` runs fully offline. Gemini and Ollama are
|
|
352
|
+
fixture-tested and were not exercised live in v0.3.0. All three speak
|
|
353
|
+
the OpenAI `chat/completions` shape. The key comes from `GROQ_API_KEY` / `GEMINI_API_KEY`
|
|
354
|
+
in the environment or a `.env` file, never from config, and is never printed.
|
|
283
355
|
|
|
284
356
|
## Measured
|
|
285
357
|
|
|
@@ -290,6 +362,21 @@ comes from the environment or a `.env` file, never from config, and is never pri
|
|
|
290
362
|
| Source access | 50 DOIs | 72 % full text, 18 % abstract only, 10 % nothing ([details](docs/eval/2026-09-11-coverage.md)) — a real biomedical paper in the live runs reached 33 % full text |
|
|
291
363
|
| Citation pairing, numeric | 61 hand-built passages | 0.99 ([details](docs/eval/2026-09-11-pairing.md)) |
|
|
292
364
|
| Citation pairing, author-year | 55 hand-built passages, 83 expectations | 0.940 ([details](docs/eval/2026-09-12-pairing-author-year.md)) |
|
|
365
|
+
| **End to end on real web claims** | AVeriTeC dev, 100 claims | **0.270 3-way accuracy against a 0.708 majority baseline — worse than always guessing "refuted"** ([details](docs/eval/2026-09-16-averitec.md)) |
|
|
366
|
+
|
|
367
|
+
**The AVeriTeC row is the one to read before trusting this tool on a news claim.** A third
|
|
368
|
+
of those claims had no readable source at all: 32 of the source URLs needed the browser
|
|
369
|
+
step, 29 were unreachable, 14 were refused by `robots.txt`. On the claims that *did* have a
|
|
370
|
+
readable source the score is 0.361 — still below the baseline, and every one of the 19
|
|
371
|
+
`Supported` claims was missed. The retrieval and entailment models were calibrated on
|
|
372
|
+
scientific abstracts, and a fact-check page is a different object: long, discursive, and
|
|
373
|
+
usually quoting the claim it debunks. Nothing was tuned after that measurement, and no
|
|
374
|
+
blocked URL was dropped from it.
|
|
375
|
+
|
|
376
|
+
What proofpath is good at is the academic path the other rows measure: finding out whether a
|
|
377
|
+
cited paper exists, whether it was retracted, and whether its text says what the sentence
|
|
378
|
+
citing it claims. Pointed at a news claim on the open web, it is currently a coverage
|
|
379
|
+
report with a weak verdict attached.
|
|
293
380
|
|
|
294
381
|
Published SciFact results sit around 70–75 F1, not 95. Nothing is tuned on a test
|
|
295
382
|
split, and no number is quoted without the run that produced it.
|
|
@@ -26,7 +26,7 @@ proofpath
|
|
|
26
26
|
╸┤ o o ╰~~~~~~~~~~~~~[PROOF]
|
|
27
27
|
╰─┬─┬────────────────────────────────────────────────────────────────┬─┬──╯
|
|
28
28
|
˘ ˘ ˘ ˘
|
|
29
|
-
proofpath v0.
|
|
29
|
+
proofpath v0.4.0 academic . online . coreml
|
|
30
30
|
paste a file path, a URL, or a claim. /help /config /quit
|
|
31
31
|
```
|
|
32
32
|
|
|
@@ -59,7 +59,7 @@ either, for screenshots and bug reports.
|
|
|
59
59
|
```
|
|
60
60
|
,_,
|
|
61
61
|
(o.o)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[PROOF]
|
|
62
|
-
" " proofpath v0.
|
|
62
|
+
" " proofpath v0.4.0 academic . online . coreml
|
|
63
63
|
paste a file path, a URL, or a claim. /help /config /quit
|
|
64
64
|
```
|
|
65
65
|
|
|
@@ -146,6 +146,7 @@ distinct, printed state (spec §15), never collapsed into a verdict:
|
|
|
146
146
|
| `UNVERIFIED (reached, no text extracted)` | 200 answered, nothing readable came back |
|
|
147
147
|
| `UNVERIFIED (network not permitted)` | `permissions.network = deny` |
|
|
148
148
|
| `UNVERIFIED (provider unavailable)` | API down, rate limited after backoff, or answering with a page instead of a record |
|
|
149
|
+
| `UNVERIFIED (credentials missing)` | the platform reads only with a credential this machine has none of — Reddit's free app, `REDDIT_CLIENT_ID` and `REDDIT_CLIENT_SECRET`. Nobody was asked, so it is not "unreachable"; the coverage block names both variables |
|
|
149
150
|
| `UNVERIFIED (not in bibliographic indexes)` | web page, blog, report — indexes do not cover it, so absence proves nothing |
|
|
150
151
|
| `AMBIGUOUS` | several plausible records, all listed |
|
|
151
152
|
| `NEI` | the source was read and neither supports nor contradicts |
|
|
@@ -183,7 +184,12 @@ runtime teardown); fixed in v0.1 — 20 of 20 piped runs exit `1`
|
|
|
183
184
|
counted as unreachable.
|
|
184
185
|
- **Coverage is not perfectly reproducible**: two runs minutes apart can read a
|
|
185
186
|
different number of sources, depending on which providers answered.
|
|
186
|
-
- The
|
|
187
|
+
- **The judge is a second opinion, not a second verdict.** `--judge` asks the model only
|
|
188
|
+
about the low-tier verdicts (1 of 10 on the live draft), and its answer is printed
|
|
189
|
+
beside the local verdict, never in place of it. `--summarize` is one extra call over
|
|
190
|
+
the finished report, labelled model-written; if the provider does not answer, the
|
|
191
|
+
markdown report, the JSON and the terminal say so (`judge status` / `summary status`
|
|
192
|
+
in the header). The SARIF log does not carry it — it is a findings document.
|
|
187
193
|
|
|
188
194
|
## Speed
|
|
189
195
|
|
|
@@ -217,13 +223,79 @@ TablePlus or DBeaver — plain tables, no extension. Raw publisher text expires
|
|
|
217
223
|
7 days; verdicts keep the passage they quote; a provider outage is never stored.
|
|
218
224
|
`proofpath resolve REF` and `proofpath fetch URL|DOI` run either half on its own.
|
|
219
225
|
|
|
220
|
-
##
|
|
226
|
+
## Posts and the links inside them (v0.4)
|
|
221
227
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
228
|
+
A social post is not a source. What proofpath checks is whether the **links inside it**
|
|
229
|
+
back what it says:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
proofpath check --url https://bsky.app/profile/bsky.app/post/3movpwtbjgs2d
|
|
233
|
+
proofpath check --url https://news.ycombinator.com/item?id=8863
|
|
234
|
+
proofpath check - # paste the text of a post that cannot be read
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Every sentence of the post is checked against the pages its links point to, and the post's
|
|
238
|
+
own words are never allowed to stand as their own evidence.
|
|
239
|
+
|
|
240
|
+
| Platform | How it is read |
|
|
241
|
+
|---|---|
|
|
242
|
+
| Bluesky | `public.api.bsky.app`, no account, first-class. Link cards, rich-text links and one level of quoted post |
|
|
243
|
+
| Hacker News | the official Firebase API, no account, first-class. A story's URL and the links in a comment |
|
|
244
|
+
| Reddit | with a **free app you register yourself**: put `REDDIT_CLIENT_ID` and `REDDIT_CLIENT_SECRET` in `.env`. Without them the run says `UNVERIFIED (credentials missing)` and names both variables — it never quietly skips the post |
|
|
245
|
+
| Mastodon | best effort, per instance. Many instances now require a login for the public API, and that answer is reported as `UNVERIFIED (blocked)`, not as a missing post |
|
|
246
|
+
| X / Twitter | cannot be read at all. `check --url` says so and asks you to paste the text; the links inside it are then verified normally |
|
|
247
|
+
|
|
248
|
+
The Reddit path is built against Reddit's documented shapes and covered by fixtures, but it
|
|
249
|
+
has never run against Reddit on this machine — nobody here has an app to register. Bluesky,
|
|
250
|
+
Hacker News and Mastodon were each read live before release.
|
|
251
|
+
|
|
252
|
+
## Optional LLM judge (v0.3)
|
|
253
|
+
|
|
254
|
+
Everything above runs locally, and the default run makes **zero** LLM calls. Two flags
|
|
255
|
+
add an LLM at the end, and only there:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
proofpath check paper.pdf --judge # a second opinion on the low-confidence verdicts
|
|
259
|
+
proofpath check paper.pdf --summarize # one model-written paragraph over the finished report
|
|
260
|
+
proofpath config check # proves the key works before you spend a run on it
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**What `--judge` does.** After the local verdicts are final, the verdicts the models
|
|
264
|
+
were least sure about — the `low` tier, never a numeric mismatch and never a claim
|
|
265
|
+
without a quoted passage — go to the model in batches of up to 20 (about 7k tokens),
|
|
266
|
+
each with its claim and the passage it was checked against. The model answers from the
|
|
267
|
+
passage alone, and its label and one-sentence rationale are printed **beside** the local
|
|
268
|
+
verdict: `= judge (groq openai/gpt-oss-120b): NEI — …`. The local verdict, the finding
|
|
269
|
+
kind and the report's states never change. Opinions are cached with the verdict, so a
|
|
270
|
+
re-run asks nothing.
|
|
271
|
+
|
|
272
|
+
**What it cannot do.** It never sees a source document, so it cannot introduce a claim
|
|
273
|
+
or an evidence passage of its own; it cannot turn `NEI` into `SUPPORTED`; it cannot
|
|
274
|
+
hide a source that could not be read. If the provider is down, rate-limited or the key
|
|
275
|
+
is wrong, the run finishes on the local verdicts and says so in the stage line, the
|
|
276
|
+
report header (`judge status:`) and the JSON — `-q` cannot hide it.
|
|
277
|
+
|
|
278
|
+
**What `--summarize` does.** One final call turns the finished markdown report into 3–5
|
|
279
|
+
plain sentences a reader can act on. It runs after the report is complete, its only
|
|
280
|
+
input is that report, it is off by default in the CLI and the TUI (`/summarize` there),
|
|
281
|
+
and the output is labelled `(model-written, <provider> <model>)`. `--summarize` alone
|
|
282
|
+
is exactly one call; with `--judge` the escalation runs first.
|
|
283
|
+
|
|
284
|
+
**Cost.** The footer counts the calls and the stage line the tokens:
|
|
285
|
+
`Judging … 1 of 10 verdicts reviewed, 1 call, 613 prompt · 193 completion tokens` and
|
|
286
|
+
`Summarising … 98 words, 1 call, 1,608 prompt · 343 completion tokens`
|
|
287
|
+
on the live draft ([details](docs/eval/2026-09-15-judge-live.md)). Groq's free tier
|
|
288
|
+
allows roughly one call a minute. Only the low-tier verdicts are sent — 1 of 10 on that
|
|
289
|
+
draft — and up to 20 go in one call, so a long bibliography costs a handful of calls, not
|
|
290
|
+
one per citation.
|
|
291
|
+
|
|
292
|
+
**Providers.** Default is Groq `openai/gpt-oss-120b` (free without a card, no training
|
|
293
|
+
on submitted data). `proofpath config set judge.provider gemini` switches to Gemini —
|
|
294
|
+
note that Google trains on free-tier prompts outside the EEA/UK/CH, and proofpath prints
|
|
295
|
+
that warning once per run. `judge.provider ollama` runs fully offline. Gemini and Ollama are
|
|
296
|
+
fixture-tested and were not exercised live in v0.3.0. All three speak
|
|
297
|
+
the OpenAI `chat/completions` shape. The key comes from `GROQ_API_KEY` / `GEMINI_API_KEY`
|
|
298
|
+
in the environment or a `.env` file, never from config, and is never printed.
|
|
227
299
|
|
|
228
300
|
## Measured
|
|
229
301
|
|
|
@@ -234,6 +306,21 @@ comes from the environment or a `.env` file, never from config, and is never pri
|
|
|
234
306
|
| Source access | 50 DOIs | 72 % full text, 18 % abstract only, 10 % nothing ([details](docs/eval/2026-09-11-coverage.md)) — a real biomedical paper in the live runs reached 33 % full text |
|
|
235
307
|
| Citation pairing, numeric | 61 hand-built passages | 0.99 ([details](docs/eval/2026-09-11-pairing.md)) |
|
|
236
308
|
| Citation pairing, author-year | 55 hand-built passages, 83 expectations | 0.940 ([details](docs/eval/2026-09-12-pairing-author-year.md)) |
|
|
309
|
+
| **End to end on real web claims** | AVeriTeC dev, 100 claims | **0.270 3-way accuracy against a 0.708 majority baseline — worse than always guessing "refuted"** ([details](docs/eval/2026-09-16-averitec.md)) |
|
|
310
|
+
|
|
311
|
+
**The AVeriTeC row is the one to read before trusting this tool on a news claim.** A third
|
|
312
|
+
of those claims had no readable source at all: 32 of the source URLs needed the browser
|
|
313
|
+
step, 29 were unreachable, 14 were refused by `robots.txt`. On the claims that *did* have a
|
|
314
|
+
readable source the score is 0.361 — still below the baseline, and every one of the 19
|
|
315
|
+
`Supported` claims was missed. The retrieval and entailment models were calibrated on
|
|
316
|
+
scientific abstracts, and a fact-check page is a different object: long, discursive, and
|
|
317
|
+
usually quoting the claim it debunks. Nothing was tuned after that measurement, and no
|
|
318
|
+
blocked URL was dropped from it.
|
|
319
|
+
|
|
320
|
+
What proofpath is good at is the academic path the other rows measure: finding out whether a
|
|
321
|
+
cited paper exists, whether it was retracted, and whether its text says what the sentence
|
|
322
|
+
citing it claims. Pointed at a news claim on the open web, it is currently a coverage
|
|
323
|
+
report with a weak verdict attached.
|
|
237
324
|
|
|
238
325
|
Published SciFact results sit around 70–75 F1, not 95. Nothing is tuned on a test
|
|
239
326
|
split, and no number is quoted without the run that produced it.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Judge layer live runs — 2026-09-15 (v0.3.0)
|
|
2
|
+
|
|
3
|
+
`proofpath check tests/data/draft-live.md --judge --summarize` on Groq
|
|
4
|
+
(`openai/gpt-oss-120b`, key from `.env`), Apple Silicon, models already downloaded.
|
|
5
|
+
Three runs: the first against the pre-fix build (it found the defect), then a cold run
|
|
6
|
+
(`--no-cache`) and a warm run against the shipped build. Stage lines are copied from
|
|
7
|
+
the terminal; the key never appears in any output.
|
|
8
|
+
|
|
9
|
+
## Run 1 — pre-fix build: the summary came back empty
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Judging groq openai/gpt-oss-120b 1 of 10 verdicts reviewed, 1 call, 661 prompt · 211 completion tokens 0.9s
|
|
13
|
+
Summarising groq openai/gpt-oss-120b summary unavailable after 0 calls (no completion in the 200 response from https://api.groq.com/openai/v1/chat/completions (finish_reason=length)); local verdicts stand 1.0s
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`openai/gpt-oss-120b` is a reasoning model: with the planned `max_tokens=400` the
|
|
17
|
+
completion budget was spent on reasoning and the visible content was empty, and the
|
|
18
|
+
written `report.md` said nothing about the summary at all (the 9.3 reviewer had found
|
|
19
|
+
the same gap from the code). Both are fixed in the shipped build: requests carry
|
|
20
|
+
`reasoning_effort=low` (dropped on a 400 from providers that reject it), the review
|
|
21
|
+
budget is 4096 tokens and the summary budget 1500, and an unanswered summary is
|
|
22
|
+
reported on the stage line, the `summary` CLI line and a `- summary status:` header
|
|
23
|
+
line in the file. The 1,888-test suite was green before this run; the live run found it.
|
|
24
|
+
|
|
25
|
+
## Run 2 — cold (`--no-cache`), shipped build
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
Parsing text 1 pages, 7 refs 0.0s
|
|
29
|
+
Claims rules 7 citations, 0 unresolved 0.0s
|
|
30
|
+
Resolving Crossref, Semantic Scholar 6 ok, 0 amb, 1 ghost 9.3s
|
|
31
|
+
Retractions Retraction Watch none 2.5s
|
|
32
|
+
Fetching arXiv, Semantic Scholar 5 full text, 1 abstract, 0 unverified 23.8s
|
|
33
|
+
Verifying coreml 10 claims: 1 supported, 2 not supported, 7 NEI 44.5s
|
|
34
|
+
Judging groq openai/gpt-oss-120b 1 of 10 verdicts reviewed, 1 call, 613 prompt · 193 completion tokens 1.1s
|
|
35
|
+
Summarising groq openai/gpt-oss-120b 98 words, 1 call, 1,608 prompt · 343 completion tokens 1.0s
|
|
36
|
+
… written · 2 API calls · 82.1s
|
|
37
|
+
judge 2,221 prompt · 536 completion tokens
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The escalation set was one verdict — the `low`-tier `NOT SUPPORTED` on the SciPy
|
|
41
|
+
sentence — and the judge's opinion was printed beside it, the local verdict untouched:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
error[not-supported]: claim is not supported by the cited source (confidence: low)
|
|
45
|
+
= judge (groq openai/gpt-oss-120b): NEI — Passage states "SciPy provides fundamental
|
|
46
|
+
algorithms for scientific computing" but does not mention SciPy building on anything.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The numeric mismatch (`high`, rule-decided) and the ghost reference were not sent, as
|
|
50
|
+
specified. The summary, verbatim:
|
|
51
|
+
|
|
52
|
+
> The report checked seven cited references, and it found two claims not supported and
|
|
53
|
+
> one ghost reference; it does not give a total number of claims that were examined. The
|
|
54
|
+
> most serious problem is the high‑confidence "NOT SUPPORTED" error on line 6, where the
|
|
55
|
+
> claim about training time for the Transformer contradicts the source. The coverage
|
|
56
|
+
> analysis shows that only 72 % of the material was verified against full text, 14 % was
|
|
57
|
+
> limited to abstracts, and the remaining 14 % could not be read, so the counts above
|
|
58
|
+
> apply only to the portion that was actually examined.
|
|
59
|
+
|
|
60
|
+
It repeats the coverage caveat as instructed and invents no finding. Two things it
|
|
61
|
+
gets slightly wrong, which is why it is labelled model-written and sits under the
|
|
62
|
+
computed report: it calls the line-6 numeric mismatch a "NOT SUPPORTED" error (the
|
|
63
|
+
report says `numeric-mismatch: claim contradicts the cited source`), and "it does not
|
|
64
|
+
give a total number of claims" is true of the markdown file (the stage table is not
|
|
65
|
+
printed there) but not of the run (`10 claims`).
|
|
66
|
+
|
|
67
|
+
## Run 3 — warm, shipped build
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
Resolving cache 6 ok, 0 amb, 1 ghost 0.0s
|
|
71
|
+
Fetching cache 5 full text, 1 abstract, 0 unverified 0.0s
|
|
72
|
+
Verifying coreml 10 claims: 1 supported, 2 not supported, 7 NEI, 10 cached 0.8s
|
|
73
|
+
Judging groq openai/gpt-oss-120b 1 of 10 verdicts reviewed, 0 calls, 0 prompt · 0 completion tokens 0.0s
|
|
74
|
+
Summarising groq openai/gpt-oss-120b 106 words, 1 call, 1,615 prompt · 263 completion tokens 0.9s
|
|
75
|
+
… written · 1 API calls · 1.8s
|
|
76
|
+
judge 1,615 prompt · 263 completion tokens
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The judgement came back from the schema-v4 `judgements` table (0 calls); the summary
|
|
80
|
+
is always one fresh call. A plain `check` of the same file (no flags) reports
|
|
81
|
+
`api_calls: 0` and `summary: null`.
|
|
82
|
+
|
|
83
|
+
## What this does and does not show
|
|
84
|
+
|
|
85
|
+
- The judge layer works end to end on Groq's free tier: batching, strict-JSON output,
|
|
86
|
+
cost accounting, caching, attribution, and the report unchanged by the model.
|
|
87
|
+
- One document, one low-tier verdict, one provider. Nothing here measures the judge's
|
|
88
|
+
accuracy; the escalation band is narrow by design (OPEN-ITEMS 14.1), so a paper with
|
|
89
|
+
118 citations would send a handful of verdicts, not dozens.
|
|
90
|
+
- Gemini and Ollama were not exercised live; they share the adapter and are covered by
|
|
91
|
+
the `respx` tests only.
|
|
92
|
+
- These runs were made with the batch cap at 7,000 prompt tokens. The whole-phase review
|
|
93
|
+
lowered it to 3,500 so that a full batch plus its 4,096-token answer budget stays under
|
|
94
|
+
Groq's 8K-per-minute tier; with one escalated item the runs above never approached
|
|
95
|
+
either figure, so nothing here measures the cap.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# AVeriTeC dev — 2026-09-16
|
|
2
|
+
|
|
3
|
+
- claims: 100 (limit=100)
|
|
4
|
+
- dataset: `https://raw.githubusercontent.com/MichSchli/AVeriTeC/main/data/dev.json` (sha256 499793726b4a…)
|
|
5
|
+
- one run of the whole product: real claims, real source pages, real fetch ladder.
|
|
6
|
+
|
|
7
|
+
## Headline
|
|
8
|
+
|
|
9
|
+
3-way accuracy **0.270** vs majority baseline 0.708, over 89 of 100 claims.
|
|
10
|
+
|
|
11
|
+
The 3-way number excludes the Conflicting Evidence/Cherrypicking rows, which proofpath has no verdict for; counting them as wrong gives a 4-way accuracy of 0.240.
|
|
12
|
+
|
|
13
|
+
## Per label
|
|
14
|
+
|
|
15
|
+
| label | n | correct | accuracy |
|
|
16
|
+
|---|---|---|---|
|
|
17
|
+
| Supported | 19 | 0 | 0.000 |
|
|
18
|
+
| Refuted | 63 | 20 | 0.317 |
|
|
19
|
+
| Not Enough Evidence | 7 | 4 | 0.571 |
|
|
20
|
+
| Conflicting Evidence/Cherrypicking | 11 | 0 | 0.000 |
|
|
21
|
+
|
|
22
|
+
## Source coverage
|
|
23
|
+
|
|
24
|
+
| state | count |
|
|
25
|
+
|---|---|
|
|
26
|
+
| ok | 120 |
|
|
27
|
+
| UNVERIFIED (blocked, browser not permitted) | 32 |
|
|
28
|
+
| UNVERIFIED (unreachable) | 29 |
|
|
29
|
+
| UNVERIFIED (blocked, robots.txt) | 14 |
|
|
30
|
+
| not a url | 9 |
|
|
31
|
+
| UNVERIFIED (reached, no text extracted) | 3 |
|
|
32
|
+
| UNVERIFIED (provider unavailable) | 2 |
|
|
33
|
+
|
|
34
|
+
76 of 200 source URLs are web.archive.org snapshots (38.0 %).
|
|
35
|
+
|
|
36
|
+
## What the numbers say
|
|
37
|
+
|
|
38
|
+
**proofpath is worse than always guessing "Refuted" on this set.** The majority baseline is
|
|
39
|
+
0.708 because 63 of the 89 answerable dev claims are refutations; proofpath scores 0.270.
|
|
40
|
+
That is the headline and it is not softened anywhere else in this repository.
|
|
41
|
+
|
|
42
|
+
Where the loss comes from, from the per-claim rows:
|
|
43
|
+
|
|
44
|
+
| | count |
|
|
45
|
+
|---|---|
|
|
46
|
+
| claims where **no** source could be read | 33 of 100 |
|
|
47
|
+
| claims with at least one readable source | 67 |
|
|
48
|
+
| 3-way accuracy on those 67 (61 answerable) | **0.361** |
|
|
49
|
+
| claims answered `NEI` | 31 |
|
|
50
|
+
| claims answered nothing at all (no source read) | 33 |
|
|
51
|
+
| claims answered `SUPPORTED` | 7 |
|
|
52
|
+
| claims answered `REFUTED` | 29 |
|
|
53
|
+
|
|
54
|
+
Two separate problems, and the coverage one is the larger:
|
|
55
|
+
|
|
56
|
+
1. **A third of the claims had nothing to read.** 32 source URLs needed the browser step
|
|
57
|
+
(this run passed `--no-browser`), 29 were unreachable, 14 were refused by `robots.txt`.
|
|
58
|
+
AVeriTeC's evidence is news sites, fact-check pages and archived snapshots — the exact
|
|
59
|
+
corner of the web that a polite, browserless fetcher is worst at. A claim with no
|
|
60
|
+
readable source is reported as such and counts as `NEI`, which is honest and still wrong
|
|
61
|
+
against the gold label 26 of the 28 times such a claim was scorable at all. Counting every
|
|
62
|
+
claim the run answered `NEI` — the 31 it decided and the 33 it could not read — 56 are
|
|
63
|
+
scorable and 52 of those are wrong.
|
|
64
|
+
2. **Even with a source in hand, entailment over a news page is much harder than over an
|
|
65
|
+
abstract.** On the claims that did have a readable source the score is 0.361, still below
|
|
66
|
+
the baseline. Every one of the 19 `Supported` claims was missed: seven came back `NEI`,
|
|
67
|
+
seven had nothing to read, five were called `REFUTED`. The retrieval and NLI models were
|
|
68
|
+
calibrated on SciFact — scientific abstracts, one claim per abstract — and a fact-check
|
|
69
|
+
page is a different object: long, discursive, and often quoting the claim it debunks.
|
|
70
|
+
|
|
71
|
+
The `Refuted` column is the only one that works (20 of 63), and some of that is the prior
|
|
72
|
+
doing the work rather than the evidence.
|
|
73
|
+
|
|
74
|
+
## What this does not say
|
|
75
|
+
|
|
76
|
+
- It is not a statement about proofpath's academic path. SciFact dev (abstracts, 340 pairs)
|
|
77
|
+
scores 0.609 with a 0.406 baseline; the ghost set scores 0.0 % false ghosts. Those measure
|
|
78
|
+
different things and are measured separately.
|
|
79
|
+
- It is not tuned away. No threshold was moved after seeing this, no URL was dropped for
|
|
80
|
+
being blocked, and the coverage table above prints every state rather than the ones that
|
|
81
|
+
flatter the run.
|
|
82
|
+
- 38 % of the source URLs are `web.archive.org` snapshots, so a good part of what was read
|
|
83
|
+
is an archived copy of the page the dataset's annotators saw, not today's page.
|
|
84
|
+
|
|
85
|
+
## How it was run
|
|
86
|
+
|
|
87
|
+
`uv run python scripts/eval_averitec.py --limit 100 --no-browser --sleep 1.0 --resume`
|
|
88
|
+
on the v0.4.0 development build, 2026-09-16, Apple Silicon, cache warm from nothing.
|
|
89
|
+
Per-claim rows are in `~/Library/Caches/proofpath/datasets/averitec_results.json`; the run
|
|
90
|
+
is resumable, so the same command reproduces it without re-fetching. The dataset is pinned
|
|
91
|
+
by sha256 and the loader refuses a mismatch.
|
|
92
|
+
|
|
93
|
+
Allowing the browser step would raise coverage and probably the score; it was left off so
|
|
94
|
+
the number describes the default install, which is what a reader gets.
|
|
95
|
+
|