proofpath 0.2.0__tar.gz → 0.3.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.
Files changed (180) hide show
  1. {proofpath-0.2.0 → proofpath-0.3.0}/CHANGELOG.md +87 -0
  2. {proofpath-0.2.0 → proofpath-0.3.0}/PKG-INFO +90 -18
  3. {proofpath-0.2.0 → proofpath-0.3.0}/README.md +89 -17
  4. proofpath-0.3.0/docs/eval/2026-09-15-judge-live.md +95 -0
  5. proofpath-0.3.0/docs/eval/2026-09-15-tui-v2-live.md +267 -0
  6. proofpath-0.3.0/docs/eval/tui-v2-plain.svg +279 -0
  7. proofpath-0.3.0/docs/eval/tui-v2-rich.svg +280 -0
  8. {proofpath-0.2.0 → proofpath-0.3.0}/docs/superpowers/OPEN-ITEMS.md +71 -7
  9. {proofpath-0.2.0 → proofpath-0.3.0}/docs/superpowers/plans/2026-09-10-proofpath-implementation-plan.md +13 -0
  10. {proofpath-0.2.0 → proofpath-0.3.0}/docs/superpowers/specs/2026-09-10-proofpath-design.md +41 -4
  11. proofpath-0.3.0/docs/superpowers/specs/2026-09-15-tui-v2-design.md +142 -0
  12. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/__init__.py +1 -1
  13. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/cache.py +91 -4
  14. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/cli.py +60 -6
  15. proofpath-0.3.0/src/proofpath/judge.py +827 -0
  16. proofpath-0.3.0/src/proofpath/prompts/__init__.py +1 -0
  17. proofpath-0.3.0/src/proofpath/prompts/review.md +40 -0
  18. proofpath-0.3.0/src/proofpath/prompts/summarize.md +30 -0
  19. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/report.py +190 -6
  20. proofpath-0.3.0/src/proofpath/tui/app.py +782 -0
  21. proofpath-0.3.0/src/proofpath/tui/pet.py +309 -0
  22. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/tui/runs.py +13 -0
  23. proofpath-0.3.0/src/proofpath/tui/theme.py +259 -0
  24. proofpath-0.3.0/src/proofpath/tui/verbs.py +328 -0
  25. proofpath-0.3.0/src/proofpath/tui/widgets/__init__.py +47 -0
  26. proofpath-0.3.0/src/proofpath/tui/widgets/_shared.py +96 -0
  27. proofpath-0.3.0/src/proofpath/tui/widgets/banner.py +194 -0
  28. proofpath-0.3.0/src/proofpath/tui/widgets/finding.py +341 -0
  29. proofpath-0.3.0/src/proofpath/tui/widgets/footer.py +162 -0
  30. proofpath-0.3.0/src/proofpath/tui/widgets/prompt.py +109 -0
  31. proofpath-0.3.0/src/proofpath/tui/widgets/run_block.py +578 -0
  32. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/ui.py +48 -6
  33. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/verify.py +294 -3
  34. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_cache.py +148 -5
  35. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_check_cli.py +400 -8
  36. proofpath-0.3.0/tests/test_judge.py +959 -0
  37. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_report.py +228 -1
  38. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_sarif.py +30 -2
  39. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_tui_app.py +136 -10
  40. proofpath-0.3.0/tests/test_tui_pet.py +483 -0
  41. proofpath-0.3.0/tests/test_tui_rich.py +679 -0
  42. proofpath-0.3.0/tests/test_tui_theme.py +319 -0
  43. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_ui.py +60 -0
  44. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_verify.py +563 -3
  45. proofpath-0.2.0/src/proofpath/judge.py +0 -149
  46. proofpath-0.2.0/src/proofpath/tui/app.py +0 -1813
  47. proofpath-0.2.0/tests/test_judge.py +0 -106
  48. {proofpath-0.2.0 → proofpath-0.3.0}/.editorconfig +0 -0
  49. {proofpath-0.2.0 → proofpath-0.3.0}/.env.example +0 -0
  50. {proofpath-0.2.0 → proofpath-0.3.0}/.gitattributes +0 -0
  51. {proofpath-0.2.0 → proofpath-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  52. {proofpath-0.2.0 → proofpath-0.3.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  53. {proofpath-0.2.0 → proofpath-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  54. {proofpath-0.2.0 → proofpath-0.3.0}/.github/ISSUE_TEMPLATE/wrong_verdict.yml +0 -0
  55. {proofpath-0.2.0 → proofpath-0.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  56. {proofpath-0.2.0 → proofpath-0.3.0}/.github/workflows/ci.yml +0 -0
  57. {proofpath-0.2.0 → proofpath-0.3.0}/.github/workflows/release.yml +0 -0
  58. {proofpath-0.2.0 → proofpath-0.3.0}/.gitignore +0 -0
  59. {proofpath-0.2.0 → proofpath-0.3.0}/CLAUDE.md +0 -0
  60. {proofpath-0.2.0 → proofpath-0.3.0}/CONTRIBUTING.md +0 -0
  61. {proofpath-0.2.0 → proofpath-0.3.0}/LICENSE +0 -0
  62. {proofpath-0.2.0 → proofpath-0.3.0}/SECURITY.md +0 -0
  63. {proofpath-0.2.0 → proofpath-0.3.0}/docs/eval/2026-09-11-coverage.md +0 -0
  64. {proofpath-0.2.0 → proofpath-0.3.0}/docs/eval/2026-09-11-ghosts.md +0 -0
  65. {proofpath-0.2.0 → proofpath-0.3.0}/docs/eval/2026-09-11-pairing.md +0 -0
  66. {proofpath-0.2.0 → proofpath-0.3.0}/docs/eval/2026-09-11-scifact-dev.md +0 -0
  67. {proofpath-0.2.0 → proofpath-0.3.0}/docs/eval/2026-09-12-ghosts.md +0 -0
  68. {proofpath-0.2.0 → proofpath-0.3.0}/docs/eval/2026-09-12-pairing-author-year.md +0 -0
  69. {proofpath-0.2.0 → proofpath-0.3.0}/docs/eval/2026-09-12-scifact-dev.md +0 -0
  70. {proofpath-0.2.0 → proofpath-0.3.0}/docs/eval/2026-09-12-tiers.md +0 -0
  71. {proofpath-0.2.0 → proofpath-0.3.0}/docs/eval/2026-09-12-v0.1-live.md +0 -0
  72. {proofpath-0.2.0 → proofpath-0.3.0}/docs/eval/2026-09-15-v0.2-live.md +0 -0
  73. {proofpath-0.2.0 → proofpath-0.3.0}/docs/research/2026-09-11-free-llm-api-tiers.md +0 -0
  74. {proofpath-0.2.0 → proofpath-0.3.0}/docs/superpowers/plans/2026-09-12-phases-9-10-plan.md +0 -0
  75. {proofpath-0.2.0 → proofpath-0.3.0}/pyproject.toml +0 -0
  76. {proofpath-0.2.0 → proofpath-0.3.0}/scripts/eval_coverage.py +0 -0
  77. {proofpath-0.2.0 → proofpath-0.3.0}/scripts/eval_ghosts.py +0 -0
  78. {proofpath-0.2.0 → proofpath-0.3.0}/scripts/eval_pairing.py +0 -0
  79. {proofpath-0.2.0 → proofpath-0.3.0}/scripts/eval_scifact.py +0 -0
  80. {proofpath-0.2.0 → proofpath-0.3.0}/scripts/zero_network_check.py +0 -0
  81. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/browser.py +0 -0
  82. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/claims.py +0 -0
  83. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/commands.py +0 -0
  84. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/config.py +0 -0
  85. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/device.py +0 -0
  86. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/document.py +0 -0
  87. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/entailment.py +0 -0
  88. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/eval/__init__.py +0 -0
  89. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/eval/metrics.py +0 -0
  90. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/eval/scifact.py +0 -0
  91. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/events.py +0 -0
  92. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/fetch.py +0 -0
  93. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/ingest.py +0 -0
  94. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/models.py +0 -0
  95. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/numerics.py +0 -0
  96. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/oa.py +0 -0
  97. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/paths.py +0 -0
  98. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/pipeline.py +0 -0
  99. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/polite.py +0 -0
  100. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/py.typed +0 -0
  101. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/resolve.py +0 -0
  102. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/retrieval.py +0 -0
  103. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/sarif.py +0 -0
  104. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/tui/__init__.py +0 -0
  105. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/tui/banner.py +0 -0
  106. {proofpath-0.2.0 → proofpath-0.3.0}/src/proofpath/tui/commands.py +0 -0
  107. {proofpath-0.2.0 → proofpath-0.3.0}/tests/__init__.py +0 -0
  108. {proofpath-0.2.0 → proofpath-0.3.0}/tests/conftest.py +0 -0
  109. {proofpath-0.2.0 → proofpath-0.3.0}/tests/data/draft-author-year.md +0 -0
  110. {proofpath-0.2.0 → proofpath-0.3.0}/tests/data/draft-live.md +0 -0
  111. {proofpath-0.2.0 → proofpath-0.3.0}/tests/data/ghost_set.jsonl +0 -0
  112. {proofpath-0.2.0 → proofpath-0.3.0}/tests/data/pairing_author_year.jsonl +0 -0
  113. {proofpath-0.2.0 → proofpath-0.3.0}/tests/data/pairing_set.jsonl +0 -0
  114. {proofpath-0.2.0 → proofpath-0.3.0}/tests/data/sarif-schema-2.1.0.json +0 -0
  115. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fakes.py +0 -0
  116. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/crossref_work.json +0 -0
  117. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/crossref_work_no_abstract.json +0 -0
  118. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/europepmc_fulltext.xml +0 -0
  119. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/europepmc_search.json +0 -0
  120. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/europepmc_search_empty.json +0 -0
  121. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/europepmc_search_not_in_epmc.json +0 -0
  122. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/openalex_work.json +0 -0
  123. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/s2_paper.json +0 -0
  124. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/s2_paper_no_abstract.json +0 -0
  125. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/unpaywall.json +0 -0
  126. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/unpaywall_closed.json +0 -0
  127. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/oa/unpaywall_landing_only.json +0 -0
  128. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/arxiv_id_roberta.xml +0 -0
  129. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/arxiv_title_fabricated.xml +0 -0
  130. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/arxiv_title_roberta.xml +0 -0
  131. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/crossref_alphafold.json +0 -0
  132. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/crossref_fabricated.json +0 -0
  133. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/crossref_numpy.json +0 -0
  134. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/crossref_rag.json +0 -0
  135. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/crossref_retracted_wakefield.json +0 -0
  136. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/crossref_roberta.json +0 -0
  137. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/crossref_work_alphafold.json +0 -0
  138. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/crossref_work_numpy.json +0 -0
  139. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/openalex_alphafold.json +0 -0
  140. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/openalex_fabricated.json +0 -0
  141. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/openalex_rag.json +0 -0
  142. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/openalex_retracted_wakefield.json +0 -0
  143. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/openalex_roberta.json +0 -0
  144. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/openlibrary_fabricated.json +0 -0
  145. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/openlibrary_using_language.json +0 -0
  146. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/s2_alphafold.json +0 -0
  147. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/s2_fabricated.json +0 -0
  148. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/s2_rag.json +0 -0
  149. {proofpath-0.2.0 → proofpath-0.3.0}/tests/fixtures/resolve/s2_roberta.json +0 -0
  150. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_browser.py +0 -0
  151. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_cache_cli.py +0 -0
  152. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_claims.py +0 -0
  153. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_cli.py +0 -0
  154. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_commands.py +0 -0
  155. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_config.py +0 -0
  156. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_config_cli.py +0 -0
  157. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_device.py +0 -0
  158. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_document.py +0 -0
  159. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_entailment.py +0 -0
  160. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_eval_coverage.py +0 -0
  161. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_eval_pairing.py +0 -0
  162. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_eval_scifact.py +0 -0
  163. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_fetch.py +0 -0
  164. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_fetch_cli.py +0 -0
  165. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_ingest.py +0 -0
  166. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_metrics.py +0 -0
  167. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_models.py +0 -0
  168. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_numerics.py +0 -0
  169. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_oa.py +0 -0
  170. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_pipeline.py +0 -0
  171. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_polite.py +0 -0
  172. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_resolve.py +0 -0
  173. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_resolve_cli.py +0 -0
  174. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_retrieval.py +0 -0
  175. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_scifact.py +0 -0
  176. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_tui_banner.py +0 -0
  177. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_tui_commands.py +0 -0
  178. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_tui_runs.py +0 -0
  179. {proofpath-0.2.0 → proofpath-0.3.0}/tests/test_version.py +0 -0
  180. {proofpath-0.2.0 → proofpath-0.3.0}/uv.lock +0 -0
@@ -6,6 +6,93 @@ All notable changes to this project are documented here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.0] - 2026-09-15
10
+
11
+ The judge layer: an opt-in LLM second opinion and an opt-in model-written summary.
12
+ The default run still makes zero LLM calls, and nothing the model says can change a
13
+ verdict. Live run on Groq in `docs/eval/2026-09-15-judge-live.md`.
14
+
15
+ ### Added
16
+ - **`check --judge`** (`judge.py`, `verify.py`). After the local verdicts are final, the
17
+ `low`-tier ones — never a numeric mismatch, never a claim without a quoted passage —
18
+ go to the model in batches of up to 20 items (about 7k tokens), each with its claim and
19
+ passage. The opinion (`SUPPORTED | REFUTED | NEI` plus a one-sentence rationale) is
20
+ attached beside the verdict: a `= judge (groq openai/gpt-oss-120b): …` line under a
21
+ finding it disagrees with, a `judge` column in the markdown `## Checked` table, and
22
+ `judge` fields in the JSON. The local `Verdict`, the finding kind and every state are
23
+ untouched (spec §11.1). Opinions are cached in the new `judgements` table (schema v4,
24
+ additive; wiped with the verdicts when a source's text changes), so a re-run asks
25
+ nothing, and `model_id` is untouched, so toggling `--judge` never invalidates a verdict.
26
+ - **`check --summarize`** and the TUI's **`/summarize`**: one extra call over the finished
27
+ markdown report, run after the report is final, off by default in both front-ends,
28
+ printed as `summary (model-written, groq openai/gpt-oss-120b) …` and as
29
+ `## Summary (model-written, …)` in the file. `--summarize` alone is exactly one call.
30
+ - **`JudgeClient`**: one adapter for Groq (default `openai/gpt-oss-120b`), Gemini and
31
+ Ollama over the OpenAI `chat/completions` shape; strict JSON-schema output with a
32
+ `json_object` fallback, `reasoning_effort=low` with a fallback for providers that
33
+ reject it, `Retry-After` on 429 (capped, accounted), exponential backoff on 5xx, then
34
+ `JudgeUnavailable`. The key comes from the environment or `.env`, never from config,
35
+ never appears in `repr`, errors or logs; provider bodies are never echoed. Prompts are
36
+ packaged template files (`proofpath/prompts/review.md`, `summarize.md`).
37
+ - **Cost on every surface**: the `Judging` and `Summarising` stage lines carry calls and
38
+ prompt/completion tokens; the footer counts the calls; `Report.judge_cost` and
39
+ `models["judge"]` land in the JSON.
40
+ - **An unanswered judge is reported, not hidden**: `judge unavailable after N calls
41
+ (HTTP 401 from …); local verdicts stand` in the stage line, the report header
42
+ (`judge status:` / `summary status:`), the JSON and an unsuppressed terminal line — a
43
+ `-q` or piped run cannot look like a judged-clean one. The SARIF log does not carry it.
44
+ The run never fails because of the judge.
45
+ - Gemini prints its data-use warning once per run (spec §11).
46
+
47
+ ### Changed
48
+ - `check --judge` / `--summarize` no longer exit with `arrives in v0.3`.
49
+ - Cache schema **v4** (`judgements`); a v1 file still migrates through the whole chain.
50
+ - The markdown `## Checked` table always carries a `judge` column; without `--judge` every
51
+ cell is `—`, so a v0.2 report and a v0.3 one differ by that column alone.
52
+ - `--format json` gained `summary`, `summary_model`, `judge_cost` and per-result `judge`
53
+ fields; every one of them is `null` on a default run.
54
+
55
+ ## [0.2.1] - 2026-09-15
56
+
57
+ The TUI's second look. No behaviour change: every state word, every honesty sentence,
58
+ the exit codes, the scheduler and the one-shot CLI are exactly v0.2.0's. Design in
59
+ `docs/superpowers/specs/2026-09-15-tui-v2-design.md`; the by-hand session in both
60
+ themes, with SVG screenshots, in `docs/eval/2026-09-15-tui-v2-live.md`.
61
+
62
+ ### Changed
63
+ - **Two themes, one truth** (`tui/theme.py`). `rich` draws box borders, Unicode glyphs
64
+ and truecolor tones when the terminal gives evidence of them (`COLORTERM`, Windows
65
+ Terminal, iTerm2, kitty, WezTerm, Ghostty, VS Code, Terminal.app); `plain` is a pure-ASCII, ANSI-16 look
66
+ (v0.2.0's `⏺ ✗ ⚠ › ⧉` become `* x ! > [copy]`, and findings now print their `= note:`
67
+ lines as the CLI does), chosen under `NO_COLOR`, `--no-color`, `-q`,
68
+ `TERM=dumb`, legacy conhost, a CJK locale, or any session without truecolor evidence (an SSH
69
+ or tmux session that strips `COLORTERM` gets `plain`). `PROOFPATH_THEME=rich|plain` overrides
70
+ detection. The meaning colours stay `ui.py`'s tables; a theme changes how a meaning
71
+ looks, never what a word means. Spec §13.1's "pure ASCII" rule for the pet now binds
72
+ `plain` only.
73
+ - **The pet** (`tui/pet.py`): `rich` draws a seven-line ferret with a real tail running
74
+ to the `[PROOF]` stamp; `plain` keeps the three-line one unchanged. Same eyes, same
75
+ blink, same reactions; the tail wags in `rich` while a run works.
76
+ - **Run panels** (`tui/widgets/run_block.py`): in `rich` each run is a rounded panel in
77
+ its accent, the command and the state word on the top border, the coverage on the
78
+ bottom one; the stages are a fixed-column table (symbol, name, summary with `·`
79
+ separators, attribution, elapsed) and the active stage carries a real `▰▱` progress
80
+ bar with `done/total`. A finished stage that left something unverified keeps the
81
+ `⏺` mark instead of a tick. Below 60 columns the borders go and the flat rows
82
+ return; a run that crossed the floor either way says its coverage exactly once.
83
+ - **Findings** (`tui/widgets/finding.py`): the state word is a badge, the location a
84
+ fixed cell, the tier right-aligned; the finding's notes and the claim (`you`) and
85
+ the passage (`source`) it was checked against are printed under it. A tier-less
86
+ badge keeps its row at 60–79 columns. `plain` prints the notes as the CLI's own
87
+ `= note:` rows and keeps `[copy]`.
88
+ - **Footer** (`tui/widgets/footer.py`): `rich` draws the coverage as a proportional
89
+ `█▓░` bar in the three meaning colours over the counts line; `plain` keeps the
90
+ `kv` lines. The prompt wears a one-line rounded border in the run's accent.
91
+ - **Structure** (OPEN-ITEMS 12.4): `tui/app.py` is split — `theme.py`, `pet.py`,
92
+ `verbs.py` and `tui/widgets/` (`run_block`, `finding`, `footer`, `prompt`,
93
+ `banner`, `_shared`) — and is now 681 lines of composition, scheduler wiring and
94
+ slash commands, no rendering.
95
+
9
96
  ## [0.2.0] - 2026-09-15
10
97
 
11
98
  The interactive front-end, author-year citations, SARIF output and a cache for the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: proofpath
3
- Version: 0.2.0
3
+ Version: 0.3.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
@@ -77,20 +77,47 @@ proofpath
77
77
  ```
78
78
 
79
79
  ```
80
- ,_,
81
- (o.o)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[PROOF]
82
- " " proofpath v0.2.0 academic . online . coreml
83
- paste a file path, a URL, or a claim. /help /config /quit
80
+ ╭╮ ╭╮
81
+ ╭╯╰─╯╰────────────────────────────────────────────────────────────────────╮
82
+ ╸┤ o o ╰~~~~~~~~~~~~~[PROOF]
83
+ ╰─┬─┬────────────────────────────────────────────────────────────────┬─┬──╯
84
+ ˘ ˘ ˘ ˘
85
+ proofpath v0.2.1 academic . online . coreml
86
+ paste a file path, a URL, or a claim. /help /config /quit
84
87
  ```
85
88
 
86
- Bare `proofpath` opens the terminal UI ([a recorded session](docs/eval/2026-09-15-v0.2-live.md)).
89
+ Bare `proofpath` opens the terminal UI ([a recorded session in both themes](docs/eval/2026-09-15-tui-v2-live.md),
90
+ with [SVG screenshots](docs/eval/tui-v2-rich.svg)). Each run is one panel in its own
91
+ accent: the command on the top border and the run's state at its right, a fixed-column
92
+ stage table underneath (`✓` finished, `⏺` still running or finished with something
93
+ unverified, a real progress bar on the active stage, the provider that produced each
94
+ number at the right), a rule, then the findings — location, reference, the state word
95
+ as a badge, the tier — with the finding's notes and the claim (`you`) and the passage
96
+ (`source`) it was checked against under it. The bottom border carries the run's
97
+ coverage; the docked footer draws it as a bar and never scrolls away.
98
+
87
99
  Paste a path and it runs; every one-shot verb is a slash command (`/check`, `/resolve`,
88
100
  `/fetch`, `/config`, `/cache`), runs can be started while others are in flight and
89
- stopped with `/cancel #n` — a stopped run keeps what it had decided and the
90
- coverage footer never scrolls away. Click (or press `enter` on) a finding to read the
91
- whole quoted passage; `⧉` copies it; a finding's reference is a link to its source.
92
- When a publisher blocks the plain fetch, the permission question is asked **inline,
93
- under the stage that hit the wall**, with `[allow once] [always] [no] [never]`.
101
+ stopped with `/cancel #n` — a stopped run keeps what it had decided. Click (or press
102
+ `enter` on) a finding to read the whole quoted passage; `⧉` copies it; a finding's
103
+ reference is a link to its source. When a publisher blocks the plain fetch, the
104
+ permission question is asked **inline, under the stage that hit the wall**, with
105
+ `[allow once] [always] [no] [never]`.
106
+
107
+ **Windows / `NO_COLOR`.** The look above is the `rich` theme, chosen when the terminal
108
+ gives evidence of truecolor (`COLORTERM`, Windows Terminal, iTerm2, kitty, WezTerm,
109
+ Ghostty, VS Code, Terminal.app). Under `NO_COLOR`, `--no-color`, `-q`, `TERM=dumb`,
110
+ legacy conhost or a CJK locale the `plain` theme draws the same runs as flat ASCII rows
111
+ in the terminal's own 16 colours — the state words, the coverage and every honesty
112
+ sentence are identical, only the drawing changes. `PROOFPATH_THEME=rich|plain` forces
113
+ either, for screenshots and bug reports.
114
+
115
+ ```
116
+ ,_,
117
+ (o.o)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[PROOF]
118
+ " " proofpath v0.2.1 academic . online . coreml
119
+ paste a file path, a URL, or a claim. /help /config /quit
120
+ ```
94
121
 
95
122
  The same engine behind a pipe or in CI:
96
123
 
@@ -212,7 +239,12 @@ runtime teardown); fixed in v0.1 — 20 of 20 piped runs exit `1`
212
239
  counted as unreachable.
213
240
  - **Coverage is not perfectly reproducible**: two runs minutes apart can read a
214
241
  different number of sources, depending on which providers answered.
215
- - The LLM judge and `--summarize` arrive in **v0.3**.
242
+ - **The judge is a second opinion, not a second verdict.** `--judge` asks the model only
243
+ about the low-tier verdicts (1 of 10 on the live draft), and its answer is printed
244
+ beside the local verdict, never in place of it. `--summarize` is one extra call over
245
+ the finished report, labelled model-written; if the provider does not answer, the
246
+ markdown report, the JSON and the terminal say so (`judge status` / `summary status`
247
+ in the header). The SARIF log does not carry it — it is a findings document.
216
248
 
217
249
  ## Speed
218
250
 
@@ -246,13 +278,53 @@ TablePlus or DBeaver — plain tables, no extension. Raw publisher text expires
246
278
  7 days; verdicts keep the passage they quote; a provider outage is never stored.
247
279
  `proofpath resolve REF` and `proofpath fetch URL|DOI` run either half on its own.
248
280
 
249
- ## Optional LLM judge — arrives in v0.3
281
+ ## Optional LLM judge (v0.3)
282
+
283
+ Everything above runs locally, and the default run makes **zero** LLM calls. Two flags
284
+ add an LLM at the end, and only there:
285
+
286
+ ```bash
287
+ proofpath check paper.pdf --judge # a second opinion on the low-confidence verdicts
288
+ proofpath check paper.pdf --summarize # one model-written paragraph over the finished report
289
+ proofpath config check # proves the key works before you spend a run on it
290
+ ```
250
291
 
251
- Everything above runs locally. An LLM is used only at the end, as an opt-in second
252
- opinion on low-confidence verdictsit never sees a source document and cannot
253
- change a verdict. The settings exist today (`proofpath config check` proves a key
254
- works, default Groq); `check --judge` and `--summarize` are wired in v0.3. The key
255
- comes from the environment or a `.env` file, never from config, and is never printed.
292
+ **What `--judge` does.** After the local verdicts are final, the verdicts the models
293
+ were least sure aboutthe `low` tier, never a numeric mismatch and never a claim
294
+ without a quoted passage go to the model in batches of up to 20 (about 7k tokens),
295
+ each with its claim and the passage it was checked against. The model answers from the
296
+ passage alone, and its label and one-sentence rationale are printed **beside** the local
297
+ verdict: `= judge (groq openai/gpt-oss-120b): NEI — …`. The local verdict, the finding
298
+ kind and the report's states never change. Opinions are cached with the verdict, so a
299
+ re-run asks nothing.
300
+
301
+ **What it cannot do.** It never sees a source document, so it cannot introduce a claim
302
+ or an evidence passage of its own; it cannot turn `NEI` into `SUPPORTED`; it cannot
303
+ hide a source that could not be read. If the provider is down, rate-limited or the key
304
+ is wrong, the run finishes on the local verdicts and says so in the stage line, the
305
+ report header (`judge status:`) and the JSON — `-q` cannot hide it.
306
+
307
+ **What `--summarize` does.** One final call turns the finished markdown report into 3–5
308
+ plain sentences a reader can act on. It runs after the report is complete, its only
309
+ input is that report, it is off by default in the CLI and the TUI (`/summarize` there),
310
+ and the output is labelled `(model-written, <provider> <model>)`. `--summarize` alone
311
+ is exactly one call; with `--judge` the escalation runs first.
312
+
313
+ **Cost.** The footer counts the calls and the stage line the tokens:
314
+ `Judging … 1 of 10 verdicts reviewed, 1 call, 613 prompt · 193 completion tokens` and
315
+ `Summarising … 98 words, 1 call, 1,608 prompt · 343 completion tokens`
316
+ on the live draft ([details](docs/eval/2026-09-15-judge-live.md)). Groq's free tier
317
+ allows roughly one call a minute. Only the low-tier verdicts are sent — 1 of 10 on that
318
+ draft — and up to 20 go in one call, so a long bibliography costs a handful of calls, not
319
+ one per citation.
320
+
321
+ **Providers.** Default is Groq `openai/gpt-oss-120b` (free without a card, no training
322
+ on submitted data). `proofpath config set judge.provider gemini` switches to Gemini —
323
+ note that Google trains on free-tier prompts outside the EEA/UK/CH, and proofpath prints
324
+ that warning once per run. `judge.provider ollama` runs fully offline. Gemini and Ollama are
325
+ fixture-tested and were not exercised live in v0.3.0. All three speak
326
+ the OpenAI `chat/completions` shape. The key comes from `GROQ_API_KEY` / `GEMINI_API_KEY`
327
+ in the environment or a `.env` file, never from config, and is never printed.
256
328
 
257
329
  ## Measured
258
330
 
@@ -21,20 +21,47 @@ proofpath
21
21
  ```
22
22
 
23
23
  ```
24
- ,_,
25
- (o.o)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[PROOF]
26
- " " proofpath v0.2.0 academic . online . coreml
27
- paste a file path, a URL, or a claim. /help /config /quit
24
+ ╭╮ ╭╮
25
+ ╭╯╰─╯╰────────────────────────────────────────────────────────────────────╮
26
+ ╸┤ o o ╰~~~~~~~~~~~~~[PROOF]
27
+ ╰─┬─┬────────────────────────────────────────────────────────────────┬─┬──╯
28
+ ˘ ˘ ˘ ˘
29
+ proofpath v0.2.1 academic . online . coreml
30
+ paste a file path, a URL, or a claim. /help /config /quit
28
31
  ```
29
32
 
30
- Bare `proofpath` opens the terminal UI ([a recorded session](docs/eval/2026-09-15-v0.2-live.md)).
33
+ Bare `proofpath` opens the terminal UI ([a recorded session in both themes](docs/eval/2026-09-15-tui-v2-live.md),
34
+ with [SVG screenshots](docs/eval/tui-v2-rich.svg)). Each run is one panel in its own
35
+ accent: the command on the top border and the run's state at its right, a fixed-column
36
+ stage table underneath (`✓` finished, `⏺` still running or finished with something
37
+ unverified, a real progress bar on the active stage, the provider that produced each
38
+ number at the right), a rule, then the findings — location, reference, the state word
39
+ as a badge, the tier — with the finding's notes and the claim (`you`) and the passage
40
+ (`source`) it was checked against under it. The bottom border carries the run's
41
+ coverage; the docked footer draws it as a bar and never scrolls away.
42
+
31
43
  Paste a path and it runs; every one-shot verb is a slash command (`/check`, `/resolve`,
32
44
  `/fetch`, `/config`, `/cache`), runs can be started while others are in flight and
33
- stopped with `/cancel #n` — a stopped run keeps what it had decided and the
34
- coverage footer never scrolls away. Click (or press `enter` on) a finding to read the
35
- whole quoted passage; `⧉` copies it; a finding's reference is a link to its source.
36
- When a publisher blocks the plain fetch, the permission question is asked **inline,
37
- under the stage that hit the wall**, with `[allow once] [always] [no] [never]`.
45
+ stopped with `/cancel #n` — a stopped run keeps what it had decided. Click (or press
46
+ `enter` on) a finding to read the whole quoted passage; `⧉` copies it; a finding's
47
+ reference is a link to its source. When a publisher blocks the plain fetch, the
48
+ permission question is asked **inline, under the stage that hit the wall**, with
49
+ `[allow once] [always] [no] [never]`.
50
+
51
+ **Windows / `NO_COLOR`.** The look above is the `rich` theme, chosen when the terminal
52
+ gives evidence of truecolor (`COLORTERM`, Windows Terminal, iTerm2, kitty, WezTerm,
53
+ Ghostty, VS Code, Terminal.app). Under `NO_COLOR`, `--no-color`, `-q`, `TERM=dumb`,
54
+ legacy conhost or a CJK locale the `plain` theme draws the same runs as flat ASCII rows
55
+ in the terminal's own 16 colours — the state words, the coverage and every honesty
56
+ sentence are identical, only the drawing changes. `PROOFPATH_THEME=rich|plain` forces
57
+ either, for screenshots and bug reports.
58
+
59
+ ```
60
+ ,_,
61
+ (o.o)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~[PROOF]
62
+ " " proofpath v0.2.1 academic . online . coreml
63
+ paste a file path, a URL, or a claim. /help /config /quit
64
+ ```
38
65
 
39
66
  The same engine behind a pipe or in CI:
40
67
 
@@ -156,7 +183,12 @@ runtime teardown); fixed in v0.1 — 20 of 20 piped runs exit `1`
156
183
  counted as unreachable.
157
184
  - **Coverage is not perfectly reproducible**: two runs minutes apart can read a
158
185
  different number of sources, depending on which providers answered.
159
- - The LLM judge and `--summarize` arrive in **v0.3**.
186
+ - **The judge is a second opinion, not a second verdict.** `--judge` asks the model only
187
+ about the low-tier verdicts (1 of 10 on the live draft), and its answer is printed
188
+ beside the local verdict, never in place of it. `--summarize` is one extra call over
189
+ the finished report, labelled model-written; if the provider does not answer, the
190
+ markdown report, the JSON and the terminal say so (`judge status` / `summary status`
191
+ in the header). The SARIF log does not carry it — it is a findings document.
160
192
 
161
193
  ## Speed
162
194
 
@@ -190,13 +222,53 @@ TablePlus or DBeaver — plain tables, no extension. Raw publisher text expires
190
222
  7 days; verdicts keep the passage they quote; a provider outage is never stored.
191
223
  `proofpath resolve REF` and `proofpath fetch URL|DOI` run either half on its own.
192
224
 
193
- ## Optional LLM judge — arrives in v0.3
225
+ ## Optional LLM judge (v0.3)
226
+
227
+ Everything above runs locally, and the default run makes **zero** LLM calls. Two flags
228
+ add an LLM at the end, and only there:
229
+
230
+ ```bash
231
+ proofpath check paper.pdf --judge # a second opinion on the low-confidence verdicts
232
+ proofpath check paper.pdf --summarize # one model-written paragraph over the finished report
233
+ proofpath config check # proves the key works before you spend a run on it
234
+ ```
194
235
 
195
- Everything above runs locally. An LLM is used only at the end, as an opt-in second
196
- opinion on low-confidence verdictsit never sees a source document and cannot
197
- change a verdict. The settings exist today (`proofpath config check` proves a key
198
- works, default Groq); `check --judge` and `--summarize` are wired in v0.3. The key
199
- comes from the environment or a `.env` file, never from config, and is never printed.
236
+ **What `--judge` does.** After the local verdicts are final, the verdicts the models
237
+ were least sure aboutthe `low` tier, never a numeric mismatch and never a claim
238
+ without a quoted passage go to the model in batches of up to 20 (about 7k tokens),
239
+ each with its claim and the passage it was checked against. The model answers from the
240
+ passage alone, and its label and one-sentence rationale are printed **beside** the local
241
+ verdict: `= judge (groq openai/gpt-oss-120b): NEI — …`. The local verdict, the finding
242
+ kind and the report's states never change. Opinions are cached with the verdict, so a
243
+ re-run asks nothing.
244
+
245
+ **What it cannot do.** It never sees a source document, so it cannot introduce a claim
246
+ or an evidence passage of its own; it cannot turn `NEI` into `SUPPORTED`; it cannot
247
+ hide a source that could not be read. If the provider is down, rate-limited or the key
248
+ is wrong, the run finishes on the local verdicts and says so in the stage line, the
249
+ report header (`judge status:`) and the JSON — `-q` cannot hide it.
250
+
251
+ **What `--summarize` does.** One final call turns the finished markdown report into 3–5
252
+ plain sentences a reader can act on. It runs after the report is complete, its only
253
+ input is that report, it is off by default in the CLI and the TUI (`/summarize` there),
254
+ and the output is labelled `(model-written, <provider> <model>)`. `--summarize` alone
255
+ is exactly one call; with `--judge` the escalation runs first.
256
+
257
+ **Cost.** The footer counts the calls and the stage line the tokens:
258
+ `Judging … 1 of 10 verdicts reviewed, 1 call, 613 prompt · 193 completion tokens` and
259
+ `Summarising … 98 words, 1 call, 1,608 prompt · 343 completion tokens`
260
+ on the live draft ([details](docs/eval/2026-09-15-judge-live.md)). Groq's free tier
261
+ allows roughly one call a minute. Only the low-tier verdicts are sent — 1 of 10 on that
262
+ draft — and up to 20 go in one call, so a long bibliography costs a handful of calls, not
263
+ one per citation.
264
+
265
+ **Providers.** Default is Groq `openai/gpt-oss-120b` (free without a card, no training
266
+ on submitted data). `proofpath config set judge.provider gemini` switches to Gemini —
267
+ note that Google trains on free-tier prompts outside the EEA/UK/CH, and proofpath prints
268
+ that warning once per run. `judge.provider ollama` runs fully offline. Gemini and Ollama are
269
+ fixture-tested and were not exercised live in v0.3.0. All three speak
270
+ the OpenAI `chat/completions` shape. The key comes from `GROQ_API_KEY` / `GEMINI_API_KEY`
271
+ in the environment or a `.env` file, never from config, and is never printed.
200
272
 
201
273
  ## Measured
202
274
 
@@ -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.