sooth 0.2.2__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.
- sooth-0.3.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- sooth-0.3.0/.github/PULL_REQUEST_TEMPLATE.md +17 -0
- sooth-0.3.0/.github/workflows/ci.yml +60 -0
- sooth-0.3.0/CHANGELOG.md +70 -0
- sooth-0.3.0/CODE_OF_CONDUCT.md +90 -0
- sooth-0.3.0/CONTRIBUTING.md +72 -0
- sooth-0.3.0/PKG-INFO +258 -0
- sooth-0.3.0/README.md +226 -0
- sooth-0.3.0/action.sh +89 -0
- sooth-0.3.0/action.yml +78 -0
- sooth-0.3.0/assets/sooth-demo.cast +92 -0
- sooth-0.3.0/assets/sooth-demo.gif +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/docs/DESIGN.md +57 -15
- {sooth-0.2.2 → sooth-0.3.0}/docs/PRD.md +6 -0
- sooth-0.3.0/docs/TESTING.md +82 -0
- sooth-0.3.0/examples/ai-summary.md +3 -0
- {sooth-0.2.2 → sooth-0.3.0}/examples/calibration.md +19 -1
- sooth-0.3.0/examples/release-notes.md +27 -0
- {sooth-0.2.2 → sooth-0.3.0}/pyproject.toml +25 -3
- sooth-0.3.0/src/sooth/__init__.py +37 -0
- {sooth-0.2.2 → sooth-0.3.0}/src/sooth/cli.py +32 -16
- sooth-0.3.0/src/sooth/demo-en.json +1 -0
- {sooth-0.2.2 → sooth-0.3.0}/src/sooth/report.py +46 -25
- sooth-0.3.0/tests/smoke.sh +81 -0
- sooth-0.3.0/tests/test_action.sh +146 -0
- {sooth-0.2.2 → sooth-0.3.0}/tests/test_core.py +128 -1
- sooth-0.2.2/.github/PULL_REQUEST_TEMPLATE.md +0 -9
- sooth-0.2.2/.github/workflows/ci.yml +0 -21
- sooth-0.2.2/PKG-INFO +0 -159
- sooth-0.2.2/README.md +0 -136
- sooth-0.2.2/docs/TESTING.md +0 -51
- sooth-0.2.2/src/sooth/__init__.py +0 -21
- sooth-0.2.2/tests/smoke.sh +0 -32
- {sooth-0.2.2 → sooth-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/.gitignore +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/LICENSE +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/docs/DOGFOOD.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/examples/calibration.json +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/examples/draft.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/examples/news-1-evil.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/examples/news-1-output.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/examples/news-1-summ.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/examples/news-1.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/examples/policy.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/examples/pricing.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/examples/source.md +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/src/sooth/claims.py +0 -0
- /sooth-0.2.2/src/sooth/demo.json → /sooth-0.3.0/src/sooth/demo-id.json +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/src/sooth/verify.py +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/tests/calibrate.py +0 -0
- {sooth-0.2.2 → sooth-0.3.0}/tests/conftest.py +0 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: true
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Read the PRD, design, and testing docs first
|
|
4
|
+
url: https://github.com/naufalhilmiaji/sooth/tree/main/docs
|
|
5
|
+
about: Scope decisions, the verdict contract, and what the test layers cover.
|
|
6
|
+
- name: TypeSafe / Jev API questions
|
|
7
|
+
url: https://docs.typesafe.ai
|
|
8
|
+
about: Sooth is a CLI on top of Jev. Questions about the engine, keys, or quotas belong with TypeSafe.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
## What
|
|
2
|
+
|
|
3
|
+
## Why
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] `python3 tests/test_core.py` passes
|
|
8
|
+
- [ ] `bash tests/test_action.sh` passes (if `action.yml` / `action.sh` changed)
|
|
9
|
+
- [ ] `ruff check src tests` is clean
|
|
10
|
+
- [ ] New logic covered by an assert in `tests/test_core.py`
|
|
11
|
+
- [ ] Docs updated if behavior changed (`docs/PRD.md`, `docs/DESIGN.md`, `docs/TESTING.md`, README)
|
|
12
|
+
- [ ] `CHANGELOG.md` updated under `## [Unreleased]`
|
|
13
|
+
|
|
14
|
+
## For verdict or accuracy changes
|
|
15
|
+
|
|
16
|
+
- [ ] No calibrated threshold was lowered to make a case pass
|
|
17
|
+
- [ ] Relevant demo records re-recorded from a live run rather than hand-edited
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python-version }}
|
|
19
|
+
- run: pip install -e ".[dev]"
|
|
20
|
+
- run: ruff check src tests
|
|
21
|
+
- run: pytest
|
|
22
|
+
- run: bash tests/test_action.sh
|
|
23
|
+
|
|
24
|
+
# End-to-end smoke of the packaged CLI with no API key: both demo cases are
|
|
25
|
+
# recorded runs, so this exercises claim parsing, verdict mapping, and every
|
|
26
|
+
# renderer on a real report. It also pins the exit-code contract, which is
|
|
27
|
+
# the thing CI users actually depend on.
|
|
28
|
+
- name: Offline demo smoke
|
|
29
|
+
run: |
|
|
30
|
+
sooth --version
|
|
31
|
+
set +e
|
|
32
|
+
sooth demo > /dev/null; rc_md=$?
|
|
33
|
+
sooth demo --case id > /dev/null; rc_id=$?
|
|
34
|
+
sooth demo --format plain > /dev/null; rc_plain=$?
|
|
35
|
+
sooth demo --format json > /tmp/demo.json; rc_json=$?
|
|
36
|
+
set -e
|
|
37
|
+
test "$rc_md" -eq 1 && test "$rc_id" -eq 1 && test "$rc_plain" -eq 1 && test "$rc_json" -eq 1
|
|
38
|
+
python -c "import json; d = json.load(open('/tmp/demo.json')); assert d['exit_code'] == 1, d['summary']; assert len(d['verdicts']) == 8, len(d['verdicts']); assert sum(d['summary'][k] for k in ('pass','fail','review','uncheckable')) == 8; assert d['verdicts'][1]['missing_numbers'] == ['2,000'], d['verdicts'][1]; print('json contract ok')"
|
|
39
|
+
|
|
40
|
+
package:
|
|
41
|
+
# The demo records are non-Python files inside the package directory. If they
|
|
42
|
+
# stop shipping in the wheel, `sooth demo` breaks only for users who installed
|
|
43
|
+
# from PyPI — so assert it here rather than by hand.
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
- uses: actions/setup-python@v5
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.12"
|
|
50
|
+
- run: pip wheel --no-deps -w dist .
|
|
51
|
+
- name: Install the built wheel and replay every demo case
|
|
52
|
+
run: |
|
|
53
|
+
pip install --force-reinstall dist/*.whl
|
|
54
|
+
cd /tmp # leave the source tree, so the installed copy is what runs
|
|
55
|
+
set +e
|
|
56
|
+
sooth demo > /dev/null; rc_en=$?
|
|
57
|
+
sooth demo --case id > /dev/null; rc_id=$?
|
|
58
|
+
set -e
|
|
59
|
+
test "$rc_en" -eq 1 && test "$rc_id" -eq 1
|
|
60
|
+
echo "wheel ships both demo cases"
|
sooth-0.3.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Sooth. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow [SemVer](https://semver.org/).
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.3.0] — 2026-09-26
|
|
8
|
+
|
|
9
|
+
Presentation and machine-consumption release. No change to verification behaviour or to any calibrated threshold.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `--format json` — stable machine-readable report (`summary`, `exit_code`, `verdicts[]` with probabilities, evidence, and missing numbers). One JSON contract for pipelines and agents instead of scraping Markdown.
|
|
14
|
+
- `sooth demo --case en|id` — two bundled recorded runs now ship in the wheel. `en` is the default (release notes vs an AI summary, three numbers silently wrong); `id` is the Indonesian market-news case.
|
|
15
|
+
- `--version`, reading the version from installed distribution metadata.
|
|
16
|
+
- GitHub Action: `fail-on` input (`review` default, `fail`, `never`), and `outputs` — `verdicts`, `pass-count`, `fail-count`, `review-count`, `uncheckable-count`, `report`, `exit-code`. All from a single API call.
|
|
17
|
+
- English calibration fixture (`examples/release-notes.md` + `examples/ai-summary.md`) as the default demo.
|
|
18
|
+
- CI: an offline demo smoke step that pins the documented exit codes and the JSON contract, plus a `package` job that installs the built wheel and replays both demo cases (guards non-Python package data).
|
|
19
|
+
- `CHANGELOG.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- README rewritten around the measured accuracy numbers and an English hero demo.
|
|
24
|
+
- Action installs the exact version declared in its own `pyproject.toml`, so the pin can no longer drift from the tag.
|
|
25
|
+
- PyPI metadata: keywords and classifiers now cover `hallucination`, `fact-checking`, `llm-evaluation`, `rag`, `guardrails`, `ci`, `github-action`.
|
|
26
|
+
- `render_json` and the `--log` record now share one verdict-serialisation function, so the two JSON surfaces cannot drift apart.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- `sooth.__version__` reported `0.1.0` while the distribution was `0.2.3`. Now sourced from packaging metadata; a test fails if it ever becomes a hardcoded literal again.
|
|
31
|
+
- `tests/smoke.sh` invoked the bare `python3`, which fails when `typesafe-sdk` only exists in the project venv. It now prefers an active venv, then `./.venv`, then `python3`, accepts `PYTHON=`, and explains the fix instead of exiting 3 silently.
|
|
32
|
+
|
|
33
|
+
## [0.2.3] — 2026-09-25
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- GitHub Action — a CI quality gate in one `uses:` line, with the report appended to the job summary.
|
|
38
|
+
|
|
39
|
+
## [0.2.2] — 2026-09-25
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- `sooth demo` — replays a bundled recorded run offline, no API key needed.
|
|
44
|
+
- README overhaul with a recorded demo.
|
|
45
|
+
|
|
46
|
+
## [0.2.1] — 2026-09-25
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- Source-span evidence behind every verdict: sources are split into sentence segments, code pre-ranks ~6 candidates per claim, and a per-claim Choice selects the best span.
|
|
51
|
+
- First PyPI release.
|
|
52
|
+
|
|
53
|
+
## [0.2.0] — 2026-09-25
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- Source-span evidence behind every verdict (`v0.2` feature branch).
|
|
58
|
+
- 30-claim calibration set with a live runner and a frozen confusion matrix.
|
|
59
|
+
|
|
60
|
+
### Fixed
|
|
61
|
+
|
|
62
|
+
- Ruff lint violations blocking CI.
|
|
63
|
+
|
|
64
|
+
## [0.1.0-alpha] — 2026-09-24
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
|
|
68
|
+
- Initial CLI: `sooth --source … --text …`, sentence-per-claim splitting, Jev fan-out verification (four questions per claim in one batched call), Markdown report, `--log` JSONL decision ledger, CI exit codes, `--confidence` threshold.
|
|
69
|
+
- Safeguards: detail-match gate and deterministic number-smuggling check demote `PASS` to `REVIEW`.
|
|
70
|
+
- PRD, technical design, and testing docs.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, caste, colour, religion, or sexual
|
|
10
|
+
identity and orientation.
|
|
11
|
+
|
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
13
|
+
diverse, inclusive, and healthy community.
|
|
14
|
+
|
|
15
|
+
## Our Standards
|
|
16
|
+
|
|
17
|
+
Examples of behaviour that contributes to a positive environment:
|
|
18
|
+
|
|
19
|
+
- Demonstrating empathy and kindness toward other people
|
|
20
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
21
|
+
- Giving and gracefully accepting constructive feedback
|
|
22
|
+
- Accepting responsibility and apologising to those affected by our mistakes,
|
|
23
|
+
and learning from the experience
|
|
24
|
+
- Focusing on what is best not just for us as individuals, but for the overall
|
|
25
|
+
community
|
|
26
|
+
|
|
27
|
+
Examples of unacceptable behaviour:
|
|
28
|
+
|
|
29
|
+
- The use of sexualised language or imagery, and sexual attention or advances
|
|
30
|
+
of any kind
|
|
31
|
+
- Trolling, insulting or derogatory comments, and personal or political attacks
|
|
32
|
+
- Public or private harassment
|
|
33
|
+
- Publishing others' private information, such as a physical or email address,
|
|
34
|
+
without their explicit permission
|
|
35
|
+
- Other conduct which could reasonably be considered inappropriate in a
|
|
36
|
+
professional setting
|
|
37
|
+
|
|
38
|
+
## Enforcement Responsibilities
|
|
39
|
+
|
|
40
|
+
The maintainer is responsible for clarifying and enforcing our standards of
|
|
41
|
+
acceptable behaviour, and will take appropriate and fair corrective action in
|
|
42
|
+
response to any behaviour that they deem inappropriate, threatening, offensive,
|
|
43
|
+
or harmful.
|
|
44
|
+
|
|
45
|
+
The maintainer has the right and responsibility to remove, edit, or reject
|
|
46
|
+
comments, commits, code, issues, and other contributions that are not aligned
|
|
47
|
+
with this Code of Conduct, and will communicate reasons for moderation decisions
|
|
48
|
+
when appropriate.
|
|
49
|
+
|
|
50
|
+
## Scope
|
|
51
|
+
|
|
52
|
+
This Code of Conduct applies within all community spaces — issues, pull
|
|
53
|
+
requests, discussions — and also applies when an individual is officially
|
|
54
|
+
representing the project in public spaces.
|
|
55
|
+
|
|
56
|
+
## Enforcement
|
|
57
|
+
|
|
58
|
+
Instances of abusive, harassing, or otherwise unacceptable behaviour may be
|
|
59
|
+
reported to the maintainer at **nhilmiaji@gmail.com**. All complaints will be
|
|
60
|
+
reviewed and investigated promptly and fairly. The maintainer is obligated to
|
|
61
|
+
respect the privacy and security of the reporter of any incident.
|
|
62
|
+
|
|
63
|
+
## Enforcement Guidelines
|
|
64
|
+
|
|
65
|
+
The maintainer will follow these Community Impact Guidelines in determining the
|
|
66
|
+
consequences for any action deemed in violation of this Code of Conduct:
|
|
67
|
+
|
|
68
|
+
**1. Correction** — A private, written warning, providing clarity around the
|
|
69
|
+
nature of the violation and an explanation of why the behaviour was
|
|
70
|
+
inappropriate. A public apology may be requested.
|
|
71
|
+
|
|
72
|
+
**2. Warning** — A warning with consequences for continued behaviour. No
|
|
73
|
+
interaction with the people involved for a specified period of time. Violating
|
|
74
|
+
these terms may lead to a temporary or permanent ban.
|
|
75
|
+
|
|
76
|
+
**3. Temporary Ban** — A temporary ban from any sort of interaction or public
|
|
77
|
+
communication with the community for a specified period of time. No public or
|
|
78
|
+
private interaction with the people involved is allowed during this period.
|
|
79
|
+
|
|
80
|
+
**4. Permanent Ban** — A permanent ban from any sort of public interaction
|
|
81
|
+
within the community.
|
|
82
|
+
|
|
83
|
+
## Attribution
|
|
84
|
+
|
|
85
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org),
|
|
86
|
+
version 2.1, available at
|
|
87
|
+
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
|
|
88
|
+
|
|
89
|
+
Community Impact Guidelines were inspired by
|
|
90
|
+
[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/inclusion).
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Contributing to Sooth
|
|
2
|
+
|
|
3
|
+
Thanks for looking. This is a small tool with a narrow contract, and the fastest way to get a change merged is to keep it narrow.
|
|
4
|
+
|
|
5
|
+
## Set up
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/naufalhilmiaji/sooth
|
|
9
|
+
cd sooth
|
|
10
|
+
python3 -m venv .venv && . .venv/bin/activate
|
|
11
|
+
pip install -e ".[dev]"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Run the checks
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
python3 tests/test_core.py # pure checks — no network, no API key, under a second
|
|
18
|
+
pytest # same suite through pytest
|
|
19
|
+
bash tests/test_action.sh # GitHub Action arg wiring, outputs, and fail-on policy
|
|
20
|
+
ruff check src tests # lint — CI runs this, line length 100
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Two optional layers need a live key (`TYPESAFE_API_KEY` from [console.typesafe.ai](https://console.typesafe.ai)):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bash tests/smoke.sh # end-to-end against the live API
|
|
27
|
+
PYTHONPATH=src python3 tests/calibrate.py # 30-claim calibration; exits non-zero if the bar is missed
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
CI never calls the live API — it would cost money and add flakiness on forks. Run the live layers yourself before a release.
|
|
31
|
+
|
|
32
|
+
## Ground rules
|
|
33
|
+
|
|
34
|
+
**Never move the threshold to hide a failure.** If calibration regresses, the fix is question wording in `build_questions()` in `src/sooth/verify.py`, not a lower `--confidence` default and not a relaxed labelled case. The calibration matrix is frozen in `examples/calibration.md`; if you change it, say why in the diff.
|
|
35
|
+
|
|
36
|
+
**No new runtime dependencies** without a discussion issue first. The runtime dependency list is exactly one package (`typesafe-sdk`); a verifier that drags in a dependency tree is a verifier nobody installs into a CI job.
|
|
37
|
+
|
|
38
|
+
**Verdict mapping stays pure and readable.** `map_verdict` and `apply_safeguards` take values and return values. Network I/O lives in `verify_claims` only. If your change makes the decision path untestable without a key, it will not be merged.
|
|
39
|
+
|
|
40
|
+
**Deterministic checks belong in code, not in prompts.** If a rule can be expressed as a regex or an arithmetic comparison — like the number-smuggling check in `missing_numbers()` — it belongs in Python, where it can be tested and audited.
|
|
41
|
+
|
|
42
|
+
**Fixed vocabulary.** Verdicts are `PASS`, `FAIL`, `REVIEW`, `UNCHECKABLE` and nothing else. Resist adding states.
|
|
43
|
+
|
|
44
|
+
## Adding a demo case
|
|
45
|
+
|
|
46
|
+
`sooth demo` must keep working with no API key and no network. To add one:
|
|
47
|
+
|
|
48
|
+
1. Add the source and draft documents under `examples/`.
|
|
49
|
+
2. Run a real verification with `--log` and keep the output:
|
|
50
|
+
```bash
|
|
51
|
+
sooth --source examples/your-source.md --text examples/your-draft.md --log /tmp/run.jsonl
|
|
52
|
+
```
|
|
53
|
+
3. Save that single JSONL line as `src/sooth/demo-<case>.json`.
|
|
54
|
+
4. Register it in `DEMO_CASES` in `src/sooth/cli.py`.
|
|
55
|
+
5. `pytest` covers the rest — `test_demo_fixtures_are_valid_records` and `test_cli_demo_replays_offline` will fail if the record or the wiring is wrong.
|
|
56
|
+
|
|
57
|
+
Demo records are real recorded runs. Do not hand-edit verdicts to make a demo look better; re-run and commit what the model actually returned.
|
|
58
|
+
|
|
59
|
+
## Adding calibration claims
|
|
60
|
+
|
|
61
|
+
Append to `examples/calibration.json` with an `expected` verdict and a one-line note explaining why that label is correct. Then re-run `tests/calibrate.py` live and update `examples/calibration.md` with the new matrix. Cases that reveal a wrong answer are more valuable than cases that confirm the tool works — record those, and explain the failure mode.
|
|
62
|
+
|
|
63
|
+
## Reporting a wrong verdict
|
|
64
|
+
|
|
65
|
+
The most useful bug report includes: the source document, the draft, the verdict Sooth returned, the verdict you expected, and the `--format json` payload for that claim. Include the `Why` column — the probability distribution usually makes the cause obvious.
|
|
66
|
+
|
|
67
|
+
## Pull requests
|
|
68
|
+
|
|
69
|
+
- One thing per PR. A feature and a refactor in the same diff will be asked to split.
|
|
70
|
+
- Add or update a test in `tests/test_core.py` for any change to logic in `claims.py`, `verify.py`, or `report.py`.
|
|
71
|
+
- Update `CHANGELOG.md` under `## [Unreleased]`.
|
|
72
|
+
- Commit messages: `feat:`, `fix:`, `docs:`, `chore:`, `test:` — the repo log is readable, keep it that way.
|
sooth-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sooth
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Claim-by-claim hallucination detection and fact-checking for AI-generated text, built for CI. PASS/FAIL/REVIEW verdicts with calibrated probabilities and the source line behind each one, powered by Jev (TypeSafe System One).
|
|
5
|
+
Project-URL: Homepage, https://github.com/naufalhilmiaji/sooth
|
|
6
|
+
Project-URL: Documentation, https://github.com/naufalhilmiaji/sooth/tree/main/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/naufalhilmiaji/sooth
|
|
8
|
+
Project-URL: Issues, https://github.com/naufalhilmiaji/sooth/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/naufalhilmiaji/sooth/releases
|
|
10
|
+
Author-email: Naufal Hilmiaji <nhilmiaji@gmail.com>
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: ai-safety,ci,fact-checking,github-action,guardrails,hallucination,hallucination-detection,jev,llm-evaluation,rag,typesafe,verification
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
24
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
25
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Requires-Dist: typesafe-sdk
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# Sooth
|
|
34
|
+
|
|
35
|
+
**LLMs generate. Sooth verifies.**
|
|
36
|
+
|
|
37
|
+
Claim-by-claim hallucination detection for AI output. Sooth checks every sentence in a draft against your source material and returns `PASS` / `FAIL` / `REVIEW` — with calibrated probabilities, the exact source line behind each verdict, and exit codes that fail your build.
|
|
38
|
+
|
|
39
|
+
[](https://pypi.org/project/sooth/)
|
|
40
|
+
[](https://pypi.org/project/sooth/)
|
|
41
|
+
[](https://github.com/naufalhilmiaji/sooth/blob/main/LICENSE)
|
|
42
|
+
[](https://github.com/naufalhilmiaji/sooth/actions/workflows/ci.yml)
|
|
43
|
+
|
|
44
|
+
## Try it in 10 seconds — no API key
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install sooth
|
|
48
|
+
sooth demo
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`demo` replays a recorded run through the real reporting code. No network, no key, no signup.
|
|
52
|
+
|
|
53
|
+
## See it catch a hallucination
|
|
54
|
+
|
|
55
|
+
A model was asked to summarise a product release note. Three numbers came back wrong.
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
# Sooth
|
|
59
|
+
|
|
60
|
+
**PASS 4 · FAIL 3 · REVIEW 0 · UNCHECKABLE 1** — threshold 0.70
|
|
61
|
+
|
|
62
|
+
| # | Claim | Verdict | P | Why (P distribution) | Evidence |
|
|
63
|
+
|---|-------|---------|---|----------------------|----------|
|
|
64
|
+
| 1 | Kestrel Cloud launched API v3 on 14 August 2026 across all of its regions. | ✅ PASS | ████████ 1.00 | supports 1.00 / contradicts 0.00 / not_found 0.00 · details 0.86 | `examples/release-notes.md:7` "API v3 is generally available in all 12 regions, includin…" |
|
|
65
|
+
| 2 | The rate limit jumps to 2,000 requests per second per project, a twenty-fold increase over v2. | ❌ FAIL | ████████ 1.00 | supports 0.00 / contradicts 1.00 / not_found 0.00 · details 0.01 · missing #s: 2,000 | `examples/release-notes.md:11` "The rate limit rises from 100 requests per second to 500 …" |
|
|
66
|
+
| 3 | Token pricing falls to $0.002 per 1,000 input tokens, making it the cheapest mainstream inference API. | ❌ FAIL | ████████ 1.00 | supports 0.00 / contradicts 1.00 / not_found 0.00 · details 0.01 · missing #s: 0.002 | `examples/release-notes.md:15` "Token pricing drops to $0.004 per 1,000 input tokens and …" |
|
|
67
|
+
| 4 | Kestrel is now certified SOC 2 Type II, which unblocks enterprise procurement. | ❌ FAIL | ████████ 1.00 | supports 0.00 / contradicts 1.00 / not_found 0.00 · details 0.01 | `examples/release-notes.md:27` "SOC 2 Type II certification is still in progress and is n…" |
|
|
68
|
+
| 5 | The free tier now includes 10,000 requests per month. | ✅ PASS | ████████ 1.00 | supports 1.00 / contradicts 0.00 / not_found 0.00 · details 0.97 | `examples/release-notes.md:15` "The free tier now includes 10,000 requests per month, up …" |
|
|
69
|
+
| 6 | API v3 runs across 12 regions and held p99 latency of 180 ms through the beta. | ✅ PASS | ████████ 1.00 | supports 1.00 / contradicts 0.00 / not_found 0.00 · details 0.88 | `examples/release-notes.md:19` "Latency at p99 was 180 ms during the six-week beta." |
|
|
70
|
+
| 7 | Developers say the migration is the smoothest they have seen. | ➖ UNCHECKABLE | █░░░░░░░ 0.16 | P(checkable)=0.16 | |
|
|
71
|
+
| 8 | Existing v2 keys keep working until 31 January 2027. | ✅ PASS | ████████ 1.00 | supports 1.00 / contradicts 0.00 / not_found 0.00 · details 0.99 | `examples/release-notes.md:7` "Existing v2 keys keep working until 31 January 2027." |
|
|
72
|
+
|
|
73
|
+
## Needs review
|
|
74
|
+
|
|
75
|
+
- line 3: Developers say the migration is the smoothest they have seen.
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Exit code `1`. The build stops. No human had to notice that `2,000` should have been `500`, or that SOC 2 was still *in progress* in the source.
|
|
79
|
+
|
|
80
|
+
Every verdict carries its probability distribution and the source span it was judged against. When Sooth is unsure, it says `REVIEW` instead of guessing.
|
|
81
|
+
|
|
82
|
+
Reproduce that exact report offline with `sooth demo`. The inputs ship in [`examples/`](examples/): [`release-notes.md`](examples/release-notes.md) and [`ai-summary.md`](examples/ai-summary.md).
|
|
83
|
+
|
|
84
|
+
## Accuracy
|
|
85
|
+
|
|
86
|
+
Measured, not asserted. [`examples/calibration.json`](examples/calibration.json) is a hand-labelled set of 30 claims — 10 supported, 10 contradicted (number flips, feature mis-attribution, negation flips), 5 invented, 5 opinions — drawn from three documents (English policy, SaaS pricing, and Indonesian market news).
|
|
87
|
+
|
|
88
|
+
- **30/30 correct** verdicts, live, re-run 2026-09-26 on the v0.3.0 code. Bar is ≥ 24/30; the runner exits non-zero if it is missed.
|
|
89
|
+
- **Zero confident-wrong `PASS` on a contradicted claim, in every run.** This is the number that matters: a wrong `PASS` is the failure mode that ships garbage, so it is the one the runner gates on hardest.
|
|
90
|
+
- One case is inherently jittery: an invented claim whose checkable probability sits on the 0.5 floor, flipping between `REVIEW` and `UNCHECKABLE` across runs. Both outcomes mean "do not act on this". It is recorded rather than tuned away.
|
|
91
|
+
|
|
92
|
+
Full confusion matrix and notes: [`examples/calibration.md`](examples/calibration.md). Re-run it live with `PYTHONPATH=src python3 tests/calibrate.py`. The threshold has never been moved to hide a failure — when a case regressed, question wording in `verify.py` was fixed instead.
|
|
93
|
+
|
|
94
|
+
Honest caveat: 30 claims is a small set, labelled by the author, and it is not a substitute for evaluating Sooth on your own documents. It is a regression gate, not a benchmark claim.
|
|
95
|
+
|
|
96
|
+
## Install
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pip install sooth
|
|
100
|
+
export TYPESAFE_API_KEY=... # get one at console.typesafe.ai
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Requires Python 3.11+. Judgments come from [Jev](https://docs.typesafe.ai) (TypeSafe System One), which returns typed distributions instead of generated prose.
|
|
104
|
+
|
|
105
|
+
## Usage
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
sooth --source docs/policy.md --source tickets/t123.md --text draft-reply.md
|
|
109
|
+
|
|
110
|
+
# CI-friendly exit codes
|
|
111
|
+
sooth --source policy.md --text draft.md --format plain
|
|
112
|
+
# 0 = clean · 1 = any FAIL · 2 = any REVIEW · 3 = usage/config error
|
|
113
|
+
|
|
114
|
+
# Options
|
|
115
|
+
# --confidence T REVIEW below this confidence (default 0.7)
|
|
116
|
+
# --format md|plain|json
|
|
117
|
+
# -o FILE write report to file
|
|
118
|
+
# --log FILE append full judgment trace (one JSONL line per run)
|
|
119
|
+
# --version
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Machine-readable output
|
|
123
|
+
|
|
124
|
+
`--format json` gives pipelines and agents a stable contract — no prose parsing, and the exit code is stated in the payload:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"summary": { "pass": 4, "fail": 3, "review": 0, "uncheckable": 1, "threshold": 0.7 },
|
|
129
|
+
"exit_code": 1,
|
|
130
|
+
"verdicts": [
|
|
131
|
+
{
|
|
132
|
+
"id": "c2",
|
|
133
|
+
"text": "The rate limit jumps to 2,000 requests per second per project…",
|
|
134
|
+
"line": 3,
|
|
135
|
+
"kind": "FAIL",
|
|
136
|
+
"choice": "contradicts",
|
|
137
|
+
"probabilities": { "supports": 0.0, "contradicts": 1.0, "not_found": 0.0 },
|
|
138
|
+
"confidence": 1.0,
|
|
139
|
+
"details_p": 0.01,
|
|
140
|
+
"missing_numbers": ["2,000"],
|
|
141
|
+
"evidence": {
|
|
142
|
+
"text": "The rate limit rises from 100 requests per second to 500 requests per second per project.",
|
|
143
|
+
"line": 11,
|
|
144
|
+
"source": "examples/release-notes.md"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Use it as a CI quality gate
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
- name: Verify AI output
|
|
155
|
+
uses: naufalhilmiaji/sooth@v0.3.0
|
|
156
|
+
with:
|
|
157
|
+
source: docs/policy.md
|
|
158
|
+
text: generated-reply.md
|
|
159
|
+
fail-on: review # review (default) | fail | never
|
|
160
|
+
env:
|
|
161
|
+
TYPESAFE_API_KEY: ${{ secrets.TYPESAFE_API_KEY }}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The step fails the build on `FAIL` — and on `REVIEW`, so nothing uncertain ships silently. Set `fail-on: fail` to block only on hard contradictions. The full report is appended to the job summary.
|
|
165
|
+
|
|
166
|
+
Consume the counts in later steps:
|
|
167
|
+
|
|
168
|
+
```yaml
|
|
169
|
+
- id: sooth
|
|
170
|
+
uses: naufalhilmiaji/sooth@v0.3.0
|
|
171
|
+
with: { source: policy.md, text: draft.md, fail-on: never }
|
|
172
|
+
env: { TYPESAFE_API_KEY: "${{ secrets.TYPESAFE_API_KEY }}" }
|
|
173
|
+
|
|
174
|
+
- run: echo "${{ steps.sooth.outputs.verdicts }}" # PASS 1, FAIL 1, REVIEW 0, UNCHECKABLE 0
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Outputs: `verdicts`, `pass-count`, `fail-count`, `review-count`, `uncheckable-count`, `report`, `exit-code`.
|
|
178
|
+
|
|
179
|
+
Prefer plain shell? `sooth --source policy.md --text draft.md` gives the same exit codes.
|
|
180
|
+
|
|
181
|
+
## How it works
|
|
182
|
+
|
|
183
|
+
1. Draft is split into claims (one sentence each).
|
|
184
|
+
2. Each claim gets four questions to Jev, fanned out in parallel batches: *is this checkable?*, *does the source support it?* (`supports` / `contradicts` / `not_found`), *do all details match exactly?*, and *which source span is the evidence?*
|
|
185
|
+
3. Verdicts are mapped in code: uncheckable → `UNCHECKABLE`; low confidence → `REVIEW`; then `PASS` / `FAIL`. Safeguards demote `PASS` to `REVIEW` when details drift or claim numbers are absent from the source (checked in plain code).
|
|
186
|
+
4. The report shows the full probability distribution per claim — not just a label.
|
|
187
|
+
|
|
188
|
+
The decision logic lives in [`src/sooth/verify.py`](https://github.com/naufalhilmiaji/sooth/blob/main/src/sooth/verify.py) in a dozen readable lines. Change thresholds and rules there, not in prompts.
|
|
189
|
+
|
|
190
|
+
## Why not just use an LLM judge?
|
|
191
|
+
|
|
192
|
+
Not claiming Sooth is universally more accurate. Claiming it gives you **architectural guarantees** a prompt cannot:
|
|
193
|
+
|
|
194
|
+
| | Sooth | Generic LLM judge |
|
|
195
|
+
|---|-------|-------------------|
|
|
196
|
+
| Claim-level verification | ✅ | Sometimes |
|
|
197
|
+
| Source span behind each verdict | ✅ | Sometimes |
|
|
198
|
+
| `PASS` / `FAIL` / `REVIEW` | ✅ fixed vocabulary | Generated labels |
|
|
199
|
+
| Probability distribution | ✅ | Usually none |
|
|
200
|
+
| Verdict rules in readable code | ✅ | Prompt-dependent |
|
|
201
|
+
| CI exit codes | ✅ | ❌ |
|
|
202
|
+
| Audit log (`--log` JSONL) | ✅ | DIY |
|
|
203
|
+
| Runs the same verdict twice | ✅ deterministic mapping | Sampling variance |
|
|
204
|
+
|
|
205
|
+
An LLM judge gives you a sentence about your text. Sooth gives you a decision your code can branch on, and the evidence it branched on.
|
|
206
|
+
|
|
207
|
+
## Who it's for
|
|
208
|
+
|
|
209
|
+
Developers building systems that generate text from trusted material:
|
|
210
|
+
|
|
211
|
+
- **RAG pipelines** — retrieved the right document, still wrote the wrong number
|
|
212
|
+
- **AI agents** — before an agent's reply reaches a human
|
|
213
|
+
- **Support / ops copilots** — policy-backed answers, checked against the policy
|
|
214
|
+
- **Report & summary generation** — figures that must match the source
|
|
215
|
+
- **Compliance workflows** — evidence trail for every claim, not vibes
|
|
216
|
+
|
|
217
|
+
## Beyond English
|
|
218
|
+
|
|
219
|
+
The bundled Indonesian case proves the pipeline is not English-only: `sooth demo --case id` replays a recorded run against Indonesian market news, where three fabricated figures are caught. Non-English claim segmentation needs a whitespace-language sentence splitter (Indonesian, Malay, and most European languages are fine; Chinese and Japanese would need a different splitter — see [`src/sooth/claims.py`](https://github.com/naufalhilmiaji/sooth/blob/main/src/sooth/claims.py)).
|
|
220
|
+
|
|
221
|
+
## Known limits (alpha)
|
|
222
|
+
|
|
223
|
+
- Safeguards catch most drift and smuggling: claim numbers absent from the source demote `PASS` to `REVIEW`, and a detail-match gate flags altered hedges ("about 74%" → "over 74%"). Not perfect — read the `Why` column before trusting a verdict.
|
|
224
|
+
- Derived numbers (totals, values computed outside the source) look "missing" and land in `REVIEW`.
|
|
225
|
+
- Source + questions must fit ~64k tokens — split long documents yourself.
|
|
226
|
+
- Sentence splitting is regex-based: abbreviations and quoted sentences can mis-split.
|
|
227
|
+
- Requires a TypeSafe API key for anything beyond `sooth demo`.
|
|
228
|
+
|
|
229
|
+
## Development
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
git clone https://github.com/naufalhilmiaji/sooth && cd sooth
|
|
233
|
+
python3 -m venv .venv && . .venv/bin/activate
|
|
234
|
+
pip install -e ".[dev]"
|
|
235
|
+
|
|
236
|
+
python3 tests/test_core.py # pure checks, no network, under a second
|
|
237
|
+
pytest # same suite
|
|
238
|
+
bash tests/test_action.sh # GitHub Action arg wiring + fail-on policy
|
|
239
|
+
ruff check src tests # lint (CI gate)
|
|
240
|
+
|
|
241
|
+
export TYPESAFE_API_KEY=... # only for the two live layers below
|
|
242
|
+
bash tests/smoke.sh # live end-to-end, both fixtures
|
|
243
|
+
PYTHONPATH=src python3 tests/calibrate.py # live calibration, 30 labeled claims
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Docs: [PRD](https://github.com/naufalhilmiaji/sooth/blob/main/docs/PRD.md) · [Design](https://github.com/naufalhilmiaji/sooth/blob/main/docs/DESIGN.md) · [Testing](https://github.com/naufalhilmiaji/sooth/blob/main/docs/TESTING.md) · [Changelog](https://github.com/naufalhilmiaji/sooth/blob/main/CHANGELOG.md)
|
|
247
|
+
|
|
248
|
+
## Roadmap
|
|
249
|
+
|
|
250
|
+
- **v0.3.0** — `--format json`, `sooth demo --case`, Action `fail-on` + outputs
|
|
251
|
+
- **v0.2.3** shipped — GitHub Action: CI quality gate in one `uses:` line
|
|
252
|
+
- **v0.2.2** shipped — `sooth demo` (offline, no API key)
|
|
253
|
+
- **v0.2.1** shipped — source-span evidence, published on PyPI
|
|
254
|
+
- later — pluggable backends (local models), hosted web app, review queues
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
MIT © Naufal Hilmiaji. Powered by [TypeSafe](https://typesafe.ai) / Jev.
|