@pharmatools/opengate 0.1.0
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.
- package/ADAPTERS.md +145 -0
- package/LICENSE +21 -0
- package/README.md +200 -0
- package/datasets/LABELING-GUIDE.md +65 -0
- package/datasets/SCHEMA.md +17 -0
- package/datasets/cases/_template.json +27 -0
- package/datasets/cases/case-cardio-bp.json +23 -0
- package/datasets/cases/case-cardio-hf.json +21 -0
- package/datasets/cases/case-cardio-lipids.json +41 -0
- package/datasets/cases/case-derm-psoriasis.json +22 -0
- package/datasets/cases/case-diabetes-glp1.json +33 -0
- package/datasets/cases/case-endo-thyroid.json +18 -0
- package/datasets/cases/case-gastro-ibd.json +21 -0
- package/datasets/cases/case-hema-anemia.json +19 -0
- package/datasets/cases/case-hep-nash.json +19 -0
- package/datasets/cases/case-hiv-prep.json +18 -0
- package/datasets/cases/case-id-antibiotic.json +18 -0
- package/datasets/cases/case-nephro-ckd.json +21 -0
- package/datasets/cases/case-neuro-migraine.json +39 -0
- package/datasets/cases/case-neuro-ms.json +21 -0
- package/datasets/cases/case-onco-pdl1.json +21 -0
- package/datasets/cases/case-oncology-pembro.json +31 -0
- package/datasets/cases/case-osteo-fracture.json +19 -0
- package/datasets/cases/case-pain-oa.json +21 -0
- package/datasets/cases/case-psych-depression.json +19 -0
- package/datasets/cases/case-pulm-ipf.json +18 -0
- package/datasets/cases/case-resp-copd.json +35 -0
- package/datasets/cases/case-rheum-jak.json +19 -0
- package/datasets/cases/case-vaccine.json +19 -0
- package/datasets/cases/case-womens-pcos.json +21 -0
- package/datasets/cases/seed-teprotumumab.json +37 -0
- package/datasets/fixtures/citation-styles.json +22 -0
- package/opengate.http.example.json +12 -0
- package/package.json +55 -0
- package/src/adapters/http.mjs +132 -0
- package/src/adapters/refcheckr.mjs +109 -0
- package/src/index.mjs +29 -0
- package/src/lib/adapter.mjs +78 -0
- package/src/lib/citations.mjs +109 -0
- package/src/lib/metrics.mjs +104 -0
- package/src/runner.mjs +223 -0
- package/src/scorers/citation-detection.mjs +69 -0
- package/src/scorers/claim-extraction.mjs +75 -0
- package/src/scorers/verdict-accuracy.mjs +163 -0
package/ADAPTERS.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Writing an adapter
|
|
2
|
+
|
|
3
|
+
An adapter is the boundary between OpenGATE's scorers and the system under test. Scorers never make network calls directly — they call the adapter, so evaluating a new system means writing one file (or, for REST-backed systems, none: see the generic HTTP adapter below). The bundled RefCheckr adapter (`src/adapters/refcheckr.mjs`) is the reference implementation.
|
|
4
|
+
|
|
5
|
+
**The methodology travels; only the gold set changes** — and the adapter is how it travels.
|
|
6
|
+
|
|
7
|
+
## Selecting an adapter
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# default: the bundled RefCheckr adapter
|
|
11
|
+
npm run eval:online
|
|
12
|
+
|
|
13
|
+
# your own, via flag or environment variable
|
|
14
|
+
node src/runner.mjs --online --adapter ./adapters/my-system.mjs
|
|
15
|
+
OPENGATE_ADAPTER=./adapters/my-system.mjs npm run eval:online
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The `--adapter` flag takes precedence over `OPENGATE_ADAPTER`. Relative paths resolve from the current working directory. The adapter is loaded and validated before any scorer runs — a malformed adapter fails fast with a message listing every missing or mistyped export, even on offline runs.
|
|
19
|
+
|
|
20
|
+
## No-code option: the generic HTTP adapter
|
|
21
|
+
|
|
22
|
+
If your system already exposes (or can expose) endpoints speaking the contract shapes below, you don't need to write code. Describe the transport in a JSON config:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
cp opengate.http.example.json opengate.http.json # edit paths/headers
|
|
26
|
+
node src/runner.mjs --online --adapter ./src/adapters/http.mjs
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"name": "my-system",
|
|
32
|
+
"baseUrl": "${MY_SYSTEM_URL}",
|
|
33
|
+
"headers": { "Authorization": "Bearer ${MY_SYSTEM_TOKEN}" },
|
|
34
|
+
"endpoints": {
|
|
35
|
+
"splitClaims": "/api/claims/split",
|
|
36
|
+
"analyzeBatch": "/api/verify/batch"
|
|
37
|
+
},
|
|
38
|
+
"modelEnv": "MY_SYSTEM_MODEL"
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`${VAR}` placeholders are interpolated from the environment at load time; the config path defaults to `./opengate.http.json` and can be set with `OPENGATE_HTTP_CONFIG`. Latency and token capture are built in. The HTTP adapter maps *transport, not payloads* — if your API uses different request/response shapes, write a thin code adapter instead.
|
|
43
|
+
|
|
44
|
+
## The contract
|
|
45
|
+
|
|
46
|
+
### Required exports
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
/**
|
|
50
|
+
* Extract candidate claims from a document.
|
|
51
|
+
* @param {string} text — the source document (e.g. a manuscript section)
|
|
52
|
+
* @returns {Promise<{ claims: Array<string | { text, originalText?, citations? }> }>}
|
|
53
|
+
*/
|
|
54
|
+
export function splitClaims(text) {}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Verify claims against reference documents.
|
|
58
|
+
* @param {object} payload
|
|
59
|
+
* { claims: string[],
|
|
60
|
+
* documents: [{ name, type: 'text', content }],
|
|
61
|
+
* citationMapping: { [citation]: { refId } },
|
|
62
|
+
* claimCitations: [{ citations: string[] }],
|
|
63
|
+
* document_name: string }
|
|
64
|
+
* @returns {Promise<{ claims: [{ individual_analyses: [{ document_name, verdict, summary, passages }] }],
|
|
65
|
+
* usage?: { prompt_tokens, completion_tokens, reasoning_tokens, total_tokens } }>}
|
|
66
|
+
* `verdict` must be one of the six values in VERDICT_SCALE (src/lib/metrics.mjs):
|
|
67
|
+
* strong_support · partial_support · implied_by_data · overclaim · not_supported · contradicted
|
|
68
|
+
*/
|
|
69
|
+
export function analyzeBatch(payload) {}
|
|
70
|
+
|
|
71
|
+
/** True when the adapter has the config it needs (URLs, tokens, …). */
|
|
72
|
+
export function onlineAvailable() {}
|
|
73
|
+
|
|
74
|
+
/** Human-readable hint shown when onlineAvailable() is false. */
|
|
75
|
+
export function onlineConfigHint() {}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Optional exports
|
|
79
|
+
|
|
80
|
+
If absent, the loader supplies no-op defaults, so scorers can call these unconditionally. Implement them to get latency, cost, and model-comparison columns in your scorecards.
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
/** Display name for the scorecard header; defaults to the filename. */
|
|
84
|
+
export const meta = { name: 'my-system' };
|
|
85
|
+
|
|
86
|
+
/** Label for which model the deployment ran (e.g. from an env var); default null. */
|
|
87
|
+
export function runModel() {}
|
|
88
|
+
|
|
89
|
+
/** Clear latency capture; called at the start of a scorer run. */
|
|
90
|
+
export function resetTiming() {}
|
|
91
|
+
|
|
92
|
+
/** Wall-clock ms for each call made since resetTiming(); default []. */
|
|
93
|
+
export function callLatencies() {}
|
|
94
|
+
|
|
95
|
+
/** Clear token capture; called at the start of a scorer run. */
|
|
96
|
+
export function resetTokens() {}
|
|
97
|
+
|
|
98
|
+
/** Aggregated token usage since resetTokens();
|
|
99
|
+
* default { calls: 0, prompt_tokens: 0, completion_tokens: 0, reasoning_tokens: 0, total_tokens: 0 }. */
|
|
100
|
+
export function tokenTotals() {}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Minimal skeleton
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
// adapters/my-system.mjs
|
|
107
|
+
export const meta = { name: 'my-system' };
|
|
108
|
+
|
|
109
|
+
const BASE = process.env.MY_SYSTEM_URL;
|
|
110
|
+
|
|
111
|
+
export const onlineAvailable = () => Boolean(BASE);
|
|
112
|
+
export const onlineConfigHint = () => 'Set MY_SYSTEM_URL to run online scorers.';
|
|
113
|
+
|
|
114
|
+
export async function splitClaims(text) {
|
|
115
|
+
const res = await fetch(`${BASE}/extract`, {
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers: { 'Content-Type': 'application/json' },
|
|
118
|
+
body: JSON.stringify({ text }),
|
|
119
|
+
});
|
|
120
|
+
const data = await res.json();
|
|
121
|
+
return { claims: data.claims }; // map your shape to the contract
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function analyzeBatch(payload) {
|
|
125
|
+
const res = await fetch(`${BASE}/verify`, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
headers: { 'Content-Type': 'application/json' },
|
|
128
|
+
body: JSON.stringify(payload),
|
|
129
|
+
});
|
|
130
|
+
return res.json(); // must include claims[].individual_analyses[].verdict
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Run it:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
OPENGATE_ADAPTER=./adapters/my-system.mjs npm run eval:online
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Notes
|
|
141
|
+
|
|
142
|
+
- **Verdict mapping.** If your system uses a different verdict taxonomy, map it to the six-point scale inside the adapter. Adjacency accuracy assumes the scale's ordering (see `datasets/LABELING-GUIDE.md`).
|
|
143
|
+
- **Gold set.** The bundled cases are biomedical. For your domain, author your own cases in `datasets/cases/` — the format spec is `datasets/SCHEMA.md`.
|
|
144
|
+
- **Timing/token capture.** See the reference adapter for a pattern: wrap your HTTP helper to record per-call latency and any `usage` block the server returns.
|
|
145
|
+
- **Stability.** The adapter surface may still shift pre-1.0; `validateAdapter()` in `src/lib/adapter.mjs` is the source of truth.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nick Lamb (PharmaTools.AI)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# OpenGATE
|
|
2
|
+
|
|
3
|
+
[](https://github.com/nickjlamb/opengate/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
**Evidence over plausibility.**
|
|
6
|
+
|
|
7
|
+
OpenGATE is an open-source framework for evaluating evidence-grounded AI systems — systems that must justify every answer from underlying source documents. It measures one thing above all: **can the system prove its answer from the source material?**
|
|
8
|
+
|
|
9
|
+
As AI moves into high-stakes domains — healthcare, scientific publishing, regulatory, legal, finance — evaluation is becoming as fundamental as automated testing is in traditional software engineering. OpenGATE turns grounding failures into numbers you can track, and gates every prompt, model, or workflow change against a baseline so reliability can't quietly regress.
|
|
10
|
+
|
|
11
|
+
Originally developed to power [RefCheckr](https://www.pharmatools.ai/refcheckr). Designed to evaluate any AI system built on retrieved documents or reference material.
|
|
12
|
+
|
|
13
|
+
## Why not DeepEval?
|
|
14
|
+
|
|
15
|
+
Use both. General-purpose frameworks such as DeepEval and OpenAI Evals evaluate AI systems in general. OpenGATE specialises in systems that must justify every answer from evidence:
|
|
16
|
+
|
|
17
|
+
- **Provenance is first-class** — does the cited passage actually exist, verbatim, in the source?
|
|
18
|
+
- **Citation fidelity is first-class** — are the right citations detected and mapped to the right references?
|
|
19
|
+
- **Regression detection is first-class** — every run is diffed against a baseline; drops fail the build.
|
|
20
|
+
|
|
21
|
+
If your system's core promise is *grounded* answers, these aren't plugins — they're the whole evaluation. That's the niche OpenGATE fills.
|
|
22
|
+
|
|
23
|
+
## First evaluation in 60 seconds
|
|
24
|
+
|
|
25
|
+
No API key needed — the offline suite tests deterministic logic against the bundled gold set:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx @pharmatools/opengate
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or from a clone:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
git clone https://github.com/nickjlamb/opengate.git
|
|
35
|
+
cd opengate
|
|
36
|
+
npm run eval
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For programmatic use, the metric and citation primitives are importable directly:
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
import { detectCitations, verdictAccuracy, precisionRecallF1 } from '@pharmatools/opengate';
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
OpenGATE — 25 case(s), online=false, sha=eff971b
|
|
47
|
+
|
|
48
|
+
✓ citation-detection PASS
|
|
49
|
+
perClaim_exactSetRate 100.0%
|
|
50
|
+
perClaim_jaccardMean 100.0%
|
|
51
|
+
supportedStyle_accuracy 100.0%
|
|
52
|
+
⊘ claim-extraction SKIPPED — online scorer (pass --online)
|
|
53
|
+
⊘ verdict-accuracy SKIPPED — online scorer (pass --online)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
To run the online scorers against a live system (bundled RefCheckr adapter):
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
export REFCHECKR_BASE_URL=http://localhost:3848
|
|
60
|
+
export REFCHECKR_TOKEN=<a valid auth token>
|
|
61
|
+
export OPENGATE_EVAL_REPEATS=3 # optional: measure verdict consistency
|
|
62
|
+
export OPENGATE_EVAL_MODEL=sonar-pro # optional: label the model in the scorecard
|
|
63
|
+
|
|
64
|
+
npm run eval:online
|
|
65
|
+
npm run eval:baseline # save current run as the regression reference
|
|
66
|
+
npm run eval:ci # exit non-zero on any failure or metric regression
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Architecture
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
┌─────────────────────────────────┐
|
|
73
|
+
│ OpenGATE │
|
|
74
|
+
│ │
|
|
75
|
+
│ benchmark datasets (gold sets) │
|
|
76
|
+
│ scorers (one per metric family)│
|
|
77
|
+
│ scorecards (versioned, on disk)│
|
|
78
|
+
│ regression gate (CI) │
|
|
79
|
+
└───────────────┬─────────────────┘
|
|
80
|
+
│ adapters
|
|
81
|
+
┌──────────────┬───────┴──────┬──────────────┐
|
|
82
|
+
▼ ▼ ▼ ▼
|
|
83
|
+
RefCheckr Patiently AI Redacta your system
|
|
84
|
+
(first impl.) (planned) (planned) (write an adapter)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Where it sits in the development loop:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
change a prompt, model, or pipeline
|
|
91
|
+
↓
|
|
92
|
+
run OpenGATE
|
|
93
|
+
↓
|
|
94
|
+
metrics vs baseline?
|
|
95
|
+
↙ ↘
|
|
96
|
+
▲ improved ▼ regressed
|
|
97
|
+
deploy investigate (build fails in CI)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Core concepts
|
|
101
|
+
|
|
102
|
+
**Gold cases** — hand-labelled benchmark cases (`datasets/cases/`): source text, the claims that should be extracted, the sentences that should *not* be, and reference snippets with known-correct verdicts. Copy `_template.json` to add one; format spec in `datasets/SCHEMA.md`, labelling rules in `datasets/LABELING-GUIDE.md`.
|
|
103
|
+
|
|
104
|
+
**Scorers** — one module per metric family (`src/scorers/`):
|
|
105
|
+
|
|
106
|
+
| Scorer | Mode | Metrics |
|
|
107
|
+
|---|---|---|
|
|
108
|
+
| `citation-detection` | offline | per-claim citation set exact-match & Jaccard; supported-style accuracy; tracked known-gap styles |
|
|
109
|
+
| `claim-extraction` | online | precision / recall / F1 vs gold; non-claim leakage; citation agreement; **fidelity** (extracted claim is verbatim from source) |
|
|
110
|
+
| `verdict-accuracy` | online | exact & adjacency accuracy on a six-point support scale; confusion matrix; **passage hallucination rate**; consistency across repeats; per-claim latency (p50/p95) and token usage for real cost/claim |
|
|
111
|
+
|
|
112
|
+
Offline scorers run with no API key — fast enough for every commit. Online scorers exercise a live system through an adapter.
|
|
113
|
+
|
|
114
|
+
**Scorecards** — every run writes `results/<timestamp>.json` stamped with the git SHA, so any result is reproducible and auditable. Per-model runs carry a `run_model` label, turning the results directory into a measured model comparison (accuracy × hallucination × latency × cost).
|
|
115
|
+
|
|
116
|
+
**Regression gate** — `--baseline` saves a reference; subsequent runs print per-metric deltas (▲/▼ in percentage points) and `--ci` fails the build on any drop. No change ships without proving it didn't make the system less reliable.
|
|
117
|
+
|
|
118
|
+
## Adapters: evaluating your own system
|
|
119
|
+
|
|
120
|
+
Scorers never talk to a system directly — they go through an adapter, injected by the runner. The bundled `src/adapters/refcheckr.mjs` is the reference implementation; select your own with:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
OPENGATE_ADAPTER=./adapters/my-system.mjs npm run eval:online
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
An adapter is one file with four required exports — `splitClaims(text)`, `analyzeBatch(payload)`, `onlineAvailable()`, `onlineConfigHint()` — plus optional timing/token/model-label hooks that unlock latency and cost columns in the scorecard. Adapters are validated at load: a malformed one fails fast with a message listing every missing export.
|
|
127
|
+
|
|
128
|
+
For REST-backed systems there's a no-code path: the bundled **generic HTTP adapter** (`src/adapters/http.mjs`) reads endpoint paths and headers from `opengate.http.json` (see `opengate.http.example.json`), with `${ENV}` interpolation and built-in latency/token capture.
|
|
129
|
+
|
|
130
|
+
Full contract, minimal skeleton, and verdict-mapping notes: **[ADAPTERS.md](ADAPTERS.md)**.
|
|
131
|
+
|
|
132
|
+
**The methodology travels; only the gold set changes.**
|
|
133
|
+
|
|
134
|
+
## CI: the GitHub Action
|
|
135
|
+
|
|
136
|
+
Use OpenGATE as a drop-in regression gate in any repository. Keep your gold set and committed `baseline.json` in your own tree; any metric that drops fails the build:
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
- uses: nickjlamb/opengate@main
|
|
140
|
+
with:
|
|
141
|
+
datasets: ./evals/datasets # your cases/ + fixtures/
|
|
142
|
+
results: ./evals/results # where baseline.json lives
|
|
143
|
+
adapter: ./evals/my-adapter.mjs # or the bundled HTTP adapter
|
|
144
|
+
online: 'true'
|
|
145
|
+
env:
|
|
146
|
+
MY_SYSTEM_URL: ${{ vars.MY_SYSTEM_URL }}
|
|
147
|
+
MY_SYSTEM_TOKEN: ${{ secrets.MY_SYSTEM_TOKEN }}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
All inputs are optional — with none, it runs the offline suite against the bundled gold set. The same overrides work locally: `--datasets <dir>` and `--results <dir>` (or `OPENGATE_DATASETS` / `OPENGATE_RESULTS`).
|
|
151
|
+
|
|
152
|
+
## Proven in production
|
|
153
|
+
|
|
154
|
+
Run against RefCheckr's gold set, OpenGATE:
|
|
155
|
+
|
|
156
|
+
- surfaced a **silent parse-failure mode** affecting ~50% of multi-claim verdicts, eliminated with enforced structured output (→ 0);
|
|
157
|
+
- **halved passage hallucination** (5.8% → 2.4%) by driving a measured production model change — a decision made on numbers, not reputation;
|
|
158
|
+
- holds claim extraction at **~0.95 F1** with near-full recall.
|
|
159
|
+
|
|
160
|
+
Full methodology and the model comparison: [how RefCheckr is evaluated](https://www.pharmatools.ai/refcheckr-eval).
|
|
161
|
+
|
|
162
|
+
## Layout
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
opengate/
|
|
166
|
+
datasets/
|
|
167
|
+
cases/ gold-labelled source sections (copy _template.json to add)
|
|
168
|
+
fixtures/ citation-style coverage fixture
|
|
169
|
+
SCHEMA.md case format spec
|
|
170
|
+
LABELING-GUIDE.md
|
|
171
|
+
src/
|
|
172
|
+
lib/ metrics.mjs (PRF1, Jaccard, verdict accuracy, confusion matrix)
|
|
173
|
+
citations.mjs (reference impl of deterministic citation logic)
|
|
174
|
+
scorers/ one file per metric family
|
|
175
|
+
adapters/ system-under-test boundary (refcheckr.mjs is the reference)
|
|
176
|
+
runner.mjs CLI: discover cases → run scorers → report → snapshot → regression-check
|
|
177
|
+
results/ timestamped run snapshots + baseline.json
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Roadmap
|
|
181
|
+
|
|
182
|
+
- **Second adapter** — Patiently AI (faithfulness evaluation for patient-language simplification)
|
|
183
|
+
- **Author-year in RefCheckr production** — `detectAuthorYear()` now lands "Smith 2020"-style keys in the reference implementation; adopting them in RefCheckr's numeric-keyed citation mapping is tracked separately
|
|
184
|
+
- **Number-adjacent superscript** — `week 24.1` is genuinely ambiguous with decimals; remains a tracked known gap
|
|
185
|
+
- **Growing gold set** — more domains, all six verdict types, real-world reference material
|
|
186
|
+
- **Stable adapter surface** — the contract may still shift pre-1.0; semver will signal breaking changes
|
|
187
|
+
|
|
188
|
+
## Contributing
|
|
189
|
+
|
|
190
|
+
Contributions are welcome, particularly:
|
|
191
|
+
|
|
192
|
+
- **Gold cases** — new domains and citation styles (see `datasets/LABELING-GUIDE.md`)
|
|
193
|
+
- **Adapters** — connect OpenGATE to your evidence-grounded system
|
|
194
|
+
- **Scorers** — new metric families that fit the gold-case format
|
|
195
|
+
|
|
196
|
+
Open an issue to discuss before large changes. Interfaces — particularly the adapter surface — may still shift pre-1.0.
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
[MIT](LICENSE) — because evaluation frameworks shouldn't be black boxes. If an evaluation influences deployment decisions, engineers should be able to inspect every scorer, metric, and benchmark.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Verdict labeling guide
|
|
2
|
+
|
|
3
|
+
The rubric every gold case is labeled against. The goal is **one consistent, defensible standard** so the benchmark measures the system, not the annotator's mood. Each `goldVerdict` is a judgment of one claim against **one specific reference snippet** — never against real-world truth or the wider literature. The only question is: *does this reference support this claim, and how?*
|
|
4
|
+
|
|
5
|
+
## The six verdicts
|
|
6
|
+
|
|
7
|
+
| Verdict | Use when |
|
|
8
|
+
|---|---|
|
|
9
|
+
| **strong_support** | The reference **explicitly states** the claim in narrative text, and the claim does not exceed it. There is at least one verbatim sentence a reviewer could quote. |
|
|
10
|
+
| **partial_support** | **Part** of the claim is explicitly supported; another part is not addressed or only weakly supported. Typical for compound claims (A and B, where A holds and B doesn't). |
|
|
11
|
+
| **implied_by_data** | The claim follows from **data** (a table, figure, or numbers) but **no narrative sentence states it**. The numbers clearly imply the claim. |
|
|
12
|
+
| **overclaim** | The reference supports a **weaker or narrower** version of the claim, but the claim **overstates** it — asserting significance the reference doesn't establish, a larger magnitude, a broader population/endpoint, or greater certainty — **and the reference does not explicitly deny the overstated part**. Direction is right; strength/scope is too much. |
|
|
13
|
+
| **not_supported** | The reference **does not address** the claim — no evidence for or against. Includes "population excluded / endpoint not evaluated / not reported." |
|
|
14
|
+
| **contradicted** | The reference **explicitly states the opposite** of, or directly negates, the claim — including explicitly saying an effect was **not** significant when the claim asserts significance, or that an outcome did **not** occur when the claim asserts it did. |
|
|
15
|
+
|
|
16
|
+
## Decision rules (the tie-breakers)
|
|
17
|
+
|
|
18
|
+
These are the boundaries the v0.1 run showed were fuzzy. Apply them in order.
|
|
19
|
+
|
|
20
|
+
1. **overclaim vs contradicted** — *Did the reference explicitly negate the over-asserted element?*
|
|
21
|
+
- The reference says the opposite of the specific assertion (e.g. claim: "significantly reduced X"; reference: "X was **not** significantly reduced") → **contradicted**.
|
|
22
|
+
- The reference is merely **silent** on the over-asserted element (e.g. claim asserts significance; reference reports the effect size but never mentions significance) → **overclaim**.
|
|
23
|
+
|
|
24
|
+
2. **not_supported vs contradicted** — *Is the reference silent, or opposite?*
|
|
25
|
+
- Silent on the claim → **not_supported**.
|
|
26
|
+
- States the opposite → **contradicted**.
|
|
27
|
+
|
|
28
|
+
3. **not_supported vs overclaim** — *Is there support for even a weaker version?*
|
|
29
|
+
- No support for any version of the claim → **not_supported**.
|
|
30
|
+
- Supports a weaker/narrower version but the claim overstates it → **overclaim**.
|
|
31
|
+
|
|
32
|
+
4. **strong_support vs partial_support** — Entire claim explicitly supported → **strong**. Only part → **partial**.
|
|
33
|
+
|
|
34
|
+
5. **implied_by_data vs strong_support** — A narrative sentence states it → **strong**. Only the data/table shows it → **implied_by_data**.
|
|
35
|
+
|
|
36
|
+
## Worked examples
|
|
37
|
+
|
|
38
|
+
- Claim "reduced LDL by 58% versus placebo" + ref "reduced LDL by a mean of 58% (p<0.001)" → **strong_support** (explicit, not exceeded).
|
|
39
|
+
- Claim "**significantly** reduced cardiovascular death" + ref "cardiovascular death alone was **not significantly** reduced" → **contradicted** (explicit negation of the significance claim — rule 1).
|
|
40
|
+
- Claim "X **significantly** reduced hospitalisations" + ref "hospitalisations were 18% lower with X" (no p-value, significance never mentioned) → **overclaim** (asserts significance the ref doesn't establish and doesn't deny — rule 1).
|
|
41
|
+
- Claim "improved renal function" + ref "did not assess renal endpoints" → **not_supported** (silent — rule 2).
|
|
42
|
+
- Claim "effective in **all** patients" + ref "effective in patients with **moderate-to-severe** disease" → **overclaim** (scope broadened beyond the reference — rule 3).
|
|
43
|
+
- Claim "reduced HbA1c more than placebo" + ref = data table only (no narrative sentence) → **implied_by_data** (rule 5).
|
|
44
|
+
- Claim "reduced body weight **and** blood pressure" + ref supports weight (p<0.001) but BP "not significant" → **partial_support** (one element holds — rule 4).
|
|
45
|
+
|
|
46
|
+
## Ordinal scale (for adjacency scoring)
|
|
47
|
+
|
|
48
|
+
Verdicts are ordered by **how well the claim, as written, is borne out by the reference** — used only to compute the softer "off-by-one" adjacency metric. Exact-match remains the primary metric.
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
strong_support > partial_support > implied_by_data > overclaim > not_supported > contradicted
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Rationale: `implied_by_data` means the claim *is* supported (just via data), so it ranks above `overclaim` (partly true but overstated), which ranks above `not_supported` (no support), which ranks above `contradicted` (actively refuted). This is a judgment call — it is documented here so the adjacency metric is reproducible, not silent.
|
|
55
|
+
|
|
56
|
+
## Per-verdict gold-case field
|
|
57
|
+
|
|
58
|
+
Each `goldVerdict` may carry a short `rationale` so a reviewer can verify the label fast:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{ "claimText": "...", "citation": 1, "verdict": "overclaim",
|
|
62
|
+
"rationale": "Ref reports an 18% reduction but never states significance; claim asserts 'significantly' — overstated, not denied (rule 1)." }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The scorer ignores `rationale`; it exists purely for human verification and provenance.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Gold case schema
|
|
2
|
+
|
|
3
|
+
One JSON file per case in `datasets/cases/` (files starting with `_` are ignored, e.g. `_template.json`).
|
|
4
|
+
|
|
5
|
+
| Field | Required | Used by | Meaning |
|
|
6
|
+
|---|---|---|---|
|
|
7
|
+
| `id` | yes | all | Unique slug. |
|
|
8
|
+
| `title` / `notes` | no | — | Human context / provenance. |
|
|
9
|
+
| `manuscript` | yes | claim-extraction | The pasted section, with citation markers exactly as authored. |
|
|
10
|
+
| `goldClaims[]` | yes | citation-detection, claim-extraction | The verifiable claims a reviewer should extract. Each has `originalText` (with markers), `text` (clean), and `citations` (number array). |
|
|
11
|
+
| `goldNonClaims[]` | no | claim-extraction | Sentences that should **not** be extracted (background, aims, transitions). Drives precision/leakage. |
|
|
12
|
+
| `references{}` | online only | verdict-accuracy | Map of citation-number → `{ name, text }`. |
|
|
13
|
+
| `goldVerdicts[]` | online only | verdict-accuracy | `{ claimText, citation, verdict }` where `verdict` ∈ the six-point scale. Mark `_requires: "online"`. |
|
|
14
|
+
|
|
15
|
+
Verdict scale (ordered, strongest support → strongest refutation): `strong_support`, `partial_support`, `implied_by_data`, `not_supported`, `contradicted`, `overclaim`.
|
|
16
|
+
|
|
17
|
+
Offline scorers need only `manuscript` + `goldClaims`. Reference texts and gold verdicts are required solely for the online verdict scorer.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "REPLACE-with-unique-id",
|
|
3
|
+
"title": "Short human-readable title",
|
|
4
|
+
"notes": "Where this case came from, what it stresses, any caveats.",
|
|
5
|
+
|
|
6
|
+
"manuscript": "Paste the manuscript section here, with citation markers exactly as the author wrote them.",
|
|
7
|
+
|
|
8
|
+
"goldClaims": [
|
|
9
|
+
{
|
|
10
|
+
"originalText": "claim sentence WITH its citation marker, e.g. ...placebo.1,2",
|
|
11
|
+
"text": "claim sentence WITHOUT citation markers (clean form used for verification)",
|
|
12
|
+
"citations": [1, 2]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
|
|
16
|
+
"goldNonClaims": [
|
|
17
|
+
"Sentences a reviewer should NOT extract (background, aims, transitions). Used for precision."
|
|
18
|
+
],
|
|
19
|
+
|
|
20
|
+
"references": {
|
|
21
|
+
"1": { "name": "First-author Year", "text": "Optional: reference text/snippet. Needed only for online verdict accuracy." }
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
"goldVerdicts": [
|
|
25
|
+
{ "claimText": "clean claim text", "citation": 1, "verdict": "strong_support|partial_support|implied_by_data|overclaim|not_supported|contradicted", "rationale": "one line citing the LABELING-GUIDE.md rule that fixes this verdict", "_requires": "online" }
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "cardio-bp",
|
|
3
|
+
"title": "Blood pressure — clean overclaim (significance not stated)",
|
|
4
|
+
"notes": "Synthetic; controlled ground truth. Overclaim exemplar: claim asserts significance the reference reports an effect size for but never establishes. VERIFY before publishing.",
|
|
5
|
+
"manuscript": "Drug Z significantly lowered systolic blood pressure versus placebo.1 Stroke risk was reduced with Drug Z.1 Serious adverse events were comparable between groups.2 This post hoc analysis explored blood-pressure and safety outcomes.",
|
|
6
|
+
"goldClaims": [
|
|
7
|
+
{ "originalText": "Drug Z significantly lowered systolic blood pressure versus placebo.1", "text": "Drug Z significantly lowered systolic blood pressure versus placebo", "citations": [1] },
|
|
8
|
+
{ "originalText": "Stroke risk was reduced with Drug Z.1", "text": "Stroke risk was reduced with Drug Z", "citations": [1] },
|
|
9
|
+
{ "originalText": "Serious adverse events were comparable between groups.2", "text": "Serious adverse events were comparable between groups", "citations": [2] }
|
|
10
|
+
],
|
|
11
|
+
"goldNonClaims": [
|
|
12
|
+
"This post hoc analysis explored blood-pressure and safety outcomes."
|
|
13
|
+
],
|
|
14
|
+
"references": {
|
|
15
|
+
"1": { "name": "ASCEND-BP primary (Khan 2024)", "text": "In this 12-week randomised trial, 620 patients with hypertension received Drug Z or placebo; the primary endpoint was change in office systolic blood pressure. Drug Z lowered systolic blood pressure by a mean of 12 mmHg compared with placebo. Point estimates and confidence intervals for the primary endpoint are reported in the supplementary appendix. This was a short-term, surrogate-endpoint study and was not designed to assess cardiovascular outcomes such as stroke or myocardial infarction." },
|
|
16
|
+
"2": { "name": "ASCEND-BP safety", "text": "Safety was assessed in all randomised patients. Serious adverse events occurred in 4.1% of patients receiving Drug Z and 4.3% receiving placebo (p=0.78). The most common adverse events were headache and dizziness, with similar frequencies in both groups. Overall tolerability was comparable between Drug Z and placebo." }
|
|
17
|
+
},
|
|
18
|
+
"goldVerdicts": [
|
|
19
|
+
{ "claimText": "Drug Z significantly lowered systolic blood pressure versus placebo", "citation": 1, "verdict": "overclaim", "rationale": "Ref reports a 12 mmHg reduction but states no significance; claim asserts 'significantly' — overstated, not denied (rule 1)." },
|
|
20
|
+
{ "claimText": "Stroke risk was reduced with Drug Z", "citation": 1, "verdict": "not_supported", "rationale": "Ref says the trial was not designed to assess stroke — no support for any version of the stroke claim (rule 3)." },
|
|
21
|
+
{ "claimText": "Serious adverse events were comparable between groups", "citation": 2, "verdict": "strong_support", "rationale": "Ref states SAE 4.1% vs 4.3% (p=0.78) and calls tolerability comparable — explicit." }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "cardio-hf",
|
|
3
|
+
"title": "Heart failure — implied, partial, not-supported",
|
|
4
|
+
"notes": "Synthetic; controlled ground truth. VERIFY before publishing.",
|
|
5
|
+
"manuscript": "The drug lowered the rate of heart-failure hospitalisation versus placebo.1 The drug improved symptoms and reduced cardiovascular mortality.1 The drug improved renal outcomes.2",
|
|
6
|
+
"goldClaims": [
|
|
7
|
+
{ "originalText": "The drug lowered the rate of heart-failure hospitalisation versus placebo.1", "text": "The drug lowered the rate of heart-failure hospitalisation versus placebo", "citations": [1] },
|
|
8
|
+
{ "originalText": "The drug improved symptoms and reduced cardiovascular mortality.1", "text": "The drug improved symptoms and reduced cardiovascular mortality", "citations": [1] },
|
|
9
|
+
{ "originalText": "The drug improved renal outcomes.2", "text": "The drug improved renal outcomes", "citations": [2] }
|
|
10
|
+
],
|
|
11
|
+
"goldNonClaims": [],
|
|
12
|
+
"references": {
|
|
13
|
+
"1": { "name": "HF-CARE table (Bauer 2024)", "text": "In this event-driven trial, 3,800 patients with heart failure were randomised to the drug or placebo and followed for a median of 26 months. Efficacy outcomes are shown in Table 2. The rate of heart-failure hospitalisation was 9.1 per 100 patient-years with the drug and 14.7 with placebo. The KCCQ symptom score improved significantly with the drug versus placebo (p<0.001). Cardiovascular mortality did not differ significantly between the groups (hazard ratio 0.96; 95% CI 0.84-1.10)." },
|
|
14
|
+
"2": { "name": "HF-CARE renal", "text": "This pre-specified analysis focused on cardiovascular and symptom endpoints. Renal outcomes, including changes in eGFR and progression to dialysis, were not among the endpoints assessed in this study." }
|
|
15
|
+
},
|
|
16
|
+
"goldVerdicts": [
|
|
17
|
+
{ "claimText": "The drug lowered the rate of heart-failure hospitalisation versus placebo", "citation": 1, "verdict": "implied_by_data", "rationale": "Support is a data table (9.1 vs 14.7 per 100 patient-years) with no narrative sentence stating it (rule 5)." },
|
|
18
|
+
{ "claimText": "The drug improved symptoms and reduced cardiovascular mortality", "citation": 1, "verdict": "partial_support", "rationale": "Symptom (KCCQ) improvement is explicit and significant; CV mortality did not differ — compound claim, one half holds (rule 4)." },
|
|
19
|
+
{ "claimText": "The drug improved renal outcomes", "citation": 2, "verdict": "not_supported", "rationale": "Ref says renal outcomes were not assessed — silent (rule 2)." }
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "cardio-lipids",
|
|
3
|
+
"title": "Lipid lowering — overclaim and not-supported",
|
|
4
|
+
"notes": "Synthetic-but-realistic; controlled ground truth. VERIFY before publishing.",
|
|
5
|
+
"manuscript": "At week 24, treatment with alirocumab reduced LDL cholesterol by 58% versus placebo.1 Alirocumab significantly reduced the rate of cardiovascular death.1 Alirocumab also improved renal function in patients with chronic kidney disease.2 These results were observed across subgroups.",
|
|
6
|
+
"goldClaims": [
|
|
7
|
+
{
|
|
8
|
+
"originalText": "At week 24, treatment with alirocumab reduced LDL cholesterol by 58% versus placebo.1",
|
|
9
|
+
"text": "At week 24, treatment with alirocumab reduced LDL cholesterol by 58% versus placebo",
|
|
10
|
+
"citations": [1]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"originalText": "Alirocumab significantly reduced the rate of cardiovascular death.1",
|
|
14
|
+
"text": "Alirocumab significantly reduced the rate of cardiovascular death",
|
|
15
|
+
"citations": [1]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"originalText": "Alirocumab also improved renal function in patients with chronic kidney disease.2",
|
|
19
|
+
"text": "Alirocumab also improved renal function in patients with chronic kidney disease",
|
|
20
|
+
"citations": [2]
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"goldNonClaims": [
|
|
24
|
+
"These results were observed across subgroups."
|
|
25
|
+
],
|
|
26
|
+
"references": {
|
|
27
|
+
"1": {
|
|
28
|
+
"name": "ODYSSEY-LDL (Roe 2023)",
|
|
29
|
+
"text": "At week 24, alirocumab reduced LDL cholesterol by a mean of 58% relative to placebo (p<0.001). For the composite of cardiovascular death, myocardial infarction, or stroke, a numerical reduction was observed (hazard ratio 0.85; 95% CI 0.72-1.01), but the difference was not statistically significant; cardiovascular death alone was not significantly reduced."
|
|
30
|
+
},
|
|
31
|
+
"2": {
|
|
32
|
+
"name": "ODYSSEY safety appendix",
|
|
33
|
+
"text": "Adverse events were balanced between groups. Injection-site reactions were more common with alirocumab. The safety analysis did not assess renal endpoints or kidney function."
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"goldVerdicts": [
|
|
37
|
+
{ "claimText": "At week 24, treatment with alirocumab reduced LDL cholesterol by 58% versus placebo", "citation": 1, "verdict": "strong_support", "rationale": "Ref states the 58% reduction with p<0.001 explicitly; claim does not exceed it." },
|
|
38
|
+
{ "claimText": "Alirocumab significantly reduced the rate of cardiovascular death", "citation": 1, "verdict": "contradicted", "rationale": "Ref explicitly says cardiovascular death alone was NOT significantly reduced — direct negation of the significance assertion (rule 1)." },
|
|
39
|
+
{ "claimText": "Alirocumab also improved renal function in patients with chronic kidney disease", "citation": 2, "verdict": "not_supported", "rationale": "Ref states renal endpoints were not assessed — silent on the claim (rule 2)." }
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "derm-psoriasis",
|
|
3
|
+
"title": "Psoriasis — overclaim, implied, partial",
|
|
4
|
+
"notes": "Synthetic; controlled ground truth. VERIFY before publishing.",
|
|
5
|
+
"manuscript": "The biologic is effective for psoriasis of all severities.1 The biologic improved joint symptoms.2 The biologic improved nail and scalp psoriasis.3",
|
|
6
|
+
"goldClaims": [
|
|
7
|
+
{ "originalText": "The biologic is effective for psoriasis of all severities.1", "text": "The biologic is effective for psoriasis of all severities", "citations": [1] },
|
|
8
|
+
{ "originalText": "The biologic improved joint symptoms.2", "text": "The biologic improved joint symptoms", "citations": [2] },
|
|
9
|
+
{ "originalText": "The biologic improved nail and scalp psoriasis.3", "text": "The biologic improved nail and scalp psoriasis", "citations": [3] }
|
|
10
|
+
],
|
|
11
|
+
"goldNonClaims": [],
|
|
12
|
+
"references": {
|
|
13
|
+
"1": { "name": "CLEAR-PSO (Haddad 2024)", "text": "Among patients with moderate-to-severe plaque psoriasis, the biologic achieved skin clearance more often than placebo. Patients with mild psoriasis were not studied." },
|
|
14
|
+
"2": { "name": "CLEAR-PSO joint substudy", "text": "Table 4. Joint pain score change from baseline: biologic -3.1, placebo -0.8." },
|
|
15
|
+
"3": { "name": "CLEAR-PSO regional", "text": "Nail psoriasis severity improved significantly with the biologic versus placebo (p<0.01). Scalp involvement was not evaluated." }
|
|
16
|
+
},
|
|
17
|
+
"goldVerdicts": [
|
|
18
|
+
{ "claimText": "The biologic is effective for psoriasis of all severities", "citation": 1, "verdict": "overclaim", "rationale": "Ref supports moderate-to-severe only and says mild was not studied; claim broadens scope to all severities (rule 3)." },
|
|
19
|
+
{ "claimText": "The biologic improved joint symptoms", "citation": 2, "verdict": "implied_by_data", "rationale": "Support is a data table (joint pain -3.1 vs -0.8) with no narrative sentence (rule 5)." },
|
|
20
|
+
{ "claimText": "The biologic improved nail and scalp psoriasis", "citation": 3, "verdict": "partial_support", "rationale": "Nail improvement is explicit; scalp involvement was not evaluated — compound claim, one half holds (rule 4)." }
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "diabetes-glp1",
|
|
3
|
+
"title": "GLP-1 — implied-by-data and partial support",
|
|
4
|
+
"notes": "Reference 1 is data-only (table-style) with no narrative sentence stating the claim, to probe implied_by_data. Synthetic; VERIFY before publishing.",
|
|
5
|
+
"manuscript": "At week 30, semaglutide reduced HbA1c more than placebo.1 Semaglutide reduced body weight and systolic blood pressure.2",
|
|
6
|
+
"goldClaims": [
|
|
7
|
+
{
|
|
8
|
+
"originalText": "At week 30, semaglutide reduced HbA1c more than placebo.1",
|
|
9
|
+
"text": "At week 30, semaglutide reduced HbA1c more than placebo",
|
|
10
|
+
"citations": [1]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"originalText": "Semaglutide reduced body weight and systolic blood pressure.2",
|
|
14
|
+
"text": "Semaglutide reduced body weight and systolic blood pressure",
|
|
15
|
+
"citations": [2]
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"goldNonClaims": [],
|
|
19
|
+
"references": {
|
|
20
|
+
"1": {
|
|
21
|
+
"name": "SUSTAIN data table (Lin 2022)",
|
|
22
|
+
"text": "Table 2. Change from baseline at week 30. HbA1c (%): semaglutide -1.8, placebo -0.3. Fasting plasma glucose (mmol/L): semaglutide -2.6, placebo -0.4. Values are least-squares means."
|
|
23
|
+
},
|
|
24
|
+
"2": {
|
|
25
|
+
"name": "SUSTAIN secondary endpoints",
|
|
26
|
+
"text": "Semaglutide significantly reduced body weight compared with placebo (-4.5 kg vs -1.0 kg; p<0.001). Systolic blood pressure was numerically lower with semaglutide, but the change was not reported as statistically significant and confidence intervals were not provided."
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"goldVerdicts": [
|
|
30
|
+
{ "claimText": "At week 30, semaglutide reduced HbA1c more than placebo", "citation": 1, "verdict": "implied_by_data", "rationale": "Support is in a data table (-1.8 vs -0.3) with no narrative sentence stating the comparison (rule 5)." },
|
|
31
|
+
{ "claimText": "Semaglutide reduced body weight and systolic blood pressure", "citation": 2, "verdict": "partial_support", "rationale": "Weight reduction is explicit and significant; SBP change is non-significant — compound claim, one half holds (rule 4)." }
|
|
32
|
+
]
|
|
33
|
+
}
|