@disclosureos/scoring 2.0.0-beta.2 → 2.0.0-beta.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0-beta.4
4
+
5
+ ### Major Changes
6
+
7
+ - Revise the V2 observable definitions and support vocabulary directly, and add shared catalog, immutable revision and term references with supplied-byte validation. Keep the chosen term separate from the subject under review and its supporting sources. Export full observable and attributed OCS origin catalogs with retained methodological context. Update enriched-observation and scoring consumers to the revised definitions. This breaks earlier beta definition and support assumptions; it does not establish an anomalous origin or turn a reported characteristic into a confirmed assessment.
8
+
9
+ ### Minor Changes
10
+
11
+ - Add optional V2 provider score policies and results with exact policy, method, input and derivation pins; distinct unavailable outcomes; provider-defined numeric grade bands and ordinal levels; and supplied-byte validation. A bounded comparison helper checks common policy, subject and input basis without executing methods, authenticating providers, assigning a universal grade or combining competing results.
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [0b00be3]
16
+ - Updated dependencies [9580e62]
17
+ - Updated dependencies [559eac9]
18
+ - Updated dependencies [5a686c1]
19
+ - Updated dependencies [813ee2c]
20
+ - Updated dependencies
21
+ - @disclosureos/records@2.0.0-beta.4
22
+ - @disclosureos/observables@2.0.0-beta.4
23
+ - @disclosureos/origins@2.0.0-beta.4
24
+ - @disclosureos/instruments@2.0.0-beta.4
25
+
26
+ ## 2.0.0-beta.3
27
+
28
+ ### Patch Changes
29
+
30
+ - Updated dependencies [4f80b20]
31
+ - @disclosureos/records@2.0.0-beta.3
32
+ - @disclosureos/instruments@2.0.0-beta.3
33
+ - @disclosureos/observables@2.0.0-beta.3
34
+ - @disclosureos/origins@2.0.0-beta.3
35
+
3
36
  ## 2.0.0-beta.2
4
37
 
5
38
  ### Patch Changes
package/README.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # @disclosureos/scoring
2
2
 
3
+ Retain provider-defined scoring policies and results, then compare only what the declared scales, criteria and inputs permit. Competing provider results remain independent.
4
+
5
+ This README describes the **2.0.0-beta.4** API. Use one exact package version
6
+ throughout an application. Check [availability](https://os.disclosure.org/v2/docs/installation)
7
+ before installing; a source branch or packed candidate is not proof of npm
8
+ publication. For a candidate that is not yet published, use the verified local
9
+ tarballs. See the [release notes](https://github.com/disclosurefoundation/disclosureos/blob/codex/beta4-release-closure/docs/releases/2.0.0-beta.4.md)
10
+ for scope and verification. Avoid unversioned installs, which can select a different
11
+ API generation through `latest`.
12
+
13
+ ## V2 entry point
14
+
15
+ Start with `@disclosureos/scoring/experimental/v2` for provider scoring and assessment summaries. Numeric grades, ordinal levels, exact inputs and policy revisions are explicit. Structural checks and bounded comparison do not execute an arbitrary provider policy, authenticate the provider or establish scientific validity. There is no universal anomaly or truth score.
16
+
17
+ [Implementation guide](https://os.disclosure.org/v2/docs/assessment) · [Availability](https://os.disclosure.org/v2/docs/installation) · [Example viewer](https://os.disclosure.org/showcase)
18
+
19
+ ## Choose a package version
20
+
21
+ Once this version is available in the registry, install it explicitly:
22
+
23
+ ```sh
24
+ npm install --save-exact @disclosureos/scoring@2.0.0-beta.4
25
+ ```
26
+
27
+ Use the same exact release for all DisclosureOS packages. Before publication,
28
+ review a verified source checkout or its locally packed artifacts. Packages are
29
+ ESM; Node.js 22 is the documented getting-started runtime.
30
+
31
+ ## Additional API reference
32
+
33
+ <details>
34
+ <summary>Earlier composition APIs and detailed source-workflow reference</summary>
35
+
36
+ The following reference retains earlier APIs and source checkpoints. It is not the
37
+ V2 first-record tutorial. Installation commands here describe the candidate API
38
+ set; use the availability guidance above until that version is published.
39
+
3
40
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
4
41
 
5
42
  Reference scoring for the [DisclosureOS](https://github.com/disclosurefoundation)
@@ -7,27 +44,12 @@ ecosystem — the **Scoring** layer. Its legacy `Observation` APIs provide:
7
44
 
8
45
  - **Population coverage** — the fraction of legacy schema field paths carrying a value.
9
46
  Presence does not establish documentation quality or analytical readiness.
10
- - **Compellingness** — *is it anomalous / non-mundane?* Derived from the observable
11
- assessments and origin classification.
47
+ - **Origin-only reference scoring** — a declared weighting of origin hypotheses. It is separate from V2 research summaries and does not establish scientific validity.
12
48
 
13
- ## The DisclosureOS model
14
-
15
- DisclosureOS is a **six-part standard**. Each part answers one question about an
16
- observation; `@disclosureos/schema` binds the package-owned pieces into one portable
17
- contract (a single TS type + JSON Schema + non-stripping parse).
49
+ **Descriptive observable support does not measure anomaly strength.** `score()` and `rankByCompellingness()` reject an observation containing any nonempty observable claim list, including `not_indicated`. They do not substitute zero, infer absence, or allow a weighting override to bypass this boundary. Use V2 attributed assessments and profile evaluation for research results.
18
50
 
19
- | Part | Package surface | Question it answers |
20
- |---|---|---|
21
- | **Records** | `@disclosureos/records` | *What was observed?* |
22
- | **Observables** | `@disclosureos/observables` | *What anomalous characteristics did it show?* |
23
- | **Origins** | `@disclosureos/origins` | *What might explain it?* |
24
- | **Claims** | `@disclosureos/records/shared` | *Who assessed it, why, and on what evidence?* |
25
- | **Scoring** | `@disclosureos/scoring` | *How complete / compelling is the case?* |
26
- | **Instruments** | `@disclosureos/instruments` | *What hardware produced the data?* |
51
+ ## The DisclosureOS model
27
52
 
28
- Supporting packages: **`@disclosureos/schema`** (the portable contract that composes the
29
- package-owned pieces), **`@disclosureos/cli`** (tooling), and **`@disclosureos/examples`**
30
- (the runnable golden path). *(You are here: **Scoring**.)*
31
53
 
32
54
  ## Consumes the foundation (does not augment it)
33
55
 
@@ -43,34 +65,30 @@ you those slots typed automatically.
43
65
  > with `pnpm --filter @disclosureos/examples golden-path`.
44
66
  >
45
67
  > **Migrating an existing dataset?** See [`examples/migration-path.ts`](../../examples/migration-path.ts)
46
- > and the [onboarding workspace](https://os.disclosure.org/onboard).
68
+ > and the [onboarding workspace](https://os.disclosure.org/v2/inspect).
47
69
 
48
70
  ## Install
49
71
 
50
72
  ```bash
51
- pnpm add @disclosureos/scoring @disclosureos/records @disclosureos/observables @disclosureos/origins zod
73
+ pnpm add @disclosureos/scoring@2.0.0-beta.4 @disclosureos/records@2.0.0-beta.4 @disclosureos/observables@2.0.0-beta.4 @disclosureos/origins@2.0.0-beta.4 zod
52
74
  ```
53
75
 
54
- ## Quick start
55
-
56
- The `getPopulationCoverage` name below requires this unreleased checkout or a future
57
- authorized release containing it. Published consumers can continue using `getCompleteness`.
76
+ ## Population coverage
58
77
 
59
78
  ```typescript
60
- import { score, getPopulationCoverage, rankByCompellingness } from '@disclosureos/scoring';
61
-
62
- const result = score(observation);
63
- // { score, range: { low, high }, contested, ... }
79
+ import { getPopulationCoverage } from '@disclosureos/scoring';
64
80
 
65
81
  const coverage = getPopulationCoverage(observation);
66
82
  // { percentage, requiredPercentage, missing, ... }
67
-
68
- const ranked = rankByCompellingness([obsA, obsB, obsC]); // most-compelling first
69
83
  ```
70
84
 
71
- Because evaluative slots hold **arrays of competing claims**, `score()` reports a
72
- `range` (the spread across claims) and a `contested` flag when evaluators disagree —
73
- not just a single point estimate.
85
+ Coverage counts populated fields. It does not certify documentation quality, anomalous behavior or readiness for an analysis. The `getPopulationCoverage` name requires this checkout or a release containing it; `getCompleteness` is the older name for the same counter.
86
+
87
+ ## Origin-only reference scorer
88
+
89
+ `score()` remains available for observations without descriptive observable claims. It evaluates declared origin hypotheses under explicit weights and reports the spread across competing classifications. `rankByCompellingness()` applies the same restriction to every input and fails the batch if a descriptive claim would be interpreted as anomaly strength.
90
+
91
+ Do not remove descriptive claims merely to obtain a score. A characteristic such as apparent hover can describe an ordinary observation; its support tier cannot answer whether the event is anomalous. This implementation retires that automatic inference. It does not introduce a replacement anomaly-scoring methodology.
74
92
 
75
93
  ## Instrument trust (calibration provenance)
76
94
 
@@ -84,8 +102,9 @@ real calibration provenance (`in_practice` / `documented` earn the most; see
84
102
  ```typescript
85
103
  import { score, calibrationTrust } from '@disclosureos/scoring';
86
104
 
87
- const result = score(observation, {
88
- evaluatorWeight: calibrationTrust(observation, [navyManifest]),
105
+ // This observation must contain no descriptive observable claim lists.
106
+ const result = score(originOnlyObservation, {
107
+ evaluatorWeight: calibrationTrust(originOnlyObservation, [sensorManifest]),
89
108
  });
90
109
  ```
91
110
 
@@ -123,6 +142,21 @@ shared inputs and differing outcome labels. It computes no aggregate score or
123
142
  confidence interval and does not certify scientific eligibility. See the
124
143
  [assessment summary guide](../../docs/experimental/assessment-summary.md).
125
144
 
126
- The additive population-coverage names are unreleased. See the [coverage guide](../../docs/experimental/population-coverage.md) for retained counting rules, denominator limits and compatibility. The existing compellingness methodology is separate from experimental v2 assessment summaries and profile completion.
145
+ The additive population-coverage names are unreleased. See the [coverage guide](../../docs/experimental/population-coverage.md) for retained counting rules, denominator limits and compatibility. Origin-only reference scoring is separate from experimental V2 assessment summaries and profile completion. Descriptive observable claims are never converted into anomaly strength.
127
146
 
128
147
  [Assessment-summary provenance and replay](../../docs/experimental/summary-provenance.md) now pin the declared history and computed summary without verifying referenced source artifacts.
148
+
149
+ ## Experimental v2 provider-authored scores (unreleased)
150
+
151
+ `ProviderScorePolicySchema` and `ProviderScoreResultSchema` retain a provider's
152
+ question, exact method revision, scale, source basis and separate derivation.
153
+ `evaluateProviderScore` validates declarations and supplied bytes without running
154
+ the method. `compareProviderScores` conservatively identifies results with the
155
+ same exact policy and source basis; it does not compute consensus or endorse a
156
+ provider. Numeric grades and ordinal levels are declared by each policy, not
157
+ universal DisclosureOS case grades.
158
+
159
+ See the [provider scoring guide](../../docs/experimental/provider-scoring.md)
160
+ and [reproducible fictional example](../../examples/provider-scoring/README.md).
161
+
162
+ </details>
@@ -55,10 +55,9 @@ declare function calibrationTrust(observation: Observation, manifests: readonly
55
55
  /** Methodology version stamped on every {@link ScoreResult}. Bump on weight/formula changes. */
56
56
  declare const SCORING_VERSION: "2.0.0";
57
57
  /**
58
- * Ordinal anomaly strength per evidentiary tier. A `confirmed` signal counts
59
- * fully; `not_indicated` contributes nothing. Multiplied by the assessment's
60
- * confidence (default 1 when unstated). Exported so consumers can render the
61
- * methodology; override semantics may come in a future minor release.
58
+ * Ordinal support-tier values retained as transparent methodology data.
59
+ * These values do not establish anomaly strength. The scorer rejects descriptive
60
+ * observable assessments rather than applying this table to the V2 vocabulary.
62
61
  */
63
62
  declare const ASSESSMENT_LEVEL_WEIGHTS: Record<AssessmentLevel, number>;
64
63
  /**
@@ -126,14 +125,10 @@ interface ScoreOptions {
126
125
  evaluatorWeight?: (claim: EvaluatorWeightInput) => number;
127
126
  }
128
127
  /**
129
- * Reference compellingness scorer. Combines the strongest technology- and
130
- * biologics-anomaly signals (from `observableAssessments`) with the confidence in
131
- * a *non-prosaic* origin classification (from `origin`), under transparent,
132
- * overridable weights. Each slot is a *list* of competing claims, so the scorer
133
- * reports a consensus `score`, the `range` of readings across claims, and whether
134
- * the case is `contested` (evaluators disagree on direction). This answers "how
135
- * strongly does this case bear on the two public questions — anomalous
136
- * tech/biologics, and a non-mundane origin?" — distinct from completeness.
128
+ * Reference scorer for origin-only inputs. Descriptive observable support tiers
129
+ * cannot supply anomaly strength, so any nonempty observable claim list is rejected.
130
+ * Use attributed V2 assessments and profile evaluation for research results.
131
+ * Rejection is not a zero score or a finding that a characteristic is absent.
137
132
  */
138
133
  declare function score(observation: Observation, options?: ScoreOptions): ScoreResult;
139
134
  interface RankedObservation<T extends Observation = Observation> {
@@ -104,29 +104,6 @@ function reduceClaims(weighted) {
104
104
  contested: anyAnomaly && anyNone
105
105
  };
106
106
  }
107
- function observableMagnitude(claim) {
108
- return ASSESSMENT_LEVEL_WEIGHTS[claim.level] * (claim.confidence ?? 1);
109
- }
110
- function domainStats(group, evaluatorWeight) {
111
- if (!group) return EMPTY_STATS;
112
- let point = 0;
113
- let low = 0;
114
- let high = 0;
115
- let contested = false;
116
- for (const claims of Object.values(group)) {
117
- if (!claims || claims.length === 0) continue;
118
- const weighted = claims.map((c) => ({
119
- magnitude: observableMagnitude(c),
120
- weight: (c.confidence ?? 1) * evaluatorWeight(c)
121
- }));
122
- const stats = reduceClaims(weighted);
123
- if (stats.point > point) point = stats.point;
124
- if (stats.low > low) low = stats.low;
125
- if (stats.high > high) high = stats.high;
126
- if (stats.contested) contested = true;
127
- }
128
- return { point, low, high, contested };
129
- }
130
107
  function originStats(origin, prefixes, evaluatorWeight) {
131
108
  if (!origin || origin.length === 0) return EMPTY_STATS;
132
109
  const weighted = origin.map((c) => ({
@@ -136,12 +113,16 @@ function originStats(origin, prefixes, evaluatorWeight) {
136
113
  return reduceClaims(weighted);
137
114
  }
138
115
  function score(observation, options) {
116
+ const assessments = observation.observableAssessments;
117
+ const hasDescriptiveClaims = [assessments?.technology, assessments?.biologics].some((group) => Object.values(group ?? {}).some((claims) => claims && claims.length > 0));
118
+ if (hasDescriptiveClaims) {
119
+ throw new Error("Descriptive observable assessments cannot produce anomaly strength. Use V2 attributed assessments and profile evaluation; this is not a zero or absent result.");
120
+ }
139
121
  const weights = options?.weights ?? DEFAULT_WEIGHTS;
140
122
  const prosaicPrefixes = options?.prosaicPrefixes ?? DEFAULT_PROSAIC_OCS_PREFIXES;
141
123
  const evaluatorWeight = options?.evaluatorWeight ?? UNIFORM_TRUST;
142
- const assessments = observation.observableAssessments;
143
- const technology = domainStats(assessments?.technology, evaluatorWeight);
144
- const biologics = domainStats(assessments?.biologics, evaluatorWeight);
124
+ const technology = EMPTY_STATS;
125
+ const biologics = EMPTY_STATS;
145
126
  const origin = originStats(observation.origin, prosaicPrefixes, evaluatorWeight);
146
127
  const totalWeight = weights.technology + weights.biologics + weights.origin;
147
128
  const combine = (t, b, o) => totalWeight > 0 ? (t * weights.technology + b * weights.biologics + o * weights.origin) / totalWeight : 0;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/compellingness/calibration.ts","../../src/compellingness/index.ts"],"names":[],"mappings":";;;;;;AAsBO,IAAM,yBAAA,GAAqD;AAAA,EAChE,UAAA,EAAY,CAAA;AAAA,EACZ,IAAA,EAAM,CAAA;AAAA,EACN,oBAAA,EAAsB,IAAA;AAAA,EACtB,WAAA,EAAa,IAAA;AAAA,EACb,UAAA,EAAY;AACd;AAiCO,SAAS,gBAAA,CACd,WAAA,EACA,SAAA,EACA,OAAA,EACyC;AACzC,EAAA,MAAM,OAAA,GAAU,SAAS,OAAA,IAAW,yBAAA;AACpC,EAAA,MAAM,IAAA,GAAO,OAAA,EAAS,eAAA,KAAoB,MAAc,CAAA,CAAA;AAGxD,EAAA,MAAM,gBAAA,uBAAuB,GAAA,EAA+B;AAC5D,EAAA,KAAA,MAAW,OAAA,IAAW,WAAA,CAAY,cAAA,EAAgB,OAAA,IAAW,EAAC,EAAG;AAC/D,IAAA,IAAI,CAAC,QAAQ,SAAA,EAAW;AACxB,IAAA,MAAM,GAAA,GAAM,cAAA,CAAe,OAAA,CAAQ,SAAS,CAAA;AAC5C,IAAA,IAAI,CAAC,GAAA,EAAK;AACV,IAAA,MAAM,QAAQ,SAAA,CACX,IAAA,CAAK,CAAC,QAAA,KAAa,SAAS,OAAA,KAAY,GAAA,CAAI,OAAO,CAAA,EAClD,QAAQ,IAAA,CAAK,CAAC,WAAW,MAAA,CAAO,EAAA,KAAO,IAAI,QAAQ,CAAA;AACvD,IAAA,MAAM,MAAA,GAAS,OAAO,WAAA,EAAa,MAAA;AACnC,IAAA,IAAI,MAAA,EAAQ,gBAAA,CAAiB,GAAA,CAAI,OAAA,CAAQ,IAAI,MAAM,CAAA;AAAA,EACrD;AAEA,EAAA,OAAO,CAAC,KAAA,KAAU;AAChB,IAAA,IAAI,SAAS,OAAA,CAAQ,UAAA;AACrB,IAAA,KAAA,MAAW,QAAA,IAAY,KAAA,CAAM,YAAA,IAAgB,EAAC,EAAG;AAC/C,MAAA,MAAM,MAAA,GAAS,iBAAiB,QAAQ,CAAA;AACxC,MAAA,IAAI,CAAC,MAAA,IAAU,MAAA,CAAO,IAAA,KAAS,QAAA,EAAU;AACzC,MAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA;AAC7C,MAAA,MAAM,SAAS,MAAA,KAAW,MAAA,GAAY,OAAA,CAAQ,UAAA,GAAa,QAAQ,MAAM,CAAA;AACzE,MAAA,IAAI,MAAA,GAAS,QAAQ,MAAA,GAAS,MAAA;AAAA,IAChC;AACA,IAAA,OAAO,IAAA,CAAK,KAAK,CAAA,GAAI,MAAA;AAAA,EACvB,CAAA;AACF;;;AChFO,IAAM,eAAA,GAAkB;AAQxB,IAAM,wBAAA,GAA4D;AAAA,EACvE,aAAA,EAAe,CAAA;AAAA,EACf,QAAA,EAAU,IAAA;AAAA,EACV,UAAA,EAAY,GAAA;AAAA,EACZ,QAAA,EAAU,IAAA;AAAA,EACV,SAAA,EAAW;AACb;AAQO,IAAM,4BAAA,GAAkD,CAAC,OAAO;AAEhE,IAAM,2BAAA,GAA8B,EACxC,MAAA,CAAO;AAAA,EACN,UAAA,EAAY,EAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,SAAS,0CAA0C,CAAA;AAAA,EACjF,SAAA,EAAW,EAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,SAAS,yCAAyC,CAAA;AAAA,EAC/E,MAAA,EAAQ,EAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,SAAS,uDAAuD;AAC5F,CAAC,CAAA,CACA,KAAK,EAAE,EAAA,EAAI,yBAAyB,CAAA,CACpC,SAAS,qGAAgG;AAYrG,IAAM,eAAA,GAAyC;AAAA,EACpD,UAAA,EAAY,IAAA;AAAA,EACZ,SAAA,EAAW,IAAA;AAAA,EACX,MAAA,EAAQ;AACV;AAEO,IAAM,iBAAA,GAAoB,EAC9B,MAAA,CAAO;AAAA,EACN,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,QAAA,CAAS,8DAAyD,CAAA;AAAA,EAClG,KAAA,EAAO,EACJ,MAAA,CAAO;AAAA,IACN,GAAA,EAAK,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,QAAA,CAAS,iFAAiF,CAAA;AAAA,IACxH,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,QAAA,CAAS,iFAAiF;AAAA,GAC1H,CAAA,CACA,QAAA;AAAA,IACC;AAAA,GAGF;AAAA,EACF,SAAA,EAAW,CAAA,CACR,OAAA,EAAQ,CACR,SAAS,mFAAmF,CAAA;AAAA,EAC/F,UAAA,EAAY,EACT,MAAA,CAAO;AAAA,IACN,UAAA,EAAY,EAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,IACnC,SAAA,EAAW,EAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,IAClC,MAAA,EAAQ,EAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA,CAAE,IAAI,CAAC;AAAA,GAChC,CAAA,CACA,QAAA,CAAS,sDAAsD,CAAA;AAAA,EAClE,OAAA,EAAS,2BAAA;AAAA,EACT,cAAA,EAAgB,CAAA,CAAE,MAAA,EAAO,CAAE,SAAS,+CAA+C;AACrF,CAAC,CAAA,CACA,KAAK,EAAE,EAAA,EAAI,eAAe,CAAA,CAC1B,SAAS,kFAAkF;AA4B9F,IAAM,gBAAgB,MAAc,CAAA;AAEpC,SAAS,SAAA,CAAU,IAAY,QAAA,EAAsC;AACnE,EAAA,OAAO,QAAA,CAAS,IAAA,CAAK,CAAC,CAAA,KAAM,EAAA,KAAO,CAAA,IAAK,EAAA,CAAG,UAAA,CAAW,CAAA,EAAG,CAAC,CAAA,CAAA,CAAG,CAAC,CAAA;AAChE;AAEA,SAAS,MAAM,CAAA,EAAmB;AAChC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,GAAG,CAAA,GAAI,GAAA;AAC/B;AAeA,IAAM,WAAA,GAA0B,EAAE,KAAA,EAAO,CAAA,EAAG,KAAK,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,SAAA,EAAW,KAAA,EAAM;AAE9E,SAAS,aAAa,QAAA,EAAkC;AACtD,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG,OAAO,WAAA;AAClC,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,GAAA,GAAM,QAAA;AACV,EAAA,IAAI,IAAA,GAAO,CAAA,QAAA;AACX,EAAA,IAAI,UAAA,GAAa,KAAA;AACjB,EAAA,IAAI,OAAA,GAAU,KAAA;AACd,EAAA,KAAA,MAAW,EAAE,SAAA,EAAW,MAAA,EAAO,IAAK,QAAA,EAAU;AAC5C,IAAA,IAAA,IAAQ,MAAA;AACR,IAAA,IAAA,IAAQ,SAAA,GAAY,MAAA;AACpB,IAAA,IAAI,SAAA,GAAY,KAAK,GAAA,GAAM,SAAA;AAC3B,IAAA,IAAI,SAAA,GAAY,MAAM,IAAA,GAAO,SAAA;AAC7B,IAAA,IAAI,SAAA,GAAY,GAAG,UAAA,GAAa,IAAA;AAAA,SAC3B,OAAA,GAAU,IAAA;AAAA,EACjB;AACA,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,IAAA,GAAO,CAAA,GAAI,IAAA,GAAO,IAAA,GAAO,CAAA;AAAA,IAChC,GAAA;AAAA,IACA,IAAA;AAAA,IACA,WAAW,UAAA,IAAc;AAAA,GAC3B;AACF;AAGA,SAAS,oBAAoB,KAAA,EAAgC;AAC3D,EAAA,OAAO,wBAAA,CAAyB,KAAA,CAAM,KAAK,CAAA,IAAK,MAAM,UAAA,IAAc,CAAA,CAAA;AACtE;AAQA,SAAS,WAAA,CACP,OACA,eAAA,EACY;AACZ,EAAA,IAAI,CAAC,OAAO,OAAO,WAAA;AACnB,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,SAAA,GAAY,KAAA;AAChB,EAAA,KAAA,MAAW,MAAA,IAAU,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA,EAAG;AACzC,IAAA,IAAI,CAAC,MAAA,IAAU,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG;AACpC,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAc,CAAC,CAAA,MAAO;AAAA,MAC5C,SAAA,EAAW,oBAAoB,CAAC,CAAA;AAAA,MAChC,MAAA,EAAA,CAAS,CAAA,CAAE,UAAA,IAAc,CAAA,IAAK,gBAAgB,CAAC;AAAA,KACjD,CAAE,CAAA;AACF,IAAA,MAAM,KAAA,GAAQ,aAAa,QAAQ,CAAA;AACnC,IAAA,IAAI,KAAA,CAAM,KAAA,GAAQ,KAAA,EAAO,KAAA,GAAQ,KAAA,CAAM,KAAA;AACvC,IAAA,IAAI,KAAA,CAAM,GAAA,GAAM,GAAA,EAAK,GAAA,GAAM,KAAA,CAAM,GAAA;AACjC,IAAA,IAAI,KAAA,CAAM,IAAA,GAAO,IAAA,EAAM,IAAA,GAAO,KAAA,CAAM,IAAA;AACpC,IAAA,IAAI,KAAA,CAAM,WAAW,SAAA,GAAY,IAAA;AAAA,EACnC;AACA,EAAA,OAAO,EAAE,KAAA,EAAO,GAAA,EAAK,IAAA,EAAM,SAAA,EAAU;AACvC;AAGA,SAAS,WAAA,CACP,MAAA,EACA,QAAA,EACA,eAAA,EACY;AACZ,EAAA,IAAI,CAAC,MAAA,IAAU,MAAA,CAAO,MAAA,KAAW,GAAG,OAAO,WAAA;AAC3C,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAc,CAAC,CAAA,MAAO;AAAA,IAC5C,WAAW,SAAA,CAAU,CAAA,CAAE,mBAAmB,QAAQ,CAAA,GAAI,IAAI,CAAA,CAAE,UAAA;AAAA,IAC5D,MAAA,EAAQ,CAAA,CAAE,UAAA,GAAa,eAAA,CAAgB,CAAC;AAAA,GAC1C,CAAE,CAAA;AACF,EAAA,OAAO,aAAa,QAAQ,CAAA;AAC9B;AAYO,SAAS,KAAA,CAAM,aAA0B,OAAA,EAAqC;AACnF,EAAA,MAAM,OAAA,GAAU,SAAS,OAAA,IAAW,eAAA;AACpC,EAAA,MAAM,eAAA,GAAkB,SAAS,eAAA,IAAmB,4BAAA;AACpD,EAAA,MAAM,eAAA,GAAkB,SAAS,eAAA,IAAmB,aAAA;AAEpD,EAAA,MAAM,cAAc,WAAA,CAAY,qBAAA;AAChC,EAAA,MAAM,UAAA,GAAa,WAAA,CAAY,WAAA,EAAa,UAAA,EAAY,eAAe,CAAA;AACvE,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,WAAA,EAAa,SAAA,EAAW,eAAe,CAAA;AACrE,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,WAAA,CAAY,MAAA,EAAQ,iBAAiB,eAAe,CAAA;AAE/E,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,UAAA,GAAa,OAAA,CAAQ,YAAY,OAAA,CAAQ,MAAA;AACrE,EAAA,MAAM,UAAU,CAAC,CAAA,EAAW,CAAA,EAAW,CAAA,KACrC,cAAc,CAAA,GAAA,CACT,CAAA,GAAI,OAAA,CAAQ,UAAA,GAAa,IAAI,OAAA,CAAQ,SAAA,GAAY,CAAA,GAAI,OAAA,CAAQ,UAAU,WAAA,GACxE,CAAA;AAEN,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,MAAM,OAAA,CAAQ,UAAA,CAAW,OAAO,SAAA,CAAU,KAAA,EAAO,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,IACrE,KAAA,EAAO;AAAA,MACL,GAAA,EAAK,MAAM,OAAA,CAAQ,UAAA,CAAW,KAAK,SAAA,CAAU,GAAA,EAAK,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,MAC7D,IAAA,EAAM,MAAM,OAAA,CAAQ,UAAA,CAAW,MAAM,SAAA,CAAU,IAAA,EAAM,MAAA,CAAO,IAAI,CAAC;AAAA,KACnE;AAAA,IACA,SAAA,EAAW,UAAA,CAAW,SAAA,IAAa,SAAA,CAAU,aAAa,MAAA,CAAO,SAAA;AAAA,IACjE,UAAA,EAAY;AAAA,MACV,UAAA,EAAY,KAAA,CAAM,UAAA,CAAW,KAAK,CAAA;AAAA,MAClC,SAAA,EAAW,KAAA,CAAM,SAAA,CAAU,KAAK,CAAA;AAAA,MAChC,MAAA,EAAQ,KAAA,CAAM,MAAA,CAAO,KAAK;AAAA,KAC5B;AAAA,IACA,OAAA;AAAA,IACA,cAAA,EAAgB;AAAA,GAClB;AACF;AAWO,SAAS,oBAAA,CACd,cACA,OAAA,EACwB;AACxB,EAAA,OAAO,YAAA,CACJ,IAAI,CAAC,WAAA,MAAiB,EAAE,WAAA,EAAa,MAAA,EAAQ,KAAA,CAAM,WAAA,EAAa,OAAO,CAAA,GAAI,CAAA,CAC3E,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,MAAA,CAAO,KAAA,GAAQ,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA;AACnD","file":"index.js","sourcesContent":["import type { Observation } from '@disclosureos/records';\nimport { parseEvidenceRef, parseSensorRef } from '@disclosureos/records/shared';\nimport type { CalibrationStatus, SensorManifest } from '@disclosureos/instruments';\nimport type { EvaluatorWeightInput } from './index';\n\n/**\n * Trust multiplier per calibration maturity level, plus the `unresolved`\n * baseline for claims whose sensor evidence does not resolve to a manifest\n * entry (no `sensorRef`, unknown org, unknown sensor, or no calibration block).\n */\nexport type CalibrationTrustWeights = Record<CalibrationStatus | 'unresolved', number>;\n\n/**\n * Conservative default gradient: instruments with real calibration provenance\n * earn *credit* over unresolved sensors — nothing is ever penalized below the\n * baseline, so adopting the hook can only reward organizations that publish\n * manifests, never punish records that predate them.\n *\n * @experimental The shape is stable; these specific values are a reference\n * policy that may be re-tuned in a minor release. Pin your own `weights` via\n * {@link CalibrationTrustOptions} if you need stable numbers.\n */\nexport const CALIBRATION_TRUST_WEIGHTS: CalibrationTrustWeights = {\n unresolved: 1,\n none: 1,\n candidate_identified: 1.05,\n in_practice: 1.15,\n documented: 1.25,\n};\n\nexport interface CalibrationTrustOptions {\n /** Override the trust gradient (defaults to {@link CALIBRATION_TRUST_WEIGHTS}). */\n weights?: CalibrationTrustWeights;\n /**\n * A base trust policy composed (multiplied) with the calibration credit —\n * e.g. an evaluator-identity policy. Defaults to uniform 1.0.\n */\n evaluatorWeight?: (claim: EvaluatorWeightInput) => number;\n}\n\n/**\n * Build an `evaluatorWeight` hook (see `ScoreOptions.evaluatorWeight`) that\n * credits claims backed by instruments with published calibration provenance.\n *\n * Resolution chain, per claim: `evidenceRefs` (`\"sensor:<id>\"`) → the\n * observation's `sensorEvidence.sensors[]` reading → its `sensorRef`\n * (`\"<org-slug>:<sensor-id>\"`) → the matching manifest entry's\n * `calibration.status`. When a claim cites several sensor readings, the\n * strongest instrument backing wins. Claims with no resolvable sensor\n * evidence get the `unresolved` baseline.\n *\n * Like every `evaluatorWeight` policy, this shifts only the consensus point\n * estimate — `range` and `contested` still report the honest spread of what\n * evaluators actually asserted.\n *\n * ```ts\n * const result = score(observation, {\n * evaluatorWeight: calibrationTrust(observation, [navyManifest]),\n * });\n * ```\n */\nexport function calibrationTrust(\n observation: Observation,\n manifests: readonly SensorManifest[],\n options?: CalibrationTrustOptions,\n): (claim: EvaluatorWeightInput) => number {\n const weights = options?.weights ?? CALIBRATION_TRUST_WEIGHTS;\n const base = options?.evaluatorWeight ?? ((): number => 1);\n\n // Pre-resolve each in-record sensor reading to its manifest calibration status.\n const statusBySensorId = new Map<string, CalibrationStatus>();\n for (const reading of observation.sensorEvidence?.sensors ?? []) {\n if (!reading.sensorRef) continue;\n const ref = parseSensorRef(reading.sensorRef);\n if (!ref) continue;\n const entry = manifests\n .find((manifest) => manifest.orgSlug === ref.orgSlug)\n ?.sensors.find((sensor) => sensor.id === ref.sensorId);\n const status = entry?.calibration?.status;\n if (status) statusBySensorId.set(reading.id, status);\n }\n\n return (claim) => {\n let credit = weights.unresolved;\n for (const evidence of claim.evidenceRefs ?? []) {\n const parsed = parseEvidenceRef(evidence);\n if (!parsed || parsed.kind !== 'sensor') continue;\n const status = statusBySensorId.get(parsed.id);\n const weight = status === undefined ? weights.unresolved : weights[status];\n if (weight > credit) credit = weight;\n }\n return base(claim) * credit;\n };\n}\n","import { z } from 'zod';\nimport type { Observation } from '@disclosureos/records';\nimport type { AssessmentLevel, ObservableClaim } from '@disclosureos/observables';\nimport type { OriginClaim } from '@disclosureos/origins';\n// Side-effect imports register the `observableAssessments` and `origin` slots on\n// `Observation` via module augmentation, so they are typed below.\nimport '@disclosureos/observables';\nimport '@disclosureos/origins';\n\nexport { calibrationTrust, CALIBRATION_TRUST_WEIGHTS } from './calibration';\nexport type { CalibrationTrustWeights, CalibrationTrustOptions } from './calibration';\n\n/** Methodology version stamped on every {@link ScoreResult}. Bump on weight/formula changes. */\nexport const SCORING_VERSION = '2.0.0' as const;\n\n/**\n * Ordinal anomaly strength per evidentiary tier. A `confirmed` signal counts\n * fully; `not_indicated` contributes nothing. Multiplied by the assessment's\n * confidence (default 1 when unstated). Exported so consumers can render the\n * methodology; override semantics may come in a future minor release.\n */\nexport const ASSESSMENT_LEVEL_WEIGHTS: Record<AssessmentLevel, number> = {\n not_indicated: 0,\n reported: 0.25,\n documented: 0.5,\n measured: 0.75,\n confirmed: 1,\n};\n\n/**\n * OCS id prefixes treated as prosaic (well-explained). A confident *prosaic*\n * classification means the case is explained, so it contributes no anomaly\n * signal. Overridable per {@link score} call. Default is the OCS \"Prosaic\"\n * branch (`1.1.1`).\n */\nexport const DEFAULT_PROSAIC_OCS_PREFIXES: readonly string[] = ['1.1.1'];\n\nexport const CompellingnessWeightsSchema = z\n .object({\n technology: z.number().min(0).describe('Weight of the technology-anomaly signal.'),\n biologics: z.number().min(0).describe('Weight of the biologics-anomaly signal.'),\n origin: z.number().min(0).describe('Weight of the (non-prosaic) origin-confidence signal.'),\n })\n .meta({ id: 'CompellingnessWeights' })\n .describe('Relative weights for the compellingness components. Need not sum to 1 — normalized internally.');\n\nexport type CompellingnessWeights = z.infer<typeof CompellingnessWeightsSchema>;\n\n/**\n * Fixed default weights, exposed as a transparent, overridable data object (not a\n * config system). Partners can propose alternate weight sets without an API change.\n *\n * @experimental The *shape* (`CompellingnessWeights`) is stable, but these specific\n * default values are a reference methodology that may be re-tuned in a minor release.\n * Pin your own `weights` via {@link ScoreOptions} if you need stable numbers.\n */\nexport const DEFAULT_WEIGHTS: CompellingnessWeights = {\n technology: 0.45,\n biologics: 0.35,\n origin: 0.2,\n};\n\nexport const ScoreResultSchema = z\n .object({\n score: z.number().min(0).max(1).describe('Overall compellingness (consensus point estimate), 0–1.'),\n range: z\n .object({\n low: z.number().min(0).max(1).describe('Most-skeptical reading of the strongest-anomaly signal across competing claims.'),\n high: z.number().min(0).max(1).describe('Most-anomalous reading of the strongest-anomaly signal across competing claims.'),\n })\n .describe(\n 'Spread of the score across competing claims — wide range signals disagreement. Bounds are '\n + 'computed per-signal under the same strongest-anomaly (max) reduction as the point estimate, '\n + 'not a global min/max over every claim.',\n ),\n contested: z\n .boolean()\n .describe('True when claims disagree on *direction* (some assert anomaly, some assert none).'),\n components: z\n .object({\n technology: z.number().min(0).max(1),\n biologics: z.number().min(0).max(1),\n origin: z.number().min(0).max(1),\n })\n .describe('Per-signal consensus contributions before weighting.'),\n weights: CompellingnessWeightsSchema,\n scoringVersion: z.string().describe('Methodology version that produced this score.'),\n })\n .meta({ id: 'ScoreResult' })\n .describe('A reference compellingness score for an observation, with a contestedness range.');\n\nexport type ScoreResult = z.infer<typeof ScoreResultSchema>;\n\n/** The minimal claim shape the trust hook sees (it never needs the full body). */\nexport type EvaluatorWeightInput = {\n evaluatedBy?: string | undefined;\n evidenceRefs?: string[] | undefined;\n};\n\nexport interface ScoreOptions {\n weights?: CompellingnessWeights;\n /** Override the prosaic OCS prefixes (defaults to {@link DEFAULT_PROSAIC_OCS_PREFIXES}). */\n prosaicPrefixes?: readonly string[];\n /**\n * Trust applied to each claim's vote in the consensus point estimate (default\n * 1.0 — uniform). This is where a future trust policy (e.g.\n * weighting verified/official evaluators higher) plugs in here without changing\n * the formula. Range/contestedness are NOT affected — they report the honest\n * spread of what evaluators actually asserted.\n *\n * @experimental The hook signature is stable, but the default trust *policy*\n * (uniform 1.0) is deliberately unopinionated and is a separate, ongoing design\n * task; a future built-in policy may change the default.\n */\n evaluatorWeight?: (claim: EvaluatorWeightInput) => number;\n}\n\nconst UNIFORM_TRUST = (): number => 1;\n\nfunction isProsaic(id: string, prefixes: readonly string[]): boolean {\n return prefixes.some((p) => id === p || id.startsWith(`${p}.`));\n}\n\nfunction round(n: number): number {\n return Math.round(n * 1e4) / 1e4;\n}\n\ntype Weighted = { magnitude: number; weight: number };\n\ninterface ClaimStats {\n /** Trust-weighted mean magnitude (the consensus point). */\n point: number;\n /** Min asserted magnitude (most skeptical). */\n low: number;\n /** Max asserted magnitude (most anomalous). */\n high: number;\n /** Claims disagree on direction (some > 0, some === 0). */\n contested: boolean;\n}\n\nconst EMPTY_STATS: ClaimStats = { point: 0, low: 0, high: 0, contested: false };\n\nfunction reduceClaims(weighted: Weighted[]): ClaimStats {\n if (weighted.length === 0) return EMPTY_STATS;\n let wsum = 0;\n let msum = 0;\n let low = Infinity;\n let high = -Infinity;\n let anyAnomaly = false;\n let anyNone = false;\n for (const { magnitude, weight } of weighted) {\n wsum += weight;\n msum += magnitude * weight;\n if (magnitude < low) low = magnitude;\n if (magnitude > high) high = magnitude;\n if (magnitude > 0) anyAnomaly = true;\n else anyNone = true;\n }\n return {\n point: wsum > 0 ? msum / wsum : 0,\n low,\n high,\n contested: anyAnomaly && anyNone,\n };\n}\n\n/** Asserted anomaly magnitude of one observable claim, in [0,1]. */\nfunction observableMagnitude(claim: ObservableClaim): number {\n return ASSESSMENT_LEVEL_WEIGHTS[claim.level] * (claim.confidence ?? 1);\n}\n\n/**\n * Strongest established anomaly within a domain — the \"is there *any* anomaly?\" reduction.\n * `point`/`low`/`high` are each a **max across observables** of that observable's claim-list\n * stat. So `low` is \"the most-skeptical reading of the strongest-anomaly observable,\" not a\n * global floor across all observables — consistent with the point estimate's max reduction.\n */\nfunction domainStats(\n group: Partial<Record<string, ObservableClaim[]>> | undefined,\n evaluatorWeight: (claim: EvaluatorWeightInput) => number,\n): ClaimStats {\n if (!group) return EMPTY_STATS;\n let point = 0;\n let low = 0;\n let high = 0;\n let contested = false;\n for (const claims of Object.values(group)) {\n if (!claims || claims.length === 0) continue;\n const weighted = claims.map<Weighted>((c) => ({\n magnitude: observableMagnitude(c),\n weight: (c.confidence ?? 1) * evaluatorWeight(c),\n }));\n const stats = reduceClaims(weighted);\n if (stats.point > point) point = stats.point;\n if (stats.low > low) low = stats.low;\n if (stats.high > high) high = stats.high;\n if (stats.contested) contested = true;\n }\n return { point, low, high, contested };\n}\n\n/** Confidence in a *non-prosaic* origin, reduced across competing classifications. */\nfunction originStats(\n origin: OriginClaim[] | undefined,\n prefixes: readonly string[],\n evaluatorWeight: (claim: EvaluatorWeightInput) => number,\n): ClaimStats {\n if (!origin || origin.length === 0) return EMPTY_STATS;\n const weighted = origin.map<Weighted>((c) => ({\n magnitude: isProsaic(c.primaryHypothesis, prefixes) ? 0 : c.confidence,\n weight: c.confidence * evaluatorWeight(c),\n }));\n return reduceClaims(weighted);\n}\n\n/**\n * Reference compellingness scorer. Combines the strongest technology- and\n * biologics-anomaly signals (from `observableAssessments`) with the confidence in\n * a *non-prosaic* origin classification (from `origin`), under transparent,\n * overridable weights. Each slot is a *list* of competing claims, so the scorer\n * reports a consensus `score`, the `range` of readings across claims, and whether\n * the case is `contested` (evaluators disagree on direction). This answers \"how\n * strongly does this case bear on the two public questions — anomalous\n * tech/biologics, and a non-mundane origin?\" — distinct from completeness.\n */\nexport function score(observation: Observation, options?: ScoreOptions): ScoreResult {\n const weights = options?.weights ?? DEFAULT_WEIGHTS;\n const prosaicPrefixes = options?.prosaicPrefixes ?? DEFAULT_PROSAIC_OCS_PREFIXES;\n const evaluatorWeight = options?.evaluatorWeight ?? UNIFORM_TRUST;\n\n const assessments = observation.observableAssessments;\n const technology = domainStats(assessments?.technology, evaluatorWeight);\n const biologics = domainStats(assessments?.biologics, evaluatorWeight);\n const origin = originStats(observation.origin, prosaicPrefixes, evaluatorWeight);\n\n const totalWeight = weights.technology + weights.biologics + weights.origin;\n const combine = (t: number, b: number, o: number): number =>\n totalWeight > 0\n ? (t * weights.technology + b * weights.biologics + o * weights.origin) / totalWeight\n : 0;\n\n return {\n score: round(combine(technology.point, biologics.point, origin.point)),\n range: {\n low: round(combine(technology.low, biologics.low, origin.low)),\n high: round(combine(technology.high, biologics.high, origin.high)),\n },\n contested: technology.contested || biologics.contested || origin.contested,\n components: {\n technology: round(technology.point),\n biologics: round(biologics.point),\n origin: round(origin.point),\n },\n weights,\n scoringVersion: SCORING_VERSION,\n };\n}\n\nexport interface RankedObservation<T extends Observation = Observation> {\n observation: T;\n result: ScoreResult;\n}\n\n/**\n * Score a set of observations and return them sorted most-compelling first — the\n * \"float the strongest cases to the top\" use case.\n */\nexport function rankByCompellingness<T extends Observation>(\n observations: readonly T[],\n options?: ScoreOptions,\n): RankedObservation<T>[] {\n return observations\n .map((observation) => ({ observation, result: score(observation, options) }))\n .sort((a, b) => b.result.score - a.result.score);\n}\n"]}
1
+ {"version":3,"sources":["../../src/compellingness/calibration.ts","../../src/compellingness/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Observation } from '@disclosureos/records';\nimport { parseEvidenceRef, parseSensorRef } from '@disclosureos/records/shared';\nimport type { CalibrationStatus, SensorManifest } from '@disclosureos/instruments';\nimport type { EvaluatorWeightInput } from './index';\n\n/**\n * Trust multiplier per calibration maturity level, plus the `unresolved`\n * baseline for claims whose sensor evidence does not resolve to a manifest\n * entry (no `sensorRef`, unknown org, unknown sensor, or no calibration block).\n */\nexport type CalibrationTrustWeights = Record<CalibrationStatus | 'unresolved', number>;\n\n/**\n * Conservative default gradient: instruments with real calibration provenance\n * earn *credit* over unresolved sensors — nothing is ever penalized below the\n * baseline, so adopting the hook can only reward organizations that publish\n * manifests, never punish records that predate them.\n *\n * @experimental The shape is stable; these specific values are a reference\n * policy that may be re-tuned in a minor release. Pin your own `weights` via\n * {@link CalibrationTrustOptions} if you need stable numbers.\n */\nexport const CALIBRATION_TRUST_WEIGHTS: CalibrationTrustWeights = {\n unresolved: 1,\n none: 1,\n candidate_identified: 1.05,\n in_practice: 1.15,\n documented: 1.25,\n};\n\nexport interface CalibrationTrustOptions {\n /** Override the trust gradient (defaults to {@link CALIBRATION_TRUST_WEIGHTS}). */\n weights?: CalibrationTrustWeights;\n /**\n * A base trust policy composed (multiplied) with the calibration credit —\n * e.g. an evaluator-identity policy. Defaults to uniform 1.0.\n */\n evaluatorWeight?: (claim: EvaluatorWeightInput) => number;\n}\n\n/**\n * Build an `evaluatorWeight` hook (see `ScoreOptions.evaluatorWeight`) that\n * credits claims backed by instruments with published calibration provenance.\n *\n * Resolution chain, per claim: `evidenceRefs` (`\"sensor:<id>\"`) → the\n * observation's `sensorEvidence.sensors[]` reading → its `sensorRef`\n * (`\"<org-slug>:<sensor-id>\"`) → the matching manifest entry's\n * `calibration.status`. When a claim cites several sensor readings, the\n * strongest instrument backing wins. Claims with no resolvable sensor\n * evidence get the `unresolved` baseline.\n *\n * Like every `evaluatorWeight` policy, this shifts only the consensus point\n * estimate — `range` and `contested` still report the honest spread of what\n * evaluators actually asserted.\n *\n * ```ts\n * const result = score(observation, {\n * evaluatorWeight: calibrationTrust(observation, [navyManifest]),\n * });\n * ```\n */\nexport function calibrationTrust(\n observation: Observation,\n manifests: readonly SensorManifest[],\n options?: CalibrationTrustOptions,\n): (claim: EvaluatorWeightInput) => number {\n const weights = options?.weights ?? CALIBRATION_TRUST_WEIGHTS;\n const base = options?.evaluatorWeight ?? ((): number => 1);\n\n // Pre-resolve each in-record sensor reading to its manifest calibration status.\n const statusBySensorId = new Map<string, CalibrationStatus>();\n for (const reading of observation.sensorEvidence?.sensors ?? []) {\n if (!reading.sensorRef) continue;\n const ref = parseSensorRef(reading.sensorRef);\n if (!ref) continue;\n const entry = manifests\n .find((manifest) => manifest.orgSlug === ref.orgSlug)\n ?.sensors.find((sensor) => sensor.id === ref.sensorId);\n const status = entry?.calibration?.status;\n if (status) statusBySensorId.set(reading.id, status);\n }\n\n return (claim) => {\n let credit = weights.unresolved;\n for (const evidence of claim.evidenceRefs ?? []) {\n const parsed = parseEvidenceRef(evidence);\n if (!parsed || parsed.kind !== 'sensor') continue;\n const status = statusBySensorId.get(parsed.id);\n const weight = status === undefined ? weights.unresolved : weights[status];\n if (weight > credit) credit = weight;\n }\n return base(claim) * credit;\n };\n}\n","import { z } from 'zod';\nimport type { Observation } from '@disclosureos/records';\nimport type { AssessmentLevel } from '@disclosureos/observables';\nimport type { OriginClaim } from '@disclosureos/origins';\n// Side-effect imports register the `observableAssessments` and `origin` slots on\n// `Observation` via module augmentation, so they are typed below.\nimport '@disclosureos/observables';\nimport '@disclosureos/origins';\n\nexport { calibrationTrust, CALIBRATION_TRUST_WEIGHTS } from './calibration';\nexport type { CalibrationTrustWeights, CalibrationTrustOptions } from './calibration';\n\n/** Methodology version stamped on every {@link ScoreResult}. Bump on weight/formula changes. */\nexport const SCORING_VERSION = '2.0.0' as const;\n\n/**\n * Ordinal support-tier values retained as transparent methodology data.\n * These values do not establish anomaly strength. The scorer rejects descriptive\n * observable assessments rather than applying this table to the V2 vocabulary.\n */\nexport const ASSESSMENT_LEVEL_WEIGHTS: Record<AssessmentLevel, number> = {\n not_indicated: 0,\n reported: 0.25,\n documented: 0.5,\n measured: 0.75,\n confirmed: 1,\n};\n\n/**\n * OCS id prefixes treated as prosaic (well-explained). A confident *prosaic*\n * classification means the case is explained, so it contributes no anomaly\n * signal. Overridable per {@link score} call. Default is the OCS \"Prosaic\"\n * branch (`1.1.1`).\n */\nexport const DEFAULT_PROSAIC_OCS_PREFIXES: readonly string[] = ['1.1.1'];\n\nexport const CompellingnessWeightsSchema = z\n .object({\n technology: z.number().min(0).describe('Weight of the technology-anomaly signal.'),\n biologics: z.number().min(0).describe('Weight of the biologics-anomaly signal.'),\n origin: z.number().min(0).describe('Weight of the (non-prosaic) origin-confidence signal.'),\n })\n .meta({ id: 'CompellingnessWeights' })\n .describe('Relative weights for the compellingness components. Need not sum to 1 — normalized internally.');\n\nexport type CompellingnessWeights = z.infer<typeof CompellingnessWeightsSchema>;\n\n/**\n * Fixed default weights, exposed as a transparent, overridable data object (not a\n * config system). Partners can propose alternate weight sets without an API change.\n *\n * @experimental The *shape* (`CompellingnessWeights`) is stable, but these specific\n * default values are a reference methodology that may be re-tuned in a minor release.\n * Pin your own `weights` via {@link ScoreOptions} if you need stable numbers.\n */\nexport const DEFAULT_WEIGHTS: CompellingnessWeights = {\n technology: 0.45,\n biologics: 0.35,\n origin: 0.2,\n};\n\nexport const ScoreResultSchema = z\n .object({\n score: z.number().min(0).max(1).describe('Overall compellingness (consensus point estimate), 0–1.'),\n range: z\n .object({\n low: z.number().min(0).max(1).describe('Most-skeptical reading of the strongest-anomaly signal across competing claims.'),\n high: z.number().min(0).max(1).describe('Most-anomalous reading of the strongest-anomaly signal across competing claims.'),\n })\n .describe(\n 'Spread of the score across competing claims — wide range signals disagreement. Bounds are '\n + 'computed per-signal under the same strongest-anomaly (max) reduction as the point estimate, '\n + 'not a global min/max over every claim.',\n ),\n contested: z\n .boolean()\n .describe('True when claims disagree on *direction* (some assert anomaly, some assert none).'),\n components: z\n .object({\n technology: z.number().min(0).max(1),\n biologics: z.number().min(0).max(1),\n origin: z.number().min(0).max(1),\n })\n .describe('Per-signal consensus contributions before weighting.'),\n weights: CompellingnessWeightsSchema,\n scoringVersion: z.string().describe('Methodology version that produced this score.'),\n })\n .meta({ id: 'ScoreResult' })\n .describe('A reference compellingness score for an observation, with a contestedness range.');\n\nexport type ScoreResult = z.infer<typeof ScoreResultSchema>;\n\n/** The minimal claim shape the trust hook sees (it never needs the full body). */\nexport type EvaluatorWeightInput = {\n evaluatedBy?: string | undefined;\n evidenceRefs?: string[] | undefined;\n};\n\nexport interface ScoreOptions {\n weights?: CompellingnessWeights;\n /** Override the prosaic OCS prefixes (defaults to {@link DEFAULT_PROSAIC_OCS_PREFIXES}). */\n prosaicPrefixes?: readonly string[];\n /**\n * Trust applied to each claim's vote in the consensus point estimate (default\n * 1.0 — uniform). This is where a future trust policy (e.g.\n * weighting verified/official evaluators higher) plugs in here without changing\n * the formula. Range/contestedness are NOT affected — they report the honest\n * spread of what evaluators actually asserted.\n *\n * @experimental The hook signature is stable, but the default trust *policy*\n * (uniform 1.0) is deliberately unopinionated and is a separate, ongoing design\n * task; a future built-in policy may change the default.\n */\n evaluatorWeight?: (claim: EvaluatorWeightInput) => number;\n}\n\nconst UNIFORM_TRUST = (): number => 1;\n\nfunction isProsaic(id: string, prefixes: readonly string[]): boolean {\n return prefixes.some((p) => id === p || id.startsWith(`${p}.`));\n}\n\nfunction round(n: number): number {\n return Math.round(n * 1e4) / 1e4;\n}\n\ntype Weighted = { magnitude: number; weight: number };\n\ninterface ClaimStats {\n /** Trust-weighted mean magnitude (the consensus point). */\n point: number;\n /** Min asserted magnitude (most skeptical). */\n low: number;\n /** Max asserted magnitude (most anomalous). */\n high: number;\n /** Claims disagree on direction (some > 0, some === 0). */\n contested: boolean;\n}\n\nconst EMPTY_STATS: ClaimStats = { point: 0, low: 0, high: 0, contested: false };\n\nfunction reduceClaims(weighted: Weighted[]): ClaimStats {\n if (weighted.length === 0) return EMPTY_STATS;\n let wsum = 0;\n let msum = 0;\n let low = Infinity;\n let high = -Infinity;\n let anyAnomaly = false;\n let anyNone = false;\n for (const { magnitude, weight } of weighted) {\n wsum += weight;\n msum += magnitude * weight;\n if (magnitude < low) low = magnitude;\n if (magnitude > high) high = magnitude;\n if (magnitude > 0) anyAnomaly = true;\n else anyNone = true;\n }\n return {\n point: wsum > 0 ? msum / wsum : 0,\n low,\n high,\n contested: anyAnomaly && anyNone,\n };\n}\n\n/** Confidence in a *non-prosaic* origin, reduced across competing classifications. */\nfunction originStats(\n origin: OriginClaim[] | undefined,\n prefixes: readonly string[],\n evaluatorWeight: (claim: EvaluatorWeightInput) => number,\n): ClaimStats {\n if (!origin || origin.length === 0) return EMPTY_STATS;\n const weighted = origin.map<Weighted>((c) => ({\n magnitude: isProsaic(c.primaryHypothesis, prefixes) ? 0 : c.confidence,\n weight: c.confidence * evaluatorWeight(c),\n }));\n return reduceClaims(weighted);\n}\n\n/**\n * Reference scorer for origin-only inputs. Descriptive observable support tiers\n * cannot supply anomaly strength, so any nonempty observable claim list is rejected.\n * Use attributed V2 assessments and profile evaluation for research results.\n * Rejection is not a zero score or a finding that a characteristic is absent.\n */\nexport function score(observation: Observation, options?: ScoreOptions): ScoreResult {\n const assessments = observation.observableAssessments;\n const hasDescriptiveClaims = [assessments?.technology, assessments?.biologics]\n .some((group) => Object.values(group ?? {}).some((claims) => claims && claims.length > 0));\n if (hasDescriptiveClaims) {\n throw new Error('Descriptive observable assessments cannot produce anomaly strength. Use V2 attributed assessments and profile evaluation; this is not a zero or absent result.');\n }\n const weights = options?.weights ?? DEFAULT_WEIGHTS;\n const prosaicPrefixes = options?.prosaicPrefixes ?? DEFAULT_PROSAIC_OCS_PREFIXES;\n const evaluatorWeight = options?.evaluatorWeight ?? UNIFORM_TRUST;\n\n const technology = EMPTY_STATS;\n const biologics = EMPTY_STATS;\n const origin = originStats(observation.origin, prosaicPrefixes, evaluatorWeight);\n\n const totalWeight = weights.technology + weights.biologics + weights.origin;\n const combine = (t: number, b: number, o: number): number =>\n totalWeight > 0\n ? (t * weights.technology + b * weights.biologics + o * weights.origin) / totalWeight\n : 0;\n\n return {\n score: round(combine(technology.point, biologics.point, origin.point)),\n range: {\n low: round(combine(technology.low, biologics.low, origin.low)),\n high: round(combine(technology.high, biologics.high, origin.high)),\n },\n contested: technology.contested || biologics.contested || origin.contested,\n components: {\n technology: round(technology.point),\n biologics: round(biologics.point),\n origin: round(origin.point),\n },\n weights,\n scoringVersion: SCORING_VERSION,\n };\n}\n\nexport interface RankedObservation<T extends Observation = Observation> {\n observation: T;\n result: ScoreResult;\n}\n\n/**\n * Score a set of observations and return them sorted most-compelling first — the\n * \"float the strongest cases to the top\" use case.\n */\nexport function rankByCompellingness<T extends Observation>(\n observations: readonly T[],\n options?: ScoreOptions,\n): RankedObservation<T>[] {\n return observations\n .map((observation) => ({ observation, result: score(observation, options) }))\n .sort((a, b) => b.result.score - a.result.score);\n}\n"]}
@@ -54,6 +54,231 @@ interface AssessmentSummaryResult {
54
54
  /** Summarize attributed declarations. No outcome is upgraded by a parser pass. */
55
55
  declare function summarizeClaimHistory(input: unknown): AssessmentSummaryResult;
56
56
 
57
+ declare const PROVIDER_SCORE_POLICY_SCHEMA_ID = "urn:disclosureos:experimental:provider-score-policy:0.1.0";
58
+ declare const PROVIDER_SCORE_RESULT_SCHEMA_ID = "urn:disclosureos:experimental:provider-score-result:0.1.0";
59
+ /** A provider-defined method, not a DisclosureOS universal case grade. */
60
+ declare const ProviderScorePolicySchema: z.ZodObject<{
61
+ kind: z.ZodLiteral<"provider_score_policy">;
62
+ schemaVersion: z.ZodLiteral<"0.1.0">;
63
+ id: z.ZodString;
64
+ version: z.ZodString;
65
+ title: z.ZodString;
66
+ metric: z.ZodObject<{
67
+ id: z.ZodString;
68
+ label: z.ZodString;
69
+ question: z.ZodString;
70
+ }, z.core.$strict>;
71
+ subjectKinds: z.ZodArray<z.ZodEnum<{
72
+ measurement: "measurement";
73
+ case: "case";
74
+ record: "record";
75
+ claim: "claim";
76
+ product: "product";
77
+ source: "source";
78
+ collection: "collection";
79
+ }>>;
80
+ method: z.ZodObject<{
81
+ description: z.ZodString;
82
+ artifacts: z.ZodArray<z.ZodObject<{
83
+ sha256: z.ZodString;
84
+ byteLength: z.ZodNumber;
85
+ ref: z.ZodString;
86
+ id: z.ZodString;
87
+ version: z.ZodString;
88
+ mediaType: z.ZodString;
89
+ }, z.core.$strict>>;
90
+ }, z.core.$strict>;
91
+ applicability: z.ZodString;
92
+ missingData: z.ZodObject<{
93
+ handling: z.ZodEnum<{
94
+ withhold: "withhold";
95
+ allow_partial: "allow_partial";
96
+ }>;
97
+ description: z.ZodString;
98
+ }, z.core.$strict>;
99
+ limitations: z.ZodArray<z.ZodString>;
100
+ scale: z.ZodDiscriminatedUnion<[z.ZodObject<{
101
+ kind: z.ZodLiteral<"numeric">;
102
+ min: z.ZodNumber;
103
+ max: z.ZodNumber;
104
+ direction: z.ZodEnum<{
105
+ higher: "higher";
106
+ lower: "lower";
107
+ none: "none";
108
+ }>;
109
+ unit: z.ZodString;
110
+ grades: z.ZodArray<z.ZodObject<{
111
+ id: z.ZodString;
112
+ label: z.ZodString;
113
+ min: z.ZodNumber;
114
+ max: z.ZodNumber;
115
+ }, z.core.$strict>>;
116
+ }, z.core.$strict>, z.ZodObject<{
117
+ kind: z.ZodLiteral<"ordinal">;
118
+ direction: z.ZodEnum<{
119
+ higher: "higher";
120
+ lower: "lower";
121
+ none: "none";
122
+ }>;
123
+ levels: z.ZodArray<z.ZodObject<{
124
+ id: z.ZodString;
125
+ label: z.ZodString;
126
+ description: z.ZodString;
127
+ }, z.core.$strict>>;
128
+ }, z.core.$strict>], "kind">;
129
+ }, z.core.$strict>;
130
+ type ProviderScorePolicy = z.infer<typeof ProviderScorePolicySchema>;
131
+ /** Common evidence inputs and the provider's derivation are deliberately separate. */
132
+ declare const ProviderScoreResultSchema: z.ZodObject<{
133
+ kind: z.ZodLiteral<"provider_score_result">;
134
+ schemaVersion: z.ZodLiteral<"0.1.0">;
135
+ id: z.ZodString;
136
+ provider: z.ZodObject<{
137
+ id: z.ZodString;
138
+ name: z.ZodString;
139
+ url: z.ZodOptional<z.ZodURL>;
140
+ }, z.core.$strict>;
141
+ producedAt: z.ZodISODateTime;
142
+ policy: z.ZodObject<{
143
+ sha256: z.ZodString;
144
+ byteLength: z.ZodNumber;
145
+ id: z.ZodString;
146
+ version: z.ZodString;
147
+ }, z.core.$strict>;
148
+ subject: z.ZodObject<{
149
+ kind: z.ZodEnum<{
150
+ measurement: "measurement";
151
+ case: "case";
152
+ record: "record";
153
+ claim: "claim";
154
+ product: "product";
155
+ source: "source";
156
+ collection: "collection";
157
+ }>;
158
+ id: z.ZodString;
159
+ }, z.core.$strict>;
160
+ inputScope: z.ZodObject<{
161
+ id: z.ZodString;
162
+ description: z.ZodString;
163
+ }, z.core.$strict>;
164
+ inputs: z.ZodArray<z.ZodObject<{
165
+ sha256: z.ZodString;
166
+ byteLength: z.ZodNumber;
167
+ ref: z.ZodString;
168
+ title: z.ZodString;
169
+ mediaType: z.ZodString;
170
+ }, z.core.$strict>>;
171
+ derivation: z.ZodArray<z.ZodObject<{
172
+ sha256: z.ZodString;
173
+ byteLength: z.ZodNumber;
174
+ ref: z.ZodString;
175
+ title: z.ZodString;
176
+ mediaType: z.ZodString;
177
+ }, z.core.$strict>>;
178
+ applicability: z.ZodObject<{
179
+ status: z.ZodEnum<{
180
+ applicable: "applicable";
181
+ not_applicable: "not_applicable";
182
+ undetermined: "undetermined";
183
+ }>;
184
+ reason: z.ZodString;
185
+ }, z.core.$strict>;
186
+ missingInputs: z.ZodArray<z.ZodObject<{
187
+ ref: z.ZodString;
188
+ description: z.ZodString;
189
+ }, z.core.$strict>>;
190
+ limitations: z.ZodArray<z.ZodString>;
191
+ outcome: z.ZodDiscriminatedUnion<[z.ZodObject<{
192
+ status: z.ZodLiteral<"scored">;
193
+ value: z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>;
194
+ gradeId: z.ZodOptional<z.ZodString>;
195
+ explanation: z.ZodString;
196
+ }, z.core.$strict>, z.ZodObject<{
197
+ status: z.ZodLiteral<"unavailable">;
198
+ reasonCode: z.ZodEnum<{
199
+ not_applicable: "not_applicable";
200
+ undetermined: "undetermined";
201
+ missing_inputs: "missing_inputs";
202
+ not_calculated: "not_calculated";
203
+ }>;
204
+ explanation: z.ZodString;
205
+ }, z.core.$strict>], "status">;
206
+ }, z.core.$strict>;
207
+ type ProviderScoreResult = z.infer<typeof ProviderScoreResultSchema>;
208
+ declare function providerScorePolicyJsonSchema(): Record<string, unknown>;
209
+ declare function providerScoreResultJsonSchema(): Record<string, unknown>;
210
+ type Status$1 = "passed" | "failed" | "not_checked";
211
+ interface ProviderScoringIssue {
212
+ code: string;
213
+ pointer: string;
214
+ message: string;
215
+ }
216
+ interface ProviderScorePolicyValidation {
217
+ success: boolean;
218
+ checks: {
219
+ structural: Status$1;
220
+ semantic: Status$1;
221
+ };
222
+ issues: ProviderScoringIssue[];
223
+ policy: ProviderScorePolicy | null;
224
+ }
225
+ /** JSON Schema covers structure; this checks bounds, identifiers and complete non-overlapping grade bands. */
226
+ declare function validateProviderScorePolicy(input: unknown): ProviderScorePolicyValidation;
227
+ /** Assign a provider's declared band, without recomputing or endorsing its score. */
228
+ declare function providerScoreGrade(policy: ProviderScorePolicy, value: number | string): {
229
+ id: string;
230
+ label: string;
231
+ } | null;
232
+ interface ProviderScoreEvaluationOptions {
233
+ policyBytes?: Uint8Array;
234
+ inputFiles?: ReadonlyMap<string, Uint8Array>;
235
+ derivationFiles?: ReadonlyMap<string, Uint8Array>;
236
+ methodFiles?: ReadonlyMap<string, Uint8Array>;
237
+ }
238
+ interface ProviderScoreEvaluation {
239
+ success: boolean;
240
+ checks: {
241
+ structural: Status$1;
242
+ semantic: Status$1;
243
+ external: Status$1;
244
+ };
245
+ issues: ProviderScoringIssue[];
246
+ files: {
247
+ ref: string;
248
+ status: Status$1;
249
+ expectedSha256: string;
250
+ expectedByteLength: number;
251
+ actualSha256?: string;
252
+ actualByteLength?: number;
253
+ }[];
254
+ policy: ProviderScorePolicy | null;
255
+ result: ProviderScoreResult | null;
256
+ grade: {
257
+ id: string;
258
+ label: string;
259
+ } | null;
260
+ policyExecution: "not_checked";
261
+ providerAuthentication: "not_checked";
262
+ scientificValidity: "not_checked";
263
+ subjectResolution: "not_checked";
264
+ }
265
+ /** Checks declarations and supplied bytes only. Does not fetch, execute a policy, resolve a subject or authenticate a provider. */
266
+ declare function evaluateProviderScore(input: unknown, options?: ProviderScoreEvaluationOptions): Promise<ProviderScoreEvaluation>;
267
+ interface ProviderScoreComparison {
268
+ eligibleForComparison: boolean;
269
+ status: "eligible_for_comparison" | "not_eligible";
270
+ reasons: string[];
271
+ left: ProviderScoreEvaluation;
272
+ right: ProviderScoreEvaluation;
273
+ sharedInputDigests: string[];
274
+ statisticalIndependence: "not_checked";
275
+ }
276
+ /** Conservative eligibility for inspecting declared results side by side; never computes a winner, average or scientific equivalence. */
277
+ declare function compareProviderScores(leftInput: unknown, rightInput: unknown, options?: {
278
+ left?: ProviderScoreEvaluationOptions;
279
+ right?: ProviderScoreEvaluationOptions;
280
+ }): Promise<ProviderScoreComparison>;
281
+
57
282
  declare const ASSESSMENT_SUMMARY_EVALUATION_SCHEMA_ID = "urn:disclosureos:experimental:assessment-summary-evaluation:0.1.0";
58
283
  declare const ASSESSMENT_SUMMARY_EVALUATION_POLICY: Readonly<{
59
284
  readonly id: "urn:disclosureos:experimental:policy:assessment-summary-evaluation";
@@ -149,4 +374,4 @@ interface AssessmentSummaryEvaluationResult {
149
374
  /** Pins the summary's declared history input. Referenced source/product bytes are not verified or fetched. */
150
375
  declare function evaluateAssessmentSummaryEvaluation(input: unknown, options?: AssessmentSummaryEvaluationOptions): Promise<AssessmentSummaryEvaluationResult>;
151
376
 
152
- export { ASSESSMENT_SUMMARY_EVALUATION_POLICY, ASSESSMENT_SUMMARY_EVALUATION_SCHEMA_ID, ASSESSMENT_SUMMARY_POLICY, type AssessmentSummaryEvaluation, type AssessmentSummaryEvaluationOptions, type AssessmentSummaryEvaluationResult, AssessmentSummaryEvaluationSchema, type AssessmentSummaryGroup, type AssessmentSummaryReceipt, type AssessmentSummaryResult, type DeclarationGroup, assessmentSummaryEvaluationJsonSchema, evaluateAssessmentSummaryEvaluation, summarizeClaimHistory };
377
+ export { ASSESSMENT_SUMMARY_EVALUATION_POLICY, ASSESSMENT_SUMMARY_EVALUATION_SCHEMA_ID, ASSESSMENT_SUMMARY_POLICY, type AssessmentSummaryEvaluation, type AssessmentSummaryEvaluationOptions, type AssessmentSummaryEvaluationResult, AssessmentSummaryEvaluationSchema, type AssessmentSummaryGroup, type AssessmentSummaryReceipt, type AssessmentSummaryResult, type DeclarationGroup, PROVIDER_SCORE_POLICY_SCHEMA_ID, PROVIDER_SCORE_RESULT_SCHEMA_ID, type ProviderScoreComparison, type ProviderScoreEvaluation, type ProviderScoreEvaluationOptions, type ProviderScorePolicy, ProviderScorePolicySchema, type ProviderScorePolicyValidation, type ProviderScoreResult, ProviderScoreResultSchema, type ProviderScoringIssue, assessmentSummaryEvaluationJsonSchema, compareProviderScores, evaluateAssessmentSummaryEvaluation, evaluateProviderScore, providerScoreGrade, providerScorePolicyJsonSchema, providerScoreResultJsonSchema, summarizeClaimHistory, validateProviderScorePolicy };