heor-agent-mcp 1.0.2 → 1.0.4

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 (48) hide show
  1. package/README.md +104 -14
  2. package/dist/analytics.d.ts +9 -0
  3. package/dist/analytics.d.ts.map +1 -1
  4. package/dist/analytics.js +20 -0
  5. package/dist/analytics.js.map +1 -1
  6. package/dist/formatters/comparisonMarkdown.d.ts.map +1 -1
  7. package/dist/formatters/comparisonMarkdown.js +16 -0
  8. package/dist/formatters/comparisonMarkdown.js.map +1 -1
  9. package/dist/grade/eq5dImpact.d.ts +43 -0
  10. package/dist/grade/eq5dImpact.d.ts.map +1 -0
  11. package/dist/grade/eq5dImpact.js +132 -0
  12. package/dist/grade/eq5dImpact.js.map +1 -0
  13. package/dist/grade/inconsistency.d.ts +29 -0
  14. package/dist/grade/inconsistency.d.ts.map +1 -0
  15. package/dist/grade/inconsistency.js +75 -0
  16. package/dist/grade/inconsistency.js.map +1 -0
  17. package/dist/grade/upgrading.d.ts +32 -0
  18. package/dist/grade/upgrading.d.ts.map +1 -0
  19. package/dist/grade/upgrading.js +54 -0
  20. package/dist/grade/upgrading.js.map +1 -0
  21. package/dist/network/bucher.d.ts +1 -1
  22. package/dist/network/bucher.d.ts.map +1 -1
  23. package/dist/network/bucher.js +36 -10
  24. package/dist/network/bucher.js.map +1 -1
  25. package/dist/network/consistency.d.ts +51 -0
  26. package/dist/network/consistency.d.ts.map +1 -0
  27. package/dist/network/consistency.js +83 -0
  28. package/dist/network/consistency.js.map +1 -0
  29. package/dist/network/types.d.ts +9 -0
  30. package/dist/network/types.d.ts.map +1 -1
  31. package/dist/providers/types.d.ts +11 -0
  32. package/dist/providers/types.d.ts.map +1 -1
  33. package/dist/schemas/dossierInputSchemas.d.ts +118 -0
  34. package/dist/schemas/dossierInputSchemas.d.ts.map +1 -0
  35. package/dist/schemas/dossierInputSchemas.js +59 -0
  36. package/dist/schemas/dossierInputSchemas.js.map +1 -0
  37. package/dist/server.js +21 -7
  38. package/dist/server.js.map +1 -1
  39. package/dist/tools/htaDossierPrep.d.ts.map +1 -1
  40. package/dist/tools/htaDossierPrep.js +55 -18
  41. package/dist/tools/htaDossierPrep.js.map +1 -1
  42. package/dist/tools/indirectComparison.d.ts.map +1 -1
  43. package/dist/tools/indirectComparison.js +15 -2
  44. package/dist/tools/indirectComparison.js.map +1 -1
  45. package/dist/tools/utilityValueSet.d.ts.map +1 -1
  46. package/dist/tools/utilityValueSet.js +25 -3
  47. package/dist/tools/utilityValueSet.js.map +1 -1
  48. package/package.json +1 -1
package/README.md CHANGED
@@ -12,6 +12,21 @@ Built for pharmaceutical, biotech, CRO, and medical affairs teams who need rigor
12
12
 
13
13
  ---
14
14
 
15
+ ## What's new in v1.0.4
16
+
17
+ Senior HEOR methodology + ChatGPT support:
18
+
19
+ - **GRADE inconsistency now uses I²** instead of study count. Single-study comparisons return `not_assessable` (per Cochrane 10.10) instead of being silently auto-downgraded as "Serious". Pass `heterogeneity_per_outcome` to `hta_dossier` and the Cochrane bands (50–74% Moderate, 75–89% Serious, ≥90% Very Serious) are applied directly.
20
+ - **GRADE upgrading (Guyatt 2011)** — observational evidence with strong effects can now be upgraded from Low. Three criteria via `upgrading_per_outcome`: large effect (RR <0.5/>2.0 → +1; <0.2/>5.0 → +2), dose-response (+1), plausible confounding biasing toward null (+1). Capped at +2.
21
+ - **Bucher consistency check** — when direct head-to-head A-vs-C evidence exists alongside the indirect A-vs-C estimate, `evidence_indirect` automatically tests Bucher's consistency assumption and flags violations (NICE DSU TSD 18). |z|≥1.96 = "substantial — consistency assumption appears violated."
22
+ - **EQ-5D 5L impact is baseline-utility-aware.** Biz 2026 reports category-level medians, but the new 5L value set compresses utilities in the 0.6–0.9 range — a drug for mild plaque psoriasis (baseline ~0.85) sees a much bigger ICER increase than one for severe HS (baseline ~0.45), even though both are `non_cancer_qol_only`. Pass `baseline_utility` to `utility_value_set` for a calibrated estimate.
23
+ - **ChatGPT Custom GPT support** — new OpenAPI 3.1 adapter at `/api/openapi` lets you build a Custom GPT in 5 minutes. See [ChatGPT Custom GPT](#chatgpt-custom-gpt) below.
24
+ - **Surface-tagged analytics** — every `tool_call` PostHog event now carries a `surface` property (`claude_anthropic_web` / `chatgpt_adapter` / `claude_desktop` / `direct_mcp`) so you can break down usage by client.
25
+
26
+ See [CHANGELOG.md](./CHANGELOG.md) for the full diff.
27
+
28
+ ---
29
+
15
30
  ## Quick Start
16
31
 
17
32
  ### Claude Code
@@ -45,15 +60,23 @@ Add to your MCP configuration:
45
60
 
46
61
  ---
47
62
 
48
- ## Tools
63
+ ## Tools (17)
49
64
 
50
65
  | Tool | Purpose |
51
66
  |------|---------|
52
- | `literature_search` | Search 42 data sources with a full PRISMA-style audit trail |
67
+ | `literature_search` | Search 44 data sources with a full PRISMA-style audit trail |
53
68
  | `screen_abstracts` | PICO-based relevance scoring and study design classification |
54
69
  | `risk_of_bias` | Cochrane RoB 2 / ROBINS-I / AMSTAR-2 with GRADE RoB domain summary |
55
- | `cost_effectiveness_model` | Markov / PartSA / decision-tree CEA with PSA, OWSA, CEAC, EVPI |
56
- | `hta_dossier_prep` | Draft submissions for NICE, EMA, FDA, IQWiG, HAS, and EU JCA GRADE table uses structured RoB when `rob_results` passed |
70
+ | `evidence_network` | Build treatment comparison network and assess NMA feasibility |
71
+ | `evidence_indirect` | Bucher and frequentist NMA with **automatic consistency check** vs direct h2h evidence (NICE DSU TSD 18) |
72
+ | `population_adjusted_comparison` | MAIC and STC for population-adjusted indirect comparisons |
73
+ | `survival_fitting` | Fit 5 parametric distributions to KM data (NICE DSU TSD 14) |
74
+ | `itc_feasibility` | Assess the 3-assumption ITC framework and recommend Bucher / NMA / MAIC / STC / ML-NMR |
75
+ | `cost_effectiveness_model` | Markov / PartSA / decision-tree CEA with PSA, OWSA, CEAC, EVPI, EVPPI; QALY + evLYG support |
76
+ | `budget_impact_model` | ISPOR-compliant BIA with year-by-year output and treatment-displacement modelling |
77
+ | `hta_dossier` | Draft submissions for NICE, EMA, FDA, IQWiG, HAS, and EU JCA — GRADE table uses structured RoB when `rob_results` passed; **inconsistency uses I² when `heterogeneity_per_outcome` passed**; **GRADE upgrading (Guyatt 2011) supported via `upgrading_per_outcome`** |
78
+ | `utility_value_set` | EQ-5D-3L / 5L value-set reference + **baseline-utility-aware** Biz 2026 ICER impact estimator (UK 5L transition) |
79
+ | `validate_links` | HTTP validation of citation URLs before presentation |
57
80
  | `project_create` | Initialize a persistent project workspace |
58
81
  | `knowledge_search` | Full-text search across a project's raw/ and wiki/ trees |
59
82
  | `knowledge_read` | Read any file from a project's knowledge base |
@@ -61,7 +84,7 @@ Add to your MCP configuration:
61
84
 
62
85
  ### `literature_search`
63
86
 
64
- Searches across 42 sources in parallel. Every call returns a **source selection table** showing which of the 42 sources were used and why — essential for HTA audit trails.
87
+ Searches across 44 sources in parallel. Every call returns a **source selection table** showing which of the 44 sources were used and why — essential for HTA audit trails.
65
88
 
66
89
  **Example call:**
67
90
  ```json
@@ -197,7 +220,7 @@ This single prompt exercises: `project_create` → `literature_search` → `scre
197
220
 
198
221
  ## Data Sources
199
222
 
200
- **42 sources across 9 categories.** Every `literature_search` call includes a source selection table showing used/not-used status and reason for each.
223
+ **44 sources across 10 categories.** Every `literature_search` call includes a source selection table showing used/not-used status and reason for each.
201
224
 
202
225
  <details>
203
226
  <summary><b>Biomedical & Clinical Trials (5)</b></summary>
@@ -270,9 +293,11 @@ This single prompt exercises: `project_create` → `literature_search` → `scre
270
293
  </details>
271
294
 
272
295
  <details>
273
- <summary><b>Other (1)</b></summary>
296
+ <summary><b>HEOR Methodology & Utility Reference (3)</b></summary>
274
297
 
275
298
  - **ISPOR** — HEOR methodology and conference abstracts
299
+ - **OHE (Office of Health Economics)** — EQ-5D value set research and HEOR methodology
300
+ - **EuroQol Group** — EQ-5D instruments, value sets, and registry
276
301
  </details>
277
302
 
278
303
  ---
@@ -293,7 +318,7 @@ DOCX files are saved to `~/.heor-agent/projects/{project}/reports/` (when a proj
293
318
 
294
319
  Every tool call returns a full audit record:
295
320
 
296
- - **Source selection table** — all 42 sources with used/not-used and reason
321
+ - **Source selection table** — all 44 sources with used/not-used and reason
297
322
  - **Sources queried** — queries sent, response counts, status, latency
298
323
  - **Inclusions / exclusions** — counts with reasons
299
324
  - **Methodology** — PRISMA-style for literature, ISPOR/NICE for economics
@@ -333,10 +358,11 @@ A companion chat interface is available at:
333
358
 
334
359
  **https://web-michael-ns-projects.vercel.app**
335
360
 
336
- - Chat with Claude Opus 4.6 + all 7 HEOR tools
361
+ - Chat with Claude Sonnet 4.6 + all 17 HEOR tools
337
362
  - **BYOK (Bring Your Own Key)** — paste your Anthropic API key in the settings; it stays in your browser's localStorage and is never stored on our servers
338
- - Markdown rendering with styled tables, tool call cards with live progress timers
339
- - Example prompts for common HEOR workflows
363
+ - Markdown rendering with styled tables, tool call cards with live progress timers, and theme-aware mermaid network diagrams
364
+ - 12 example prompts covering literature search, CEA, BIA, NMA, ITC feasibility, RoB, EQ-5D 5L, EU JCA dossiers
365
+ - Per-request MCP sessions (no cross-user session bleed)
340
366
 
341
367
  The web UI calls the hosted MCP server on Railway for tool execution. No setup required — just add your API key and start querying.
342
368
 
@@ -353,6 +379,70 @@ Set `MCP_SERVER_URL` to point to your own MCP server instance (default: the publ
353
379
 
354
380
  ---
355
381
 
382
+ ## ChatGPT Custom GPT
383
+
384
+ HEORAgent can also be used as a ChatGPT Custom GPT Action — useful when you (or your team) prefer the ChatGPT interface or have a ChatGPT Plus/Team account but no Anthropic API access.
385
+
386
+ The web tier exposes an OpenAPI 3.1 adapter at `/api/openapi`, with one POST endpoint per tool at `/api/v1/{tool_name}`. ChatGPT speaks this contract natively.
387
+
388
+ ### What's different from the Anthropic surface
389
+
390
+ | | Web UI / MCP / Claude Desktop | ChatGPT Custom GPT |
391
+ |---|---|---|
392
+ | Streaming | yes (SSE) | no (45s single response) |
393
+ | `psa_iterations` | up to 10,000 | capped to 1,000 (CEA) / 500 (BIA) |
394
+ | `literature_search.runs` | 1–5 | capped to 1 |
395
+ | `literature_search.max_results` | up to 100 | capped to 30 |
396
+ | Auth model | BYOK Anthropic | optional `X-API-Key` header (server-side `CHATGPT_ADAPTER_TOKEN`) |
397
+ | Surface label in PostHog | `claude_anthropic_web` / `claude_desktop` | `chatgpt_adapter` |
398
+
399
+ The caps exist because ChatGPT Actions hard-fail at the 45-second response timeout. PSA, multi-run literature search, and full max_results would routinely exceed it. The web UI and MCP clients are unaffected.
400
+
401
+ ### Build a Custom GPT (ChatGPT Plus / Team required)
402
+
403
+ 1. Visit [chatgpt.com/gpts/editor](https://chatgpt.com/gpts/editor) and click **Create**.
404
+ 2. **Configure** tab — fill in name (e.g., "HEORAgent"), description, and conversation starters. Paste the system prompt from `web/lib/claude.ts` (or write your own — the tool descriptions are self-documenting).
405
+ 3. **Actions** → **Create new action** → **Import from URL** → paste:
406
+ ```
407
+ https://web-michael-ns-projects.vercel.app/api/openapi
408
+ ```
409
+ ChatGPT auto-imports all 17 endpoints with their schemas.
410
+ 4. **Authentication** — choose **None** for the open public endpoint, or **API Key** with the `CHATGPT_ADAPTER_TOKEN` value if you've configured one (recommended for prod).
411
+ 5. **Privacy policy URL** — required by GPT Store. Use the web UI's privacy URL or your own.
412
+ 6. **Test** in the playground (right pane), then **Publish** → "Anyone with the link" or "GPT Store".
413
+
414
+ ### Securing the adapter for production
415
+
416
+ By default the `/api/v1/*` endpoint is open. Two layers of protection are recommended for any public-facing GPT:
417
+
418
+ ```bash
419
+ # 1. Token-gate the endpoint
420
+ cd web
421
+ vercel env add CHATGPT_ADAPTER_TOKEN production # generate a long random token
422
+ # Configure the same token in your Custom GPT under Authentication → API Key
423
+
424
+ # 2. Built-in rate limit
425
+ # 60 req/min per IP is enforced automatically (lib/rateLimit.ts).
426
+ # For multi-region/high-traffic prod, swap in @upstash/ratelimit + Vercel KV.
427
+ ```
428
+
429
+ ### Sample call (manual, no GPT needed)
430
+
431
+ ```bash
432
+ curl -X POST https://web-michael-ns-projects.vercel.app/api/v1/utility_value_set \
433
+ -H "Content-Type: application/json" \
434
+ -d '{
435
+ "action": "estimate_impact",
436
+ "indication_type": "non_cancer_qol_only",
437
+ "baseline_utility": 0.85,
438
+ "base_icer": 30000
439
+ }'
440
+ ```
441
+
442
+ Returns the Biz 2026 baseline-utility-adjusted ICER projection (the new EQ-5D 5L impact estimator).
443
+
444
+ ---
445
+
356
446
  ## HTTP Transport
357
447
 
358
448
  The server supports both **stdio** (default, for local MCP clients) and **Streamable HTTP** (for hosted deployment).
@@ -379,7 +469,7 @@ HTTP endpoints:
379
469
  git clone https://github.com/neptun2000/heor-agent-mcp
380
470
  cd heor-agent-mcp
381
471
  npm install
382
- npm test # 244 tests across 66 suites
472
+ npm test # 401 tests across 84 suites
383
473
  npm run build # Compile TypeScript to dist/
384
474
  npm run dev # Run with tsx (no build step)
385
475
  ```
@@ -398,10 +488,10 @@ npm run dev # Run with tsx (no build step)
398
488
  ┌────────────────▼──────────────────────────┐
399
489
  │ heor-agent-mcp server │
400
490
  │ ┌──────────────────────────────────────┐ │
401
- │ │ 7 MCP tools (Zod-validated) │ │
491
+ │ │ 17 MCP tools (Zod-validated) │ │
402
492
  │ ├──────────────────────────────────────┤ │
403
493
  │ │ DirectProvider (default) │ │
404
- │ │ ├─ 42 source fetchers │ │
494
+ │ │ ├─ 44 source fetchers │ │
405
495
  │ │ ├─ Audit builder + PRISMA trail │ │
406
496
  │ │ ├─ Markov / PartSA economic models │ │
407
497
  │ │ ├─ Markdown + DOCX formatters │ │
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Map MCP `clientInfo.name` (set by the calling client during initialize)
3
+ * to a canonical surface label so PostHog can distinguish events from
4
+ * Claude Desktop, the Vercel web UI, the ChatGPT Custom GPT adapter, etc.
5
+ *
6
+ * Returns "direct_mcp" for unknown / npx / third-party clients.
7
+ */
8
+ export type ClientSurface = "claude_anthropic_web" | "chatgpt_adapter" | "claude_desktop" | "smithery" | "glama" | "pulsemcp" | "direct_mcp";
9
+ export declare function inferSurface(clientName: string | undefined): ClientSurface;
1
10
  export declare function trackEvent(event: string, properties?: Record<string, unknown>, sessionId?: string): void;
2
11
  export declare function trackToolCall(toolName: string, durationMs: number, status: "ok" | "error", sessionId?: string, properties?: Record<string, unknown>): void;
3
12
  export declare function trackSession(event: "session_start" | "session_end", sessionId: string, properties?: Record<string, unknown>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAgBA,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACxC,SAAS,CAAC,EAAE,MAAM,QAanB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,IAAI,GAAG,OAAO,EACtB,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,QAQzC;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,eAAe,GAAG,aAAa,EACtC,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,QAGzC;AAED,wBAAsB,iBAAiB,kBAKtC"}
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,MAAM,aAAa,GACrB,sBAAsB,GACtB,iBAAiB,GACjB,gBAAgB,GAChB,UAAU,GACV,OAAO,GACP,UAAU,GACV,YAAY,CAAC;AAEjB,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAe1E;AAgBD,wBAAgB,UAAU,CACxB,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACxC,SAAS,CAAC,EAAE,MAAM,QAanB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,IAAI,GAAG,OAAO,EACtB,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,QAYzC;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,eAAe,GAAG,aAAa,EACtC,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,QAGzC;AAED,wBAAsB,iBAAiB,kBAKtC"}
package/dist/analytics.js CHANGED
@@ -1,4 +1,24 @@
1
1
  import { PostHog } from "posthog-node";
2
+ export function inferSurface(clientName) {
3
+ if (!clientName)
4
+ return "direct_mcp";
5
+ const n = clientName.toLowerCase();
6
+ if (n.startsWith("heor-web-ui"))
7
+ return "claude_anthropic_web";
8
+ if (n.startsWith("chatgpt-adapter"))
9
+ return "chatgpt_adapter";
10
+ if (n === "claude" ||
11
+ n.startsWith("claude-ai") ||
12
+ n.startsWith("claude-desktop"))
13
+ return "claude_desktop";
14
+ if (n.startsWith("smithery"))
15
+ return "smithery";
16
+ if (n.startsWith("glama"))
17
+ return "glama";
18
+ if (n.startsWith("pulsemcp"))
19
+ return "pulsemcp";
20
+ return "direct_mcp";
21
+ }
2
22
  let client = null;
3
23
  function getClient() {
4
24
  if (client)
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,IAAI,MAAM,GAAmB,IAAI,CAAC;AAElC,SAAS,SAAS;IAChB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACxC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;QACxB,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,CAAC;QACV,aAAa,EAAE,KAAK;KACrB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,KAAa,EACb,aAAsC,EAAE,EACxC,SAAkB;IAElB,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE;QAAE,OAAO;IAEhB,EAAE,CAAC,OAAO,CAAC;QACT,UAAU,EAAE,SAAS,IAAI,WAAW;QACpC,KAAK;QACL,UAAU,EAAE;YACV,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,SAAS;YAC5D,GAAG,UAAU;SACd;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,QAAgB,EAChB,UAAkB,EAClB,MAAsB,EACtB,SAAkB,EAClB,aAAsC,EAAE;IAExC,UAAU,CAAC,WAAW,EAAE;QACtB,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,UAAU;QACvB,MAAM;QACN,GAAG,UAAU;KACd,EAAE,SAAS,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,KAAsC,EACtC,SAAiB,EACjB,aAAsC,EAAE;IAExC,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAkBvC,MAAM,UAAU,YAAY,CAAC,UAA8B;IACzD,IAAI,CAAC,UAAU;QAAE,OAAO,YAAY,CAAC;IACrC,MAAM,CAAC,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IACnC,IAAI,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,sBAAsB,CAAC;IAC/D,IAAI,CAAC,CAAC,UAAU,CAAC,iBAAiB,CAAC;QAAE,OAAO,iBAAiB,CAAC;IAC9D,IACE,CAAC,KAAK,QAAQ;QACd,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC;QACzB,CAAC,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAE9B,OAAO,gBAAgB,CAAC;IAC1B,IAAI,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IAChD,IAAI,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAC1C,IAAI,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,UAAU,CAAC;IAChD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,IAAI,MAAM,GAAmB,IAAI,CAAC;AAElC,SAAS,SAAS;IAChB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACxC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;QACxB,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,CAAC;QACV,aAAa,EAAE,KAAK;KACrB,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,KAAa,EACb,aAAsC,EAAE,EACxC,SAAkB;IAElB,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE;QAAE,OAAO;IAEhB,EAAE,CAAC,OAAO,CAAC;QACT,UAAU,EAAE,SAAS,IAAI,WAAW;QACpC,KAAK;QACL,UAAU,EAAE;YACV,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,SAAS;YAC5D,GAAG,UAAU;SACd;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,QAAgB,EAChB,UAAkB,EAClB,MAAsB,EACtB,SAAkB,EAClB,aAAsC,EAAE;IAExC,UAAU,CACR,WAAW,EACX;QACE,SAAS,EAAE,QAAQ;QACnB,WAAW,EAAE,UAAU;QACvB,MAAM;QACN,GAAG,UAAU;KACd,EACD,SAAS,CACV,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,KAAsC,EACtC,SAAiB,EACjB,aAAsC,EAAE;IAExC,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"comparisonMarkdown.d.ts","sourceRoot":"","sources":["../../src/formatters/comparisonMarkdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAYpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,wBAAwB,GAAG,MAAM,CAqG7E"}
1
+ {"version":3,"file":"comparisonMarkdown.d.ts","sourceRoot":"","sources":["../../src/formatters/comparisonMarkdown.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAYpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,wBAAwB,GAAG,MAAM,CA2H7E"}
@@ -47,6 +47,22 @@ export function comparisonToMarkdown(result) {
47
47
  lines.push(`| ${e.intervention} vs ${e.comparator} | ${est} | ${ci} | ${p} | ${via} | ${method} |`);
48
48
  }
49
49
  lines.push("");
50
+ // Bucher consistency check (when direct h2h evidence available)
51
+ const conflicts = estimates.filter((e) => e.consistency_check && e.consistency_check.severity !== "none");
52
+ if (conflicts.length > 0) {
53
+ lines.push("**Bucher consistency check (direct vs indirect):**");
54
+ lines.push("");
55
+ for (const e of conflicts) {
56
+ const c = e.consistency_check;
57
+ const icon = c.severity === "substantial"
58
+ ? "🚨"
59
+ : c.severity === "moderate"
60
+ ? "⚠️"
61
+ : "ℹ️";
62
+ lines.push(`${icon} **${e.intervention} vs ${e.comparator}** (severity: ${c.severity}): ${c.rationale}`);
63
+ }
64
+ lines.push("");
65
+ }
50
66
  }
51
67
  // Heterogeneity statistics (I², Cochran Q)
52
68
  if (result.heterogeneity && result.heterogeneity.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"comparisonMarkdown.js","sourceRoot":"","sources":["../../src/formatters/comparisonMarkdown.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"comparisonMarkdown.js","sourceRoot":"","sources":["../../src/formatters/comparisonMarkdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Baseline-utility-aware EQ-5D 3L→5L impact estimator.
3
+ *
4
+ * Biz, Hernández Alava, Wailoo (2026) report category-level medians for the
5
+ * UK 3L→5L value-set transition. The new 5L value set has compressed utilities
6
+ * in mild–moderate health states relative to 3L (DSU mapping), which means
7
+ * the ICER impact of the transition depends strongly on the patient cohort's
8
+ * baseline utility:
9
+ *
10
+ * - non_cancer_qol_only: utility loss is concentrated in the 0.6–0.9 zone.
11
+ * Drugs treating MILD chronic conditions (baseline ~0.85, e.g., mild
12
+ * plaque psoriasis) see the biggest ICER increase. SEVERE versions of
13
+ * these conditions (baseline ~0.45, e.g., severe HS Hurley III) see
14
+ * less impact because patients spend more time in low-utility states
15
+ * where 5L compression is less severe.
16
+ *
17
+ * - cancer_life_extending: improvement is concentrated in severe states
18
+ * (5L assigns higher utility to the worst states than DSU mapping does),
19
+ * so a drug treating advanced/metastatic disease (baseline ~0.4) sees
20
+ * a bigger ICER decrease than one treating early-stage disease.
21
+ *
22
+ * - non_cancer_life_extending: Biz report mixed direction (7/11 decreased,
23
+ * 4/11 increased). Modulation is not defensible without the underlying
24
+ * state-by-state utility differences, so we return median + warning.
25
+ *
26
+ * The modulation factor is deliberately conservative — labelled as an
27
+ * extrapolation, not a finding from the paper. Users are advised to re-run
28
+ * their economic model with both value sets for an exact estimate.
29
+ */
30
+ import type { IndicationType } from "../data/eq5dValueSets.js";
31
+ export interface BaselineAdjustedImpact {
32
+ indication_type: IndicationType;
33
+ icer_change_pct: {
34
+ point: number;
35
+ lower: number;
36
+ upper: number;
37
+ };
38
+ is_baseline_adjusted: boolean;
39
+ baseline_utility?: number;
40
+ rationale: string;
41
+ }
42
+ export declare function estimateBaselineAdjustedImpact(indication: IndicationType, baseline_utility: number | undefined): BaselineAdjustedImpact;
43
+ //# sourceMappingURL=eq5dImpact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eq5dImpact.d.ts","sourceRoot":"","sources":["../../src/grade/eq5dImpact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D,MAAM,WAAW,sBAAsB;IACrC,eAAe,EAAE,cAAc,CAAC;IAChC,eAAe,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AA4BD,wBAAgB,8BAA8B,CAC5C,UAAU,EAAE,cAAc,EAC1B,gBAAgB,EAAE,MAAM,GAAG,SAAS,GACnC,sBAAsB,CAsFxB"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Baseline-utility-aware EQ-5D 3L→5L impact estimator.
3
+ *
4
+ * Biz, Hernández Alava, Wailoo (2026) report category-level medians for the
5
+ * UK 3L→5L value-set transition. The new 5L value set has compressed utilities
6
+ * in mild–moderate health states relative to 3L (DSU mapping), which means
7
+ * the ICER impact of the transition depends strongly on the patient cohort's
8
+ * baseline utility:
9
+ *
10
+ * - non_cancer_qol_only: utility loss is concentrated in the 0.6–0.9 zone.
11
+ * Drugs treating MILD chronic conditions (baseline ~0.85, e.g., mild
12
+ * plaque psoriasis) see the biggest ICER increase. SEVERE versions of
13
+ * these conditions (baseline ~0.45, e.g., severe HS Hurley III) see
14
+ * less impact because patients spend more time in low-utility states
15
+ * where 5L compression is less severe.
16
+ *
17
+ * - cancer_life_extending: improvement is concentrated in severe states
18
+ * (5L assigns higher utility to the worst states than DSU mapping does),
19
+ * so a drug treating advanced/metastatic disease (baseline ~0.4) sees
20
+ * a bigger ICER decrease than one treating early-stage disease.
21
+ *
22
+ * - non_cancer_life_extending: Biz report mixed direction (7/11 decreased,
23
+ * 4/11 increased). Modulation is not defensible without the underlying
24
+ * state-by-state utility differences, so we return median + warning.
25
+ *
26
+ * The modulation factor is deliberately conservative — labelled as an
27
+ * extrapolation, not a finding from the paper. Users are advised to re-run
28
+ * their economic model with both value sets for an exact estimate.
29
+ */
30
+ import { getImpactEstimate } from "../data/eq5dValueSets.js";
31
+ /**
32
+ * Modulate the published median by baseline utility.
33
+ *
34
+ * Reference baselines (calibrated so multiplier=1.0 ≈ published median):
35
+ * - non_cancer_qol_only: ref_baseline = 0.65 (typical of NICE TA dataset)
36
+ * - cancer_life_extending: ref_baseline = 0.55
37
+ *
38
+ * Linear scaling within plausible bounds (×0.4 to ×1.7) — wider than the
39
+ * IQR of the published distribution to acknowledge extrapolation uncertainty.
40
+ */
41
+ function multiplierForQolOnly(baseline) {
42
+ const ref = 0.65;
43
+ const slope = 1.5; // each +0.1 baseline → +15% multiplier
44
+ const raw = 1 + slope * (baseline - ref);
45
+ return Math.min(1.7, Math.max(0.4, raw));
46
+ }
47
+ function multiplierForCancer(baseline) {
48
+ // For cancer life-extending, a LOWER baseline means BIGGER impact (more negative %).
49
+ // ref=0.55 → multiplier=1.0
50
+ const ref = 0.55;
51
+ const slope = -2.0; // each +0.1 baseline → -20% multiplier (less impact)
52
+ const raw = 1 + slope * (baseline - ref);
53
+ return Math.min(1.7, Math.max(0.4, raw));
54
+ }
55
+ export function estimateBaselineAdjustedImpact(indication, baseline_utility) {
56
+ if (baseline_utility !== undefined) {
57
+ if (baseline_utility < 0 || baseline_utility > 1) {
58
+ throw new Error(`baseline_utility must be in [0, 1]; got ${baseline_utility}`);
59
+ }
60
+ }
61
+ const published = getImpactEstimate(indication);
62
+ // Guard: indication categories without a published median (future entries
63
+ // added before data is populated) must not silently return a degenerate
64
+ // {0, 0, 0} range. Return is_baseline_adjusted=false with an explicit
65
+ // "no estimate available" rationale so callers can branch.
66
+ if (!published) {
67
+ return {
68
+ indication_type: indication,
69
+ icer_change_pct: { point: 0, lower: 0, upper: 0 },
70
+ is_baseline_adjusted: false,
71
+ baseline_utility,
72
+ rationale: `No published impact estimate for ${indication} — this category has no Biz 2026 entry yet. Re-run your model under both value sets for a direct estimate.`,
73
+ };
74
+ }
75
+ const median = published.median_icer_change_pct;
76
+ // Range for unmodulated estimate (±25% of median to reflect inter-study spread)
77
+ const baseRange = {
78
+ point: median,
79
+ lower: median - Math.abs(median) * 0.25,
80
+ upper: median + Math.abs(median) * 0.25,
81
+ };
82
+ if (baseline_utility === undefined) {
83
+ return {
84
+ indication_type: indication,
85
+ icer_change_pct: baseRange,
86
+ is_baseline_adjusted: false,
87
+ rationale: `Published median for ${indication} (Biz et al. 2026, n=${published.examples?.length ?? 0} indication examples).`,
88
+ };
89
+ }
90
+ if (indication === "non_cancer_life_extending") {
91
+ return {
92
+ indication_type: indication,
93
+ icer_change_pct: baseRange,
94
+ is_baseline_adjusted: false,
95
+ baseline_utility,
96
+ rationale: "Mixed/heterogeneous direction in Biz 2026 (7/11 decreased, 4/11 increased) — cannot reliably modulate by baseline utility. Re-run the model with both value sets for an exact estimate.",
97
+ };
98
+ }
99
+ let multiplier;
100
+ let directionalNote;
101
+ if (indication === "non_cancer_qol_only") {
102
+ multiplier = multiplierForQolOnly(baseline_utility);
103
+ directionalNote =
104
+ baseline_utility > 0.75
105
+ ? `MILD baseline utility (${baseline_utility.toFixed(2)}) → 5L compression in mild-moderate states hits this cohort harder; expect larger ICER increase than category median.`
106
+ : baseline_utility < 0.55
107
+ ? `SEVERE baseline utility (${baseline_utility.toFixed(2)}) → patients spend more time in low-utility states where 5L compression is less severe; expect smaller ICER increase than category median.`
108
+ : `Baseline utility (${baseline_utility.toFixed(2)}) near typical NICE TA dataset average — expect impact close to published median.`;
109
+ }
110
+ else {
111
+ multiplier = multiplierForCancer(baseline_utility);
112
+ directionalNote =
113
+ baseline_utility < 0.45
114
+ ? `Advanced/metastatic disease (baseline=${baseline_utility.toFixed(2)}) — 5L assigns higher utility to severe states than DSU mapping; expect larger ICER decrease than median.`
115
+ : baseline_utility > 0.65
116
+ ? `Earlier-stage disease (baseline=${baseline_utility.toFixed(2)}) — patients spend less time in severe states; expect smaller ICER decrease than median.`
117
+ : `Baseline utility (${baseline_utility.toFixed(2)}) near typical advanced-cancer dataset average — expect impact close to published median.`;
118
+ }
119
+ const adjustedPoint = median * multiplier;
120
+ return {
121
+ indication_type: indication,
122
+ icer_change_pct: {
123
+ point: adjustedPoint,
124
+ lower: adjustedPoint - Math.abs(adjustedPoint) * 0.3,
125
+ upper: adjustedPoint + Math.abs(adjustedPoint) * 0.3,
126
+ },
127
+ is_baseline_adjusted: true,
128
+ baseline_utility,
129
+ rationale: `${directionalNote} This is an EXTRAPOLATION beyond Biz 2026 (which reports only category-level medians) — not a direct finding. Approximation: multiplier ${multiplier.toFixed(2)}× applied to published median ${median}%. Validate by re-running your model under both value sets.`,
130
+ };
131
+ }
132
+ //# sourceMappingURL=eq5dImpact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eq5dImpact.js","sourceRoot":"","sources":["../../src/grade/eq5dImpact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * GRADE Inconsistency assessment.
3
+ *
4
+ * Per Cochrane Handbook Ch. 10.10 / GRADE Handbook 5.1, inconsistency reflects
5
+ * heterogeneity of effect estimates across studies — NOT the number of studies.
6
+ *
7
+ * Single-study comparisons cannot be assessed for inconsistency; they are
8
+ * downgraded for imprecision instead. This function returns "not_assessable"
9
+ * for k=1, mapping I² bands to GRADE inconsistency levels otherwise.
10
+ *
11
+ * I² interpretation bands (Cochrane):
12
+ * 0–40% might not be important
13
+ * 30–60% moderate heterogeneity
14
+ * 50–90% substantial heterogeneity
15
+ * 75–100% considerable heterogeneity
16
+ *
17
+ * GRADE downgrade mapping:
18
+ * <50% Low (no downgrade)
19
+ * 50–75% Moderate (consider 1-step downgrade — "Serious")
20
+ * >75% Serious (1-step downgrade — "Very Serious" if ≥90%)
21
+ */
22
+ export type GradeInconsistency = "not_assessable" | "Low" | "Moderate" | "Serious" | "Very Serious";
23
+ export interface InconsistencyAssessment {
24
+ level: GradeInconsistency;
25
+ downgrade_steps: 0 | 1 | 2;
26
+ rationale: string;
27
+ }
28
+ export declare function assessInconsistency(n_studies: number, i_squared_pct: number | null): InconsistencyAssessment;
29
+ //# sourceMappingURL=inconsistency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inconsistency.d.ts","sourceRoot":"","sources":["../../src/grade/inconsistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,kBAAkB,GAC1B,gBAAgB,GAChB,KAAK,GACL,UAAU,GACV,SAAS,GACT,cAAc,CAAC;AAEnB,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,eAAe,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,uBAAuB,CAsDzB"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * GRADE Inconsistency assessment.
3
+ *
4
+ * Per Cochrane Handbook Ch. 10.10 / GRADE Handbook 5.1, inconsistency reflects
5
+ * heterogeneity of effect estimates across studies — NOT the number of studies.
6
+ *
7
+ * Single-study comparisons cannot be assessed for inconsistency; they are
8
+ * downgraded for imprecision instead. This function returns "not_assessable"
9
+ * for k=1, mapping I² bands to GRADE inconsistency levels otherwise.
10
+ *
11
+ * I² interpretation bands (Cochrane):
12
+ * 0–40% might not be important
13
+ * 30–60% moderate heterogeneity
14
+ * 50–90% substantial heterogeneity
15
+ * 75–100% considerable heterogeneity
16
+ *
17
+ * GRADE downgrade mapping:
18
+ * <50% Low (no downgrade)
19
+ * 50–75% Moderate (consider 1-step downgrade — "Serious")
20
+ * >75% Serious (1-step downgrade — "Very Serious" if ≥90%)
21
+ */
22
+ export function assessInconsistency(n_studies, i_squared_pct) {
23
+ if (n_studies <= 0) {
24
+ return {
25
+ level: "not_assessable",
26
+ downgrade_steps: 0,
27
+ rationale: "No studies — domain not assessable",
28
+ };
29
+ }
30
+ if (n_studies === 1) {
31
+ return {
32
+ level: "not_assessable",
33
+ downgrade_steps: 0,
34
+ rationale: "Single study — inconsistency not assessable (consider imprecision instead)",
35
+ };
36
+ }
37
+ if (i_squared_pct == null) {
38
+ // Was: level="Moderate", downgrade_steps=0 — internally inconsistent
39
+ // (every other Moderate path uses 1 step). Returning not_assessable
40
+ // with 0 downgrade forces an explicit manual decision instead of
41
+ // silently inflating GRADE certainty.
42
+ return {
43
+ level: "not_assessable",
44
+ downgrade_steps: 0,
45
+ rationale: "Multiple studies but I² not computed — manual heterogeneity review recommended",
46
+ };
47
+ }
48
+ if (i_squared_pct >= 90) {
49
+ return {
50
+ level: "Very Serious",
51
+ downgrade_steps: 2,
52
+ rationale: `I²=${i_squared_pct.toFixed(0)}% (considerable heterogeneity, ≥90%)`,
53
+ };
54
+ }
55
+ if (i_squared_pct >= 75) {
56
+ return {
57
+ level: "Serious",
58
+ downgrade_steps: 1,
59
+ rationale: `I²=${i_squared_pct.toFixed(0)}% (considerable heterogeneity, 75–89%)`,
60
+ };
61
+ }
62
+ if (i_squared_pct >= 50) {
63
+ return {
64
+ level: "Moderate",
65
+ downgrade_steps: 1,
66
+ rationale: `I²=${i_squared_pct.toFixed(0)}% (substantial heterogeneity, 50–74%)`,
67
+ };
68
+ }
69
+ return {
70
+ level: "Low",
71
+ downgrade_steps: 0,
72
+ rationale: `I²=${i_squared_pct.toFixed(0)}% (low heterogeneity, <50%)`,
73
+ };
74
+ }
75
+ //# sourceMappingURL=inconsistency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inconsistency.js","sourceRoot":"","sources":["../../src/grade/inconsistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAeH,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,aAA4B;IAE5B,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACnB,OAAO;YACL,KAAK,EAAE,gBAAgB;YACvB,eAAe,EAAE,CAAC;YAClB,SAAS,EAAE,oCAAoC;SAChD,CAAC;IACJ,CAAC;IACD,IAAI,SAAS,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO;YACL,KAAK,EAAE,gBAAgB;YACvB,eAAe,EAAE,CAAC;YAClB,SAAS,EACP,4EAA4E;SAC/E,CAAC;IACJ,CAAC;IACD,IAAI,aAAa,IAAI,IAAI,EAAE,CAAC;QAC1B,qEAAqE;QACrE,oEAAoE;QACpE,iEAAiE;QACjE,sCAAsC;QACtC,OAAO;YACL,KAAK,EAAE,gBAAgB;YACvB,eAAe,EAAE,CAAC;YAClB,SAAS,EACP,gFAAgF;SACnF,CAAC;IACJ,CAAC;IACD,IAAI,aAAa,IAAI,EAAE,EAAE,CAAC;QACxB,OAAO;YACL,KAAK,EAAE,cAAc;YACrB,eAAe,EAAE,CAAC;YAClB,SAAS,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,sCAAsC;SAChF,CAAC;IACJ,CAAC;IACD,IAAI,aAAa,IAAI,EAAE,EAAE,CAAC;QACxB,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,eAAe,EAAE,CAAC;YAClB,SAAS,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,wCAAwC;SAClF,CAAC;IACJ,CAAC;IACD,IAAI,aAAa,IAAI,EAAE,EAAE,CAAC;QACxB,OAAO;YACL,KAAK,EAAE,UAAU;YACjB,eAAe,EAAE,CAAC;YAClB,SAAS,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,uCAAuC;SACjF,CAAC;IACJ,CAAC;IACD,OAAO;QACL,KAAK,EAAE,KAAK;QACZ,eAAe,EAAE,CAAC;QAClB,SAAS,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B;KACvE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * GRADE Upgrading assessment for observational evidence (Guyatt 2011).
3
+ *
4
+ * GRADE allows upgrading observational studies that start at "Low" certainty
5
+ * for three specific reasons:
6
+ * 1. Large magnitude of effect (RR < 0.5 or > 2.0 → +1; RR < 0.2 or > 5.0 → +2)
7
+ * 2. Dose-response gradient
8
+ * 3. Plausible confounding/bias would reduce the observed effect (i.e.,
9
+ * bias is biasing toward null, so the true effect is likely larger)
10
+ *
11
+ * Total upgrade is capped at +2 steps. Upgrading does NOT apply when the
12
+ * starting certainty is High (RCTs) — RCTs cannot be upgraded above High.
13
+ *
14
+ * Reference: Guyatt GH et al. GRADE guidelines: 9. Rating up the quality
15
+ * of evidence. J Clin Epidemiol. 2011;64(12):1311-1316.
16
+ */
17
+ export interface UpgradingInput {
18
+ /** Starting certainty before downgrades — "High" for RCTs, "Low" for observational. */
19
+ start_certainty: "High" | "Low";
20
+ /** Magnitude of effect (effect size relative to control). */
21
+ large_effect?: "none" | "large" | "very_large";
22
+ /** Documented dose-response gradient. */
23
+ dose_response?: boolean;
24
+ /** Plausible residual confounding would bias the effect toward null. */
25
+ plausible_confounding_toward_null?: boolean;
26
+ }
27
+ export interface UpgradingAssessment {
28
+ upgrade_steps: 0 | 1 | 2;
29
+ rationale: string;
30
+ }
31
+ export declare function assessUpgrading(input: UpgradingInput): UpgradingAssessment;
32
+ //# sourceMappingURL=upgrading.d.ts.map