@disclosureos/scoring 1.1.0 → 2.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +23 -8
- package/dist/completeness/index.d.ts +3 -3
- package/dist/completeness/index.js.map +1 -1
- package/dist/experimental/v2/index.d.ts +152 -0
- package/dist/experimental/v2/index.js +433 -0
- package/dist/experimental/v2/index.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/population-coverage/index.d.ts +3 -0
- package/dist/population-coverage/index.js +109 -0
- package/dist/population-coverage/index.js.map +1 -0
- package/package.json +19 -8
- package/schema/experimental/assessment-summary-evaluation-0.1.0.schema.json +174 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.0.0-beta.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- Prepare the coordinated v2 beta package set. This prerelease packages the merged
|
|
8
|
+
experimental observation and claim contracts, acquisition and dataset exchange,
|
|
9
|
+
versioned evaluation, and bounded migration tooling for external consumer testing.
|
|
10
|
+
Existing root APIs and schema identities remain available; the new contracts keep
|
|
11
|
+
explicit `/experimental/v2` imports. Observables and origins retain their existing
|
|
12
|
+
catalogs within the pinned beta dependency graph. This is not a stable v2 release,
|
|
13
|
+
scientific certification, or publication of partner data. See
|
|
14
|
+
`docs/releases/2.0.0-beta.0.md` for package-specific scope and validation boundaries.
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Updated dependencies
|
|
19
|
+
- @disclosureos/records@2.0.0-beta.0
|
|
20
|
+
- @disclosureos/observables@2.0.0-beta.0
|
|
21
|
+
- @disclosureos/origins@2.0.0-beta.0
|
|
22
|
+
- @disclosureos/instruments@2.0.0-beta.0
|
|
23
|
+
|
|
3
24
|
All notable changes to `@disclosureos/scoring` are documented here. The format is
|
|
4
25
|
based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
|
|
5
26
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
27
|
|
|
28
|
+
## Unreleased compatibility additions
|
|
29
|
+
|
|
30
|
+
- Add descriptive population-coverage naming while preserving legacy completeness results and schema identities.
|
|
31
|
+
|
|
32
|
+
## Unreleased experimental work
|
|
33
|
+
|
|
34
|
+
- Add exact-byte assessment-summary provenance, versioned input schema, and unsigned computed-result receipts; existing declaration summary behavior and source-verification limits are preserved.
|
|
35
|
+
|
|
36
|
+
- 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.
|
|
37
|
+
|
|
7
38
|
## 1.1.0
|
|
8
39
|
|
|
9
40
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
4
|
|
|
5
5
|
Reference scoring for the [DisclosureOS](https://github.com/disclosurefoundation)
|
|
6
|
-
ecosystem — the **Scoring** layer.
|
|
7
|
-
orthogonal measures:
|
|
6
|
+
ecosystem — the **Scoring** layer. Its legacy `Observation` APIs provide:
|
|
8
7
|
|
|
9
|
-
- **
|
|
10
|
-
|
|
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,
|
|
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
|
|
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/
|
|
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
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
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 };
|