@disclosureos/scoring 1.1.0 → 2.0.0-beta.1

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,9 +1,50 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0-beta.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [9e7c76a]
8
+ - @disclosureos/records@2.0.0-beta.1
9
+ - @disclosureos/instruments@2.0.0-beta.1
10
+ - @disclosureos/observables@2.0.0-beta.1
11
+ - @disclosureos/origins@2.0.0-beta.1
12
+
13
+ ## 2.0.0-beta.0
14
+
15
+ ### Major Changes
16
+
17
+ - Prepare the coordinated v2 beta package set. This prerelease packages the merged
18
+ experimental observation and claim contracts, acquisition and dataset exchange,
19
+ versioned evaluation, and bounded migration tooling for external consumer testing.
20
+ Existing root APIs and schema identities remain available; the new contracts keep
21
+ explicit `/experimental/v2` imports. Observables and origins retain their existing
22
+ catalogs within the pinned beta dependency graph. This is not a stable v2 release,
23
+ scientific certification, or publication of partner data. See
24
+ `docs/releases/2.0.0-beta.0.md` for package-specific scope and validation boundaries.
25
+
26
+ ### Patch Changes
27
+
28
+ - Updated dependencies
29
+ - @disclosureos/records@2.0.0-beta.0
30
+ - @disclosureos/observables@2.0.0-beta.0
31
+ - @disclosureos/origins@2.0.0-beta.0
32
+ - @disclosureos/instruments@2.0.0-beta.0
33
+
3
34
  All notable changes to `@disclosureos/scoring` are documented here. The format is
4
35
  based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
5
36
  adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
37
 
38
+ ## Unreleased compatibility additions
39
+
40
+ - Add descriptive population-coverage naming while preserving legacy completeness results and schema identities.
41
+
42
+ ## Unreleased experimental work
43
+
44
+ - Add exact-byte assessment-summary provenance, versioned input schema, and unsigned computed-result receipts; existing declaration summary behavior and source-verification limits are preserved.
45
+
46
+ - Add opt-in assessment summaries with current revision filtering, exact declaration deduplication, explicit shared lineage, and distinct outcome labels. Missing confidence stays omitted; existing scoring APIs and package versions are unchanged.
47
+
7
48
  ## 1.1.0
8
49
 
9
50
  ### Minor Changes
package/README.md CHANGED
@@ -3,11 +3,10 @@
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
4
4
 
5
5
  Reference scoring for the [DisclosureOS](https://github.com/disclosurefoundation)
6
- ecosystem — the **Scoring** layer. It turns an enriched `Observation` into two
7
- orthogonal measures:
6
+ ecosystem — the **Scoring** layer. Its legacy `Observation` APIs provide:
8
7
 
9
- - **Completeness** — *is it well-documented?* What fraction of the record's fields are
10
- present.
8
+ - **Population coverage** — the fraction of legacy schema field paths carrying a value.
9
+ Presence does not establish documentation quality or analytical readiness.
11
10
  - **Compellingness** — *is it anomalous / non-mundane?* Derived from the observable
12
11
  assessments and origin classification.
13
12
 
@@ -54,13 +53,16 @@ pnpm add @disclosureos/scoring @disclosureos/records @disclosureos/observables @
54
53
 
55
54
  ## Quick start
56
55
 
56
+ The `getPopulationCoverage` name below requires this unreleased checkout or a future
57
+ authorized release containing it. Published consumers can continue using `getCompleteness`.
58
+
57
59
  ```typescript
58
- import { score, getCompleteness, rankByCompellingness } from '@disclosureos/scoring';
60
+ import { score, getPopulationCoverage, rankByCompellingness } from '@disclosureos/scoring';
59
61
 
60
62
  const result = score(observation);
61
63
  // { score, range: { low, high }, contested, ... }
62
64
 
63
- const completeness = getCompleteness(observation);
65
+ const coverage = getPopulationCoverage(observation);
64
66
  // { percentage, requiredPercentage, missing, ... }
65
67
 
66
68
  const ranked = rankByCompellingness([obsA, obsB, obsC]); // most-compelling first
@@ -96,8 +98,9 @@ every `evaluatorWeight` policy it shifts only the consensus point — `range` an
96
98
 
97
99
  | Subpath | Contents |
98
100
  |---|---|
99
- | `@disclosureos/scoring` | `score`, `rankByCompellingness`, `getCompleteness`, `DEFAULT_WEIGHTS` |
100
- | `@disclosureos/scoring/completeness` | Completeness scoring + `deriveFieldPaths` |
101
+ | `@disclosureos/scoring` | `score`, `rankByCompellingness`, `getPopulationCoverage`, legacy `getCompleteness`, `DEFAULT_WEIGHTS` |
102
+ | `@disclosureos/scoring/population-coverage` | Field-presence counter and `deriveFieldPaths` |
103
+ | `@disclosureos/scoring/completeness` | Legacy field-presence counter + `deriveFieldPaths` |
101
104
  | `@disclosureos/scoring/compellingness` | Compellingness scoring + weights |
102
105
  | `@disclosureos/scoring/schema` | The committed JSON Schema (`scoring.schema.json`) |
103
106
 
@@ -111,3 +114,15 @@ them directly, with no DisclosureOS-specific adapter.
111
114
  ## License
112
115
 
113
116
  MIT © [Disclosure Foundation](https://disclosure.org)
117
+
118
+ ## Experimental v2 assessment summaries (unreleased)
119
+
120
+ `summarizeClaimHistory` from `@disclosureos/scoring/experimental/v2` groups current
121
+ attributed declarations by topic and subject, collapses exact copies, and discloses
122
+ shared inputs and differing outcome labels. It computes no aggregate score or
123
+ confidence interval and does not certify scientific eligibility. See the
124
+ [assessment summary guide](../../docs/experimental/assessment-summary.md).
125
+
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.
127
+
128
+ [Assessment-summary provenance and replay](../../docs/experimental/summary-provenance.md) now pin the declared history and computed summary without verifying referenced source artifacts.
@@ -32,9 +32,9 @@ interface CompletenessOptions {
32
32
  paths?: FieldPath[];
33
33
  }
34
34
  /**
35
- * Measure how fully an observation populates the records schema. This is the
36
- * "is it well-documented?" axis — deliberately kept separate from compellingness
37
- * ("is it anomalous?"), so a thin-but-anomalous case never masquerades as complete.
35
+ * Count populated legacy schema field paths. A present value is not necessarily
36
+ * valid, documented, applicable or independently analyzable. Prefer the public
37
+ * getPopulationCoverage name for new callers; legacy behavior remains unchanged.
38
38
  */
39
39
  declare function getCompleteness(observation: Observation | Record<string, unknown>, options?: CompletenessOptions): CompletenessResult;
40
40
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/completeness/field-paths.ts","../../src/completeness/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { recordsJsonSchema } from '@disclosureos/records';\n\n/** A leaf field path derived from the records JSON Schema. */\nexport interface FieldPath {\n /** Dot-path into an `Observation` (e.g. `location.latitude`). */\n path: string;\n /** True only when every segment along the path is schema-required. */\n required: boolean;\n}\n\ninterface SchemaNode {\n $ref?: string;\n properties?: Record<string, SchemaNode>;\n required?: string[];\n type?: string | string[];\n}\n\nfunction refName(ref: string): string {\n return ref.replace('#/$defs/', '');\n}\n\n/**\n * Walk the committed records JSON Schema and enumerate every leaf field path on\n * `Observation`. Objects are recursed (resolving `$ref` into `$defs`); arrays,\n * enums, scalars, and `record`/`anyOf` nodes are treated as leaves. This is the\n * single source of completeness coverage — there is no hand-maintained path list\n * (so adding a field to the schema automatically extends completeness).\n */\nexport function deriveFieldPaths(schema?: Record<string, unknown>): FieldPath[] {\n const root = (schema ?? recordsJsonSchema()) as Record<string, unknown> & {\n $ref?: string;\n $defs?: Record<string, SchemaNode>;\n };\n const defs = root.$defs ?? {};\n const out: FieldPath[] = [];\n\n function resolve(node: SchemaNode): SchemaNode {\n let cur: SchemaNode = node;\n const seen = new Set<string>();\n while (cur.$ref) {\n const name = refName(cur.$ref);\n if (seen.has(name)) break;\n seen.add(name);\n cur = defs[name] ?? {};\n }\n return cur;\n }\n\n function walk(node: SchemaNode, prefix: string, required: boolean, visited: Set<string>): void {\n const refn = node.$ref ? refName(node.$ref) : undefined;\n // Cycle guard: a recursive $ref re-entering an in-progress def becomes a leaf.\n if (refn && visited.has(refn)) {\n if (prefix) out.push({ path: prefix, required });\n return;\n }\n const resolved = resolve(node);\n const props = resolved.properties;\n if (props && Object.keys(props).length > 0) {\n const nextVisited = refn ? new Set([...visited, refn]) : visited;\n const req = new Set(resolved.required ?? []);\n for (const [key, child] of Object.entries(props)) {\n const childPath = prefix ? `${prefix}.${key}` : key;\n walk(child, childPath, required && req.has(key), nextVisited);\n }\n return;\n }\n if (prefix) out.push({ path: prefix, required });\n }\n\n if (root.$ref) {\n walk({ $ref: root.$ref }, '', true, new Set());\n }\n return out;\n}\n","import { z } from 'zod';\nimport type { Observation } from '@disclosureos/records';\nimport { deriveFieldPaths } from './field-paths';\nimport type { FieldPath } from './field-paths';\n\nexport type { FieldPath } from './field-paths';\nexport { deriveFieldPaths } from './field-paths';\n\nexport const CompletenessResultSchema = z\n .object({\n total: z.number().int().describe('Total leaf field paths defined by the records schema.'),\n present: z.number().int().describe('How many of those paths carry a value.'),\n percentage: z.number().int().describe('present / total, as a 0–100 integer.'),\n missing: z.array(z.string()).describe('Paths that are absent or empty.'),\n requiredTotal: z.number().int().describe('Count of schema-required leaf paths.'),\n requiredPresent: z.number().int().describe('How many required paths carry a value.'),\n requiredPercentage: z\n .number()\n .int()\n .describe('requiredPresent / requiredTotal, as a 0–100 integer.'),\n })\n .meta({ id: 'CompletenessResult' })\n .describe('How fully an observation populates the records schema.');\n\nexport type CompletenessResult = z.infer<typeof CompletenessResultSchema>;\n\nexport interface CompletenessOptions {\n /** Override the derived field-path set (defaults to the records schema). */\n paths?: FieldPath[];\n}\n\nfunction getNested(obj: Record<string, unknown>, path: string): unknown {\n let current: unknown = obj;\n for (const part of path.split('.')) {\n if (current == null || typeof current !== 'object') return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n}\n\nfunction isPresent(value: unknown): boolean {\n if (value == null) return false;\n if (typeof value === 'string') return value.length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\n// Field paths are stable for a given schema version, so derive once and reuse.\nlet cachedPaths: FieldPath[] | null = null;\nfunction defaultPaths(): FieldPath[] {\n return (cachedPaths ??= deriveFieldPaths());\n}\n\nfunction pct(present: number, total: number): number {\n return total > 0 ? Math.round((present / total) * 100) : 0;\n}\n\n/**\n * Measure how fully an observation populates the records schema. This is the\n * \"is it well-documented?\" axis — deliberately kept separate from compellingness\n * (\"is it anomalous?\"), so a thin-but-anomalous case never masquerades as complete.\n */\nexport function getCompleteness(\n observation: Observation | Record<string, unknown>,\n options?: CompletenessOptions,\n): CompletenessResult {\n const record = observation as Record<string, unknown>;\n const paths = options?.paths ?? defaultPaths();\n const missing: string[] = [];\n let present = 0;\n let requiredTotal = 0;\n let requiredPresent = 0;\n\n for (const field of paths) {\n const ok = isPresent(getNested(record, field.path));\n if (ok) present++;\n else missing.push(field.path);\n if (field.required) {\n requiredTotal++;\n if (ok) requiredPresent++;\n }\n }\n\n return {\n total: paths.length,\n present,\n percentage: pct(present, paths.length),\n missing,\n requiredTotal,\n requiredPresent,\n requiredPercentage: pct(requiredPresent, requiredTotal),\n };\n}\n"]}
1
+ {"version":3,"sources":["../../src/completeness/field-paths.ts","../../src/completeness/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { recordsJsonSchema } from '@disclosureos/records';\n\n/** A leaf field path derived from the records JSON Schema. */\nexport interface FieldPath {\n /** Dot-path into an `Observation` (e.g. `location.latitude`). */\n path: string;\n /** True only when every segment along the path is schema-required. */\n required: boolean;\n}\n\ninterface SchemaNode {\n $ref?: string;\n properties?: Record<string, SchemaNode>;\n required?: string[];\n type?: string | string[];\n}\n\nfunction refName(ref: string): string {\n return ref.replace('#/$defs/', '');\n}\n\n/**\n * Walk the committed records JSON Schema and enumerate every leaf field path on\n * `Observation`. Objects are recursed (resolving `$ref` into `$defs`); arrays,\n * enums, scalars, and `record`/`anyOf` nodes are treated as leaves. This is the\n * single source of completeness coverage — there is no hand-maintained path list\n * (so adding a field to the schema automatically extends completeness).\n */\nexport function deriveFieldPaths(schema?: Record<string, unknown>): FieldPath[] {\n const root = (schema ?? recordsJsonSchema()) as Record<string, unknown> & {\n $ref?: string;\n $defs?: Record<string, SchemaNode>;\n };\n const defs = root.$defs ?? {};\n const out: FieldPath[] = [];\n\n function resolve(node: SchemaNode): SchemaNode {\n let cur: SchemaNode = node;\n const seen = new Set<string>();\n while (cur.$ref) {\n const name = refName(cur.$ref);\n if (seen.has(name)) break;\n seen.add(name);\n cur = defs[name] ?? {};\n }\n return cur;\n }\n\n function walk(node: SchemaNode, prefix: string, required: boolean, visited: Set<string>): void {\n const refn = node.$ref ? refName(node.$ref) : undefined;\n // Cycle guard: a recursive $ref re-entering an in-progress def becomes a leaf.\n if (refn && visited.has(refn)) {\n if (prefix) out.push({ path: prefix, required });\n return;\n }\n const resolved = resolve(node);\n const props = resolved.properties;\n if (props && Object.keys(props).length > 0) {\n const nextVisited = refn ? new Set([...visited, refn]) : visited;\n const req = new Set(resolved.required ?? []);\n for (const [key, child] of Object.entries(props)) {\n const childPath = prefix ? `${prefix}.${key}` : key;\n walk(child, childPath, required && req.has(key), nextVisited);\n }\n return;\n }\n if (prefix) out.push({ path: prefix, required });\n }\n\n if (root.$ref) {\n walk({ $ref: root.$ref }, '', true, new Set());\n }\n return out;\n}\n","import { z } from 'zod';\nimport type { Observation } from '@disclosureos/records';\nimport { deriveFieldPaths } from './field-paths';\nimport type { FieldPath } from './field-paths';\n\nexport type { FieldPath } from './field-paths';\nexport { deriveFieldPaths } from './field-paths';\n\nexport const CompletenessResultSchema = z\n .object({\n total: z.number().int().describe('Total leaf field paths defined by the records schema.'),\n present: z.number().int().describe('How many of those paths carry a value.'),\n percentage: z.number().int().describe('present / total, as a 0–100 integer.'),\n missing: z.array(z.string()).describe('Paths that are absent or empty.'),\n requiredTotal: z.number().int().describe('Count of schema-required leaf paths.'),\n requiredPresent: z.number().int().describe('How many required paths carry a value.'),\n requiredPercentage: z\n .number()\n .int()\n .describe('requiredPresent / requiredTotal, as a 0–100 integer.'),\n })\n .meta({ id: 'CompletenessResult' })\n .describe('How fully an observation populates the records schema.');\n\nexport type CompletenessResult = z.infer<typeof CompletenessResultSchema>;\n\nexport interface CompletenessOptions {\n /** Override the derived field-path set (defaults to the records schema). */\n paths?: FieldPath[];\n}\n\nfunction getNested(obj: Record<string, unknown>, path: string): unknown {\n let current: unknown = obj;\n for (const part of path.split('.')) {\n if (current == null || typeof current !== 'object') return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n}\n\nfunction isPresent(value: unknown): boolean {\n if (value == null) return false;\n if (typeof value === 'string') return value.length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\n// Field paths are stable for a given schema version, so derive once and reuse.\nlet cachedPaths: FieldPath[] | null = null;\nfunction defaultPaths(): FieldPath[] {\n return (cachedPaths ??= deriveFieldPaths());\n}\n\nfunction pct(present: number, total: number): number {\n return total > 0 ? Math.round((present / total) * 100) : 0;\n}\n\n/**\n * Count populated legacy schema field paths. A present value is not necessarily\n * valid, documented, applicable or independently analyzable. Prefer the public\n * getPopulationCoverage name for new callers; legacy behavior remains unchanged.\n */\nexport function getCompleteness(\n observation: Observation | Record<string, unknown>,\n options?: CompletenessOptions,\n): CompletenessResult {\n const record = observation as Record<string, unknown>;\n const paths = options?.paths ?? defaultPaths();\n const missing: string[] = [];\n let present = 0;\n let requiredTotal = 0;\n let requiredPresent = 0;\n\n for (const field of paths) {\n const ok = isPresent(getNested(record, field.path));\n if (ok) present++;\n else missing.push(field.path);\n if (field.required) {\n requiredTotal++;\n if (ok) requiredPresent++;\n }\n }\n\n return {\n total: paths.length,\n present,\n percentage: pct(present, paths.length),\n missing,\n requiredTotal,\n requiredPresent,\n requiredPercentage: pct(requiredPresent, requiredTotal),\n };\n}\n"]}
@@ -0,0 +1,152 @@
1
+ import { ClaimHistoryValidation, ClaimSubject, HistoricalClaim, SourceStatement, UnassessedClaim, AssessedClaim } from '@disclosureos/records/experimental/v2';
2
+ import { z } from 'zod';
3
+
4
+ declare const ASSESSMENT_SUMMARY_POLICY: Readonly<{
5
+ readonly id: "urn:disclosureos:experimental:policy:assessment-summary";
6
+ readonly version: "0.1.0";
7
+ readonly scope: "current_declared_assessments";
8
+ }>;
9
+ type Declaration<T extends HistoricalClaim> = Omit<T, "id" | "recordedAt" | "supersedes">;
10
+ interface DeclarationGroup<T extends HistoricalClaim> {
11
+ /** All current copies; the first sorted ref is the deterministic representative. */
12
+ claimRefs: string[];
13
+ declaration: Declaration<T>;
14
+ }
15
+ interface AssessmentSummaryGroup {
16
+ topic: string;
17
+ subject: ClaimSubject;
18
+ sourceAssertions: DeclarationGroup<SourceStatement>[];
19
+ unassessed: DeclarationGroup<UnassessedClaim>[];
20
+ assessments: (DeclarationGroup<AssessedClaim> & {
21
+ lineageRefs: string[];
22
+ })[];
23
+ declaredOutcomes: AssessedClaim["outcome"][];
24
+ disagreement: "not_assessed" | "single_declared_outcome" | "multiple_declared_outcomes";
25
+ }
26
+ interface AssessmentSummaryResult {
27
+ success: boolean;
28
+ policy: typeof ASSESSMENT_SUMMARY_POLICY;
29
+ contract: ClaimHistoryValidation["contract"];
30
+ checks: ClaimHistoryValidation["checks"];
31
+ issues: ClaimHistoryValidation["issues"];
32
+ uncheckedRefs: string[];
33
+ historyId?: string;
34
+ observationId?: string;
35
+ currentClaimRefs: string[];
36
+ supersededClaimRefs: string[];
37
+ groups: AssessmentSummaryGroup[];
38
+ sharedInputs: {
39
+ ref: string;
40
+ assessmentRefs: string[];
41
+ }[];
42
+ /** Equal declared hashes are a dependence signal, not a completed byte check. */
43
+ sharedDeclaredArtifacts: {
44
+ sha256: string;
45
+ artifactRefs: string[];
46
+ assessmentRefs: string[];
47
+ }[];
48
+ scientificEligibility: "not_checked";
49
+ artifactIntegrity: "not_checked";
50
+ vocabularyMembership: "not_checked";
51
+ statisticalIndependence: "not_checked";
52
+ reproducibility: "not_checked";
53
+ }
54
+ /** Summarize attributed declarations. No outcome is upgraded by a parser pass. */
55
+ declare function summarizeClaimHistory(input: unknown): AssessmentSummaryResult;
56
+
57
+ declare const ASSESSMENT_SUMMARY_EVALUATION_SCHEMA_ID = "urn:disclosureos:experimental:assessment-summary-evaluation:0.1.0";
58
+ declare const ASSESSMENT_SUMMARY_EVALUATION_POLICY: Readonly<{
59
+ readonly id: "urn:disclosureos:experimental:policy:assessment-summary-evaluation";
60
+ readonly version: "0.1.0";
61
+ readonly scope: "pinned_claim_history_and_computed_declarations";
62
+ }>;
63
+ declare const AssessmentSummaryEvaluationSchema: z.ZodObject<{
64
+ kind: z.ZodLiteral<"assessment_summary_evaluation">;
65
+ schemaVersion: z.ZodLiteral<"0.1.0">;
66
+ id: z.ZodString;
67
+ workflow: z.ZodLiteral<"assessment-summary:0.1.0">;
68
+ history: z.ZodObject<{
69
+ sha256: z.ZodString;
70
+ byteLength: z.ZodNumber;
71
+ }, z.core.$strict>;
72
+ dependencies: z.ZodObject<{
73
+ vocabularies: z.ZodArray<z.ZodObject<{
74
+ sha256: z.ZodString;
75
+ byteLength: z.ZodNumber;
76
+ ref: z.ZodString;
77
+ id: z.ZodString;
78
+ version: z.ZodString;
79
+ }, z.core.$strict>>;
80
+ implementation: z.ZodObject<{
81
+ sha256: z.ZodString;
82
+ byteLength: z.ZodNumber;
83
+ ref: z.ZodString;
84
+ id: z.ZodString;
85
+ version: z.ZodString;
86
+ }, z.core.$strict>;
87
+ environment: z.ZodObject<{
88
+ sha256: z.ZodString;
89
+ byteLength: z.ZodNumber;
90
+ ref: z.ZodString;
91
+ id: z.ZodString;
92
+ version: z.ZodString;
93
+ }, z.core.$strict>;
94
+ }, z.core.$strict>;
95
+ }, z.core.$strict>;
96
+ type AssessmentSummaryEvaluation = z.infer<typeof AssessmentSummaryEvaluationSchema>;
97
+ declare function assessmentSummaryEvaluationJsonSchema(): Record<string, unknown>;
98
+ interface AssessmentSummaryEvaluationOptions {
99
+ historyBytes?: Uint8Array;
100
+ dependencyFiles?: ReadonlyMap<string, Uint8Array>;
101
+ }
102
+ type Status = "passed" | "failed" | "not_checked";
103
+ interface AssessmentSummaryReceipt {
104
+ format: "disclosureos-assessment-summary-receipt:0.1.0";
105
+ serialization: "sorted-json-utf8:0.1.0";
106
+ request: {
107
+ sha256: string;
108
+ byteLength: number;
109
+ };
110
+ output: {
111
+ sha256: string;
112
+ byteLength: number;
113
+ };
114
+ requestJson: string;
115
+ outputJson: string;
116
+ }
117
+ interface AssessmentSummaryEvaluationResult {
118
+ success: boolean;
119
+ policy: typeof ASSESSMENT_SUMMARY_EVALUATION_POLICY;
120
+ checks: {
121
+ structural: Status;
122
+ semantic: Status;
123
+ external: Status;
124
+ summary: Status;
125
+ receipt: Status;
126
+ };
127
+ issues: {
128
+ code: string;
129
+ pointer: string;
130
+ message: string;
131
+ }[];
132
+ files: {
133
+ ref: string;
134
+ status: Status;
135
+ expectedSha256: string;
136
+ expectedByteLength: number;
137
+ actualSha256?: string;
138
+ actualByteLength?: number;
139
+ }[];
140
+ summary: AssessmentSummaryResult | null;
141
+ receipt: AssessmentSummaryReceipt | null;
142
+ sourceArtifactIntegrity: "not_checked";
143
+ vocabularyMembership: "not_checked";
144
+ scientificEligibility: "not_checked";
145
+ statisticalIndependence: "not_checked";
146
+ implementationExecution: "not_attested";
147
+ environmentExecution: "not_attested";
148
+ }
149
+ /** Pins the summary's declared history input. Referenced source/product bytes are not verified or fetched. */
150
+ declare function evaluateAssessmentSummaryEvaluation(input: unknown, options?: AssessmentSummaryEvaluationOptions): Promise<AssessmentSummaryEvaluationResult>;
151
+
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 };