@kontourai/survey 0.1.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/README.md +80 -0
- package/dist/examples/public-field-observation.d.ts +1 -0
- package/dist/examples/public-field-observation.js +43 -0
- package/dist/fixtures/corrected-document-candidates.d.ts +2 -0
- package/dist/fixtures/corrected-document-candidates.js +143 -0
- package/dist/fixtures/public-field-review.d.ts +2 -0
- package/dist/fixtures/public-field-review.js +125 -0
- package/dist/src/builder.d.ts +61 -0
- package/dist/src/builder.js +140 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.js +2 -0
- package/dist/src/to-surface.d.ts +3 -0
- package/dist/src/to-surface.js +215 -0
- package/dist/src/types.d.ts +109 -0
- package/dist/src/types.js +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Kontour Survey
|
|
2
|
+
|
|
3
|
+
Survey is the producer-side contract for turning raw observations into
|
|
4
|
+
Surface-ready trust records.
|
|
5
|
+
|
|
6
|
+
This repo is intentionally small right now. It is a proof package, not an
|
|
7
|
+
ingestion platform:
|
|
8
|
+
|
|
9
|
+
- producers own acquisition, parsing, ranking, review UX, and vertical policy;
|
|
10
|
+
- Survey owns source, extraction, candidate, and review record shapes;
|
|
11
|
+
- `buildSurveyTrustInput` projects those records into `@kontourai/surface`
|
|
12
|
+
`TrustInput`;
|
|
13
|
+
- Surface owns trust reporting, derivation, console projections, and downstream
|
|
14
|
+
transparency.
|
|
15
|
+
|
|
16
|
+
The first success criterion is that generic corrected-document and public-field
|
|
17
|
+
fixtures can pass through Survey and produce valid Surface reports without
|
|
18
|
+
Survey absorbing vertical policy.
|
|
19
|
+
|
|
20
|
+
## Quickstart
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { buildTrustReport, validateTrustInput } from "@kontourai/surface";
|
|
24
|
+
import { buildSurveyTrustInput, SurveyInputBuilder } from "@kontourai/survey";
|
|
25
|
+
|
|
26
|
+
const surveyInput = new SurveyInputBuilder({
|
|
27
|
+
source: "example-producer:run-1",
|
|
28
|
+
})
|
|
29
|
+
.addObservation({
|
|
30
|
+
id: "listing-123.availability.current",
|
|
31
|
+
rawSource: {
|
|
32
|
+
kind: "web-page",
|
|
33
|
+
sourceRef: "https://example.test/listings/123",
|
|
34
|
+
observedAt: new Date().toISOString(),
|
|
35
|
+
locatorScheme: "html",
|
|
36
|
+
},
|
|
37
|
+
extraction: {
|
|
38
|
+
target: "availabilityStatus",
|
|
39
|
+
value: "AVAILABLE",
|
|
40
|
+
confidence: 0.92,
|
|
41
|
+
locator: "html:field=availabilityStatus",
|
|
42
|
+
excerpt: "Availability is open.",
|
|
43
|
+
extractor: "example-crawler",
|
|
44
|
+
extractedAt: new Date().toISOString(),
|
|
45
|
+
},
|
|
46
|
+
reviewOutcome: {
|
|
47
|
+
status: "verified",
|
|
48
|
+
actor: "example-operator",
|
|
49
|
+
reviewedAt: new Date().toISOString(),
|
|
50
|
+
},
|
|
51
|
+
claim: {
|
|
52
|
+
subjectType: "public-record.entity",
|
|
53
|
+
subjectId: "listing-123",
|
|
54
|
+
surface: "public-record.profile",
|
|
55
|
+
claimType: "public-data.field",
|
|
56
|
+
fieldOrBehavior: "availabilityStatus",
|
|
57
|
+
impactLevel: "medium",
|
|
58
|
+
collectedBy: "example-crawler",
|
|
59
|
+
},
|
|
60
|
+
})
|
|
61
|
+
.build();
|
|
62
|
+
|
|
63
|
+
const trustInput = validateTrustInput(buildSurveyTrustInput(surveyInput));
|
|
64
|
+
const report = buildTrustReport(trustInput);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Product Boundary
|
|
68
|
+
|
|
69
|
+
Survey does not crawl pages, parse PDFs, rank candidates, decide review policy,
|
|
70
|
+
or claim a value is true. Producers own acquisition, extraction, ranking, review
|
|
71
|
+
UX, materiality, and domain policy. Survey gives those producers a consistent
|
|
72
|
+
source -> extraction -> candidate -> review -> claim contract before the records
|
|
73
|
+
enter Surface.
|
|
74
|
+
|
|
75
|
+
## Commands
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
npm install
|
|
79
|
+
npm run verify
|
|
80
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { buildTrustReport, validateTrustInput } from "@kontourai/surface";
|
|
2
|
+
import { buildSurveyTrustInput, SurveyInputBuilder } from "../src/index.js";
|
|
3
|
+
const observedAt = "2026-05-31T16:00:00.000Z";
|
|
4
|
+
const surveyInput = new SurveyInputBuilder({
|
|
5
|
+
source: "example-producer:public-field",
|
|
6
|
+
generatedAt: observedAt,
|
|
7
|
+
})
|
|
8
|
+
.addObservation({
|
|
9
|
+
id: "example.entity-1.availability.current",
|
|
10
|
+
rawSource: {
|
|
11
|
+
kind: "web-page",
|
|
12
|
+
sourceRef: "https://example.test/entities/1",
|
|
13
|
+
observedAt,
|
|
14
|
+
locatorScheme: "html",
|
|
15
|
+
},
|
|
16
|
+
extraction: {
|
|
17
|
+
target: "availabilityStatus",
|
|
18
|
+
value: "AVAILABLE",
|
|
19
|
+
confidence: 0.92,
|
|
20
|
+
locator: "html:field=availabilityStatus",
|
|
21
|
+
excerpt: "Availability is open.",
|
|
22
|
+
extractor: "example-crawler",
|
|
23
|
+
extractedAt: observedAt,
|
|
24
|
+
},
|
|
25
|
+
reviewOutcome: {
|
|
26
|
+
status: "verified",
|
|
27
|
+
actor: "example-operator",
|
|
28
|
+
reviewedAt: observedAt,
|
|
29
|
+
},
|
|
30
|
+
claim: {
|
|
31
|
+
subjectType: "public-record.entity",
|
|
32
|
+
subjectId: "entity-1",
|
|
33
|
+
surface: "public-record.profile",
|
|
34
|
+
claimType: "public-data.field",
|
|
35
|
+
fieldOrBehavior: "availabilityStatus",
|
|
36
|
+
impactLevel: "medium",
|
|
37
|
+
collectedBy: "example-crawler",
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
.build();
|
|
41
|
+
const trustInput = validateTrustInput(buildSurveyTrustInput(surveyInput));
|
|
42
|
+
const report = buildTrustReport(trustInput);
|
|
43
|
+
console.log(JSON.stringify(report.summary, null, 2));
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
const generatedAt = "2026-05-31T16:00:00.000Z";
|
|
2
|
+
export const correctedDocumentCandidatesFixture = {
|
|
3
|
+
source: "survey.fixture.corrected-document-candidates",
|
|
4
|
+
generatedAt,
|
|
5
|
+
rawSources: [
|
|
6
|
+
{
|
|
7
|
+
id: "document:source:original",
|
|
8
|
+
kind: "uploaded-document",
|
|
9
|
+
sourceRef: "documents://original-statement.pdf",
|
|
10
|
+
observedAt: "2026-02-01T12:00:00.000Z",
|
|
11
|
+
checksum: "sha256:original",
|
|
12
|
+
locatorScheme: "pdf",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "document:source:corrected",
|
|
16
|
+
kind: "uploaded-document",
|
|
17
|
+
sourceRef: "documents://corrected-statement.pdf",
|
|
18
|
+
observedAt: "2026-03-01T12:00:00.000Z",
|
|
19
|
+
checksum: "sha256:corrected",
|
|
20
|
+
locatorScheme: "pdf",
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
extractions: [
|
|
24
|
+
documentExtraction("original:amount", "document:source:original", "statement.totalAmount", 82000, "pdf:page=1;box=1"),
|
|
25
|
+
documentExtraction("original:credit", "document:source:original", "statement.creditAmount", 8600, "pdf:page=1;box=2"),
|
|
26
|
+
documentExtraction("corrected:amount", "document:source:corrected", "statement.totalAmount", 84000, "pdf:page=1;box=1"),
|
|
27
|
+
documentExtraction("corrected:credit", "document:source:corrected", "statement.creditAmount", 9100, "pdf:page=1;box=2"),
|
|
28
|
+
],
|
|
29
|
+
candidateSets: [
|
|
30
|
+
documentCandidateSet("amount", "original:amount", 82000, "corrected:amount", 84000),
|
|
31
|
+
documentCandidateSet("credit", "original:credit", 8600, "corrected:credit", 9100),
|
|
32
|
+
],
|
|
33
|
+
reviewOutcomes: [],
|
|
34
|
+
claims: [
|
|
35
|
+
documentClaim("document.entity-1.statement.amount.original", "amount", "original:amount", "statement.totalAmount", "superseded"),
|
|
36
|
+
documentClaim("document.entity-1.statement.credit.original", "credit", "original:credit", "statement.creditAmount", "superseded"),
|
|
37
|
+
documentClaim("document.entity-1.statement.amount.corrected", "amount", "corrected:amount", "statement.totalAmount", "proposed"),
|
|
38
|
+
documentClaim("document.entity-1.statement.credit.corrected", "credit", "corrected:credit", "statement.creditAmount", "proposed"),
|
|
39
|
+
],
|
|
40
|
+
derivedClaims: [
|
|
41
|
+
{
|
|
42
|
+
id: "document.entity-1.statement-position.current",
|
|
43
|
+
subjectType: "verified-record.period",
|
|
44
|
+
subjectId: "entity-1:2026",
|
|
45
|
+
surface: "document-review",
|
|
46
|
+
claimType: "derived-field",
|
|
47
|
+
fieldOrBehavior: "statementPosition",
|
|
48
|
+
value: {
|
|
49
|
+
totalAmount: 84000,
|
|
50
|
+
creditAmount: 9100,
|
|
51
|
+
position: "credit-present",
|
|
52
|
+
},
|
|
53
|
+
status: "proposed",
|
|
54
|
+
impactLevel: "high",
|
|
55
|
+
inputClaimIds: [
|
|
56
|
+
{ claimId: "document.entity-1.statement.amount.corrected", role: "amount-input", supportStrength: "strong" },
|
|
57
|
+
{ claimId: "document.entity-1.statement.credit.corrected", role: "credit-input", supportStrength: "strong" },
|
|
58
|
+
],
|
|
59
|
+
createdAt: generatedAt,
|
|
60
|
+
updatedAt: generatedAt,
|
|
61
|
+
evidenceSummary: "Derived statement position from corrected source fields.",
|
|
62
|
+
sourceRef: "documents://entities/entity-1/periods/2026/resolved-fields/statement",
|
|
63
|
+
collectedBy: "survey-document-fixture",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: "document.entity-1.statement-position.original",
|
|
67
|
+
subjectType: "verified-record.period",
|
|
68
|
+
subjectId: "entity-1:2026",
|
|
69
|
+
surface: "document-review",
|
|
70
|
+
claimType: "derived-field",
|
|
71
|
+
fieldOrBehavior: "statementPosition",
|
|
72
|
+
value: {
|
|
73
|
+
totalAmount: 82000,
|
|
74
|
+
creditAmount: 8600,
|
|
75
|
+
position: "credit-present",
|
|
76
|
+
},
|
|
77
|
+
status: "stale",
|
|
78
|
+
impactLevel: "high",
|
|
79
|
+
inputClaimIds: [
|
|
80
|
+
{ claimId: "document.entity-1.statement.amount.original", role: "amount-input", supportStrength: "strong" },
|
|
81
|
+
{ claimId: "document.entity-1.statement.credit.original", role: "credit-input", supportStrength: "strong" },
|
|
82
|
+
],
|
|
83
|
+
createdAt: generatedAt,
|
|
84
|
+
updatedAt: generatedAt,
|
|
85
|
+
evidenceSummary: "Prior statement position derived from original source fields.",
|
|
86
|
+
sourceRef: "documents://entities/entity-1/periods/2026/resolved-fields/statement",
|
|
87
|
+
collectedBy: "survey-document-fixture",
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
function documentExtraction(id, sourceId, target, value, locator) {
|
|
92
|
+
return {
|
|
93
|
+
id: `document:extraction:${id}`,
|
|
94
|
+
sourceId,
|
|
95
|
+
target,
|
|
96
|
+
value,
|
|
97
|
+
confidence: 0.96,
|
|
98
|
+
locator,
|
|
99
|
+
excerpt: `${target}=${value}`,
|
|
100
|
+
extractor: "document-field-parser",
|
|
101
|
+
extractedAt: generatedAt,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function documentCandidateSet(target, originalId, originalValue, correctedId, correctedValue) {
|
|
105
|
+
return {
|
|
106
|
+
id: `document:candidates:${target}`,
|
|
107
|
+
target: `statement.${target}`,
|
|
108
|
+
selectedCandidateId: `document:candidate:${correctedId}`,
|
|
109
|
+
status: "needs-review",
|
|
110
|
+
rationale: "Corrected document supersedes the original source but still needs review.",
|
|
111
|
+
candidates: [
|
|
112
|
+
{
|
|
113
|
+
id: `document:candidate:${originalId}`,
|
|
114
|
+
extractionId: `document:extraction:${originalId}`,
|
|
115
|
+
value: originalValue,
|
|
116
|
+
confidence: 0.96,
|
|
117
|
+
sourceRank: 2,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: `document:candidate:${correctedId}`,
|
|
121
|
+
extractionId: `document:extraction:${correctedId}`,
|
|
122
|
+
value: correctedValue,
|
|
123
|
+
confidence: 0.96,
|
|
124
|
+
sourceRank: 1,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function documentClaim(id, target, candidateId, fieldOrBehavior, status) {
|
|
130
|
+
return {
|
|
131
|
+
id,
|
|
132
|
+
candidateSetId: `document:candidates:${target}`,
|
|
133
|
+
candidateId: `document:candidate:${candidateId}`,
|
|
134
|
+
subjectType: "verified-record.period",
|
|
135
|
+
subjectId: "entity-1:2026",
|
|
136
|
+
surface: "document-review",
|
|
137
|
+
claimType: "source-field",
|
|
138
|
+
fieldOrBehavior,
|
|
139
|
+
status,
|
|
140
|
+
impactLevel: "high",
|
|
141
|
+
collectedBy: "document-field-parser",
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
const generatedAt = "2026-05-31T16:00:00.000Z";
|
|
2
|
+
export const publicFieldReviewFixture = {
|
|
3
|
+
source: "survey.fixture.public-field-review",
|
|
4
|
+
generatedAt,
|
|
5
|
+
rawSources: [
|
|
6
|
+
{
|
|
7
|
+
id: "public-field:source:approved-page",
|
|
8
|
+
kind: "web-page",
|
|
9
|
+
sourceRef: "https://example.test/listings/example-program",
|
|
10
|
+
observedAt: "2026-05-30T18:00:00.000Z",
|
|
11
|
+
fetchedAt: "2026-05-30T18:00:00.000Z",
|
|
12
|
+
locatorScheme: "html",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "public-field:source:proposal-page",
|
|
16
|
+
kind: "web-page",
|
|
17
|
+
sourceRef: "https://example.test/listings/example-program",
|
|
18
|
+
observedAt: "2026-05-31T15:00:00.000Z",
|
|
19
|
+
fetchedAt: "2026-05-31T15:00:00.000Z",
|
|
20
|
+
locatorScheme: "html",
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
extractions: [
|
|
24
|
+
{
|
|
25
|
+
id: "public-field:extraction:approved",
|
|
26
|
+
sourceId: "public-field:source:approved-page",
|
|
27
|
+
target: "availabilityStatus",
|
|
28
|
+
value: "AVAILABLE",
|
|
29
|
+
confidence: 0.91,
|
|
30
|
+
locator: "html:field=availabilityStatus",
|
|
31
|
+
excerpt: "Availability is open for the example program.",
|
|
32
|
+
extractor: "example-field-review",
|
|
33
|
+
extractedAt: "2026-05-30T18:00:00.000Z",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "public-field:extraction:proposal",
|
|
37
|
+
sourceId: "public-field:source:proposal-page",
|
|
38
|
+
target: "availabilityStatus",
|
|
39
|
+
value: "WAITLIST",
|
|
40
|
+
confidence: 0.82,
|
|
41
|
+
locator: "html:field=availabilityStatus",
|
|
42
|
+
excerpt: "Join the waitlist for this listing.",
|
|
43
|
+
extractor: "example-crawl",
|
|
44
|
+
extractedAt: "2026-05-31T15:00:00.000Z",
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
candidateSets: [
|
|
48
|
+
{
|
|
49
|
+
id: "public-field:candidates:current",
|
|
50
|
+
target: "availabilityStatus",
|
|
51
|
+
selectedCandidateId: "public-field:candidate:approved",
|
|
52
|
+
status: "resolved",
|
|
53
|
+
candidates: [
|
|
54
|
+
{
|
|
55
|
+
id: "public-field:candidate:approved",
|
|
56
|
+
extractionId: "public-field:extraction:approved",
|
|
57
|
+
value: "AVAILABLE",
|
|
58
|
+
confidence: 0.91,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: "public-field:candidates:proposal",
|
|
64
|
+
target: "availabilityStatus",
|
|
65
|
+
status: "needs-review",
|
|
66
|
+
candidates: [
|
|
67
|
+
{
|
|
68
|
+
id: "public-field:candidate:proposal",
|
|
69
|
+
extractionId: "public-field:extraction:proposal",
|
|
70
|
+
value: "WAITLIST",
|
|
71
|
+
confidence: 0.82,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
reviewOutcomes: [
|
|
77
|
+
{
|
|
78
|
+
id: "public-field:review:approved",
|
|
79
|
+
candidateSetId: "public-field:candidates:current",
|
|
80
|
+
candidateId: "public-field:candidate:approved",
|
|
81
|
+
status: "verified",
|
|
82
|
+
actor: "example-operator",
|
|
83
|
+
reviewedAt: "2026-05-30T18:05:00.000Z",
|
|
84
|
+
rationale: "Operator approved the field source.",
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
claims: [
|
|
88
|
+
{
|
|
89
|
+
id: "public-field.entity-123.availability-status.current",
|
|
90
|
+
candidateSetId: "public-field:candidates:current",
|
|
91
|
+
candidateId: "public-field:candidate:approved",
|
|
92
|
+
subjectType: "public-record.entity",
|
|
93
|
+
subjectId: "entity-123",
|
|
94
|
+
surface: "public-record.profile",
|
|
95
|
+
claimType: "public-data.field",
|
|
96
|
+
fieldOrBehavior: "availabilityStatus",
|
|
97
|
+
impactLevel: "medium",
|
|
98
|
+
collectedBy: "example-field-review",
|
|
99
|
+
metadata: {
|
|
100
|
+
producer: {
|
|
101
|
+
slug: "example-program",
|
|
102
|
+
displayName: "Example Program",
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: "public-field.entity-123.availability-status.proposal-456",
|
|
108
|
+
candidateSetId: "public-field:candidates:proposal",
|
|
109
|
+
candidateId: "public-field:candidate:proposal",
|
|
110
|
+
subjectType: "public-record.entity",
|
|
111
|
+
subjectId: "entity-123",
|
|
112
|
+
surface: "public-record.profile",
|
|
113
|
+
claimType: "public-data.field-candidate",
|
|
114
|
+
fieldOrBehavior: "availabilityStatus",
|
|
115
|
+
impactLevel: "medium",
|
|
116
|
+
collectedBy: "example-crawl",
|
|
117
|
+
metadata: {
|
|
118
|
+
producer: {
|
|
119
|
+
proposalId: "proposal-456",
|
|
120
|
+
oldValue: "AVAILABLE",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { CandidateSet, ClaimTarget, DerivedClaimTarget, Extraction, RawSource, ReviewOutcome, SurveyInput } from "./types.js";
|
|
2
|
+
export interface SurveyInputBuilderArgs {
|
|
3
|
+
source: string;
|
|
4
|
+
generatedAt?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SurveyClaimRecord {
|
|
7
|
+
rawSource: RawSource;
|
|
8
|
+
extraction: Extraction;
|
|
9
|
+
candidateSet: CandidateSet;
|
|
10
|
+
reviewOutcome?: ReviewOutcome;
|
|
11
|
+
claim: ClaimTarget;
|
|
12
|
+
}
|
|
13
|
+
export interface SurveyObservationInput {
|
|
14
|
+
id: string;
|
|
15
|
+
rawSource: Omit<RawSource, "id"> & {
|
|
16
|
+
id?: string;
|
|
17
|
+
};
|
|
18
|
+
extraction: Omit<Extraction, "id" | "sourceId"> & {
|
|
19
|
+
id?: string;
|
|
20
|
+
};
|
|
21
|
+
candidate?: {
|
|
22
|
+
id?: string;
|
|
23
|
+
confidence?: number;
|
|
24
|
+
sourceRank?: number;
|
|
25
|
+
metadata?: Record<string, unknown>;
|
|
26
|
+
};
|
|
27
|
+
candidateSet?: {
|
|
28
|
+
id?: string;
|
|
29
|
+
status?: CandidateSet["status"];
|
|
30
|
+
rationale?: string;
|
|
31
|
+
metadata?: Record<string, unknown>;
|
|
32
|
+
};
|
|
33
|
+
reviewOutcome?: Omit<ReviewOutcome, "id" | "candidateSetId" | "candidateId"> & {
|
|
34
|
+
id?: string;
|
|
35
|
+
};
|
|
36
|
+
claim: Omit<ClaimTarget, "id" | "candidateSetId" | "candidateId"> & {
|
|
37
|
+
id?: string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export declare class SurveyInputBuilder {
|
|
41
|
+
private readonly source;
|
|
42
|
+
private readonly generatedAt;
|
|
43
|
+
private readonly rawSources;
|
|
44
|
+
private readonly extractions;
|
|
45
|
+
private readonly candidateSets;
|
|
46
|
+
private readonly reviewOutcomes;
|
|
47
|
+
private readonly claims;
|
|
48
|
+
private readonly derivedClaims;
|
|
49
|
+
constructor(args: SurveyInputBuilderArgs);
|
|
50
|
+
addRawSource(rawSource: RawSource): this;
|
|
51
|
+
addExtraction(extraction: Extraction): this;
|
|
52
|
+
addCandidateSet(candidateSet: CandidateSet): this;
|
|
53
|
+
addReviewOutcome(reviewOutcome: ReviewOutcome): this;
|
|
54
|
+
addClaim(claim: ClaimTarget): this;
|
|
55
|
+
addDerivedClaim(derivedClaim: DerivedClaimTarget): this;
|
|
56
|
+
addClaimRecord(record: SurveyClaimRecord): this;
|
|
57
|
+
addClaimRecords(records: SurveyClaimRecord[]): this;
|
|
58
|
+
addObservation(observation: SurveyObservationInput): this;
|
|
59
|
+
addObservations(observations: SurveyObservationInput[]): this;
|
|
60
|
+
build(): SurveyInput;
|
|
61
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
export class SurveyInputBuilder {
|
|
2
|
+
source;
|
|
3
|
+
generatedAt;
|
|
4
|
+
rawSources = new Map();
|
|
5
|
+
extractions = new Map();
|
|
6
|
+
candidateSets = new Map();
|
|
7
|
+
reviewOutcomes = new Map();
|
|
8
|
+
claims = new Map();
|
|
9
|
+
derivedClaims = new Map();
|
|
10
|
+
constructor(args) {
|
|
11
|
+
this.source = args.source;
|
|
12
|
+
this.generatedAt = args.generatedAt ?? new Date().toISOString();
|
|
13
|
+
}
|
|
14
|
+
addRawSource(rawSource) {
|
|
15
|
+
addUnique(this.rawSources, rawSource, "raw source");
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
addExtraction(extraction) {
|
|
19
|
+
addUnique(this.extractions, extraction, "extraction");
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
addCandidateSet(candidateSet) {
|
|
23
|
+
addUnique(this.candidateSets, candidateSet, "candidate set");
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
addReviewOutcome(reviewOutcome) {
|
|
27
|
+
addUnique(this.reviewOutcomes, reviewOutcome, "review outcome");
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
addClaim(claim) {
|
|
31
|
+
addUnique(this.claims, claim, "claim target");
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
addDerivedClaim(derivedClaim) {
|
|
35
|
+
addUnique(this.derivedClaims, derivedClaim, "derived claim target");
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
addClaimRecord(record) {
|
|
39
|
+
this.addRawSource(record.rawSource);
|
|
40
|
+
this.addExtraction(record.extraction);
|
|
41
|
+
this.addCandidateSet(record.candidateSet);
|
|
42
|
+
if (record.reviewOutcome)
|
|
43
|
+
this.addReviewOutcome(record.reviewOutcome);
|
|
44
|
+
this.addClaim(record.claim);
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
addClaimRecords(records) {
|
|
48
|
+
for (const record of records)
|
|
49
|
+
this.addClaimRecord(record);
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
addObservation(observation) {
|
|
53
|
+
return this.addClaimRecord(observationToClaimRecord(observation));
|
|
54
|
+
}
|
|
55
|
+
addObservations(observations) {
|
|
56
|
+
for (const observation of observations)
|
|
57
|
+
this.addObservation(observation);
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
build() {
|
|
61
|
+
return {
|
|
62
|
+
source: this.source,
|
|
63
|
+
generatedAt: this.generatedAt,
|
|
64
|
+
rawSources: [...this.rawSources.values()],
|
|
65
|
+
extractions: [...this.extractions.values()],
|
|
66
|
+
candidateSets: [...this.candidateSets.values()],
|
|
67
|
+
reviewOutcomes: [...this.reviewOutcomes.values()],
|
|
68
|
+
claims: [...this.claims.values()],
|
|
69
|
+
derivedClaims: [...this.derivedClaims.values()],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function observationToClaimRecord(observation) {
|
|
74
|
+
const ids = observationIds(observation.id, observation);
|
|
75
|
+
const value = observation.claim.value ?? observation.extraction.value;
|
|
76
|
+
const confidence = observation.candidate?.confidence ?? observation.extraction.confidence;
|
|
77
|
+
return {
|
|
78
|
+
rawSource: {
|
|
79
|
+
id: ids.sourceId,
|
|
80
|
+
...observation.rawSource,
|
|
81
|
+
},
|
|
82
|
+
extraction: {
|
|
83
|
+
id: ids.extractionId,
|
|
84
|
+
sourceId: ids.sourceId,
|
|
85
|
+
...observation.extraction,
|
|
86
|
+
},
|
|
87
|
+
candidateSet: {
|
|
88
|
+
id: ids.candidateSetId,
|
|
89
|
+
target: observation.extraction.target,
|
|
90
|
+
selectedCandidateId: ids.candidateId,
|
|
91
|
+
status: observation.candidateSet?.status ?? candidateSetStatusFor(observation.reviewOutcome?.status),
|
|
92
|
+
rationale: observation.candidateSet?.rationale,
|
|
93
|
+
metadata: observation.candidateSet?.metadata,
|
|
94
|
+
candidates: [{
|
|
95
|
+
id: ids.candidateId,
|
|
96
|
+
extractionId: ids.extractionId,
|
|
97
|
+
value,
|
|
98
|
+
confidence,
|
|
99
|
+
sourceRank: observation.candidate?.sourceRank,
|
|
100
|
+
metadata: observation.candidate?.metadata,
|
|
101
|
+
}],
|
|
102
|
+
},
|
|
103
|
+
reviewOutcome: observation.reviewOutcome
|
|
104
|
+
? {
|
|
105
|
+
id: ids.reviewOutcomeId,
|
|
106
|
+
candidateSetId: ids.candidateSetId,
|
|
107
|
+
candidateId: ids.candidateId,
|
|
108
|
+
...observation.reviewOutcome,
|
|
109
|
+
}
|
|
110
|
+
: undefined,
|
|
111
|
+
claim: {
|
|
112
|
+
id: ids.claimId,
|
|
113
|
+
candidateSetId: ids.candidateSetId,
|
|
114
|
+
candidateId: ids.candidateId,
|
|
115
|
+
...observation.claim,
|
|
116
|
+
value,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function observationIds(rootId, observation) {
|
|
121
|
+
const claimId = observation.claim.id ?? rootId;
|
|
122
|
+
return {
|
|
123
|
+
claimId,
|
|
124
|
+
sourceId: observation.rawSource.id ?? `${rootId}.source`,
|
|
125
|
+
extractionId: observation.extraction.id ?? `${rootId}.extraction`,
|
|
126
|
+
candidateId: observation.candidate?.id ?? `${rootId}.candidate`,
|
|
127
|
+
candidateSetId: observation.candidateSet?.id ?? `${rootId}.candidates`,
|
|
128
|
+
reviewOutcomeId: observation.reviewOutcome?.id ?? `${rootId}.review`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function candidateSetStatusFor(reviewStatus) {
|
|
132
|
+
if (!reviewStatus || reviewStatus === "proposed")
|
|
133
|
+
return "needs-review";
|
|
134
|
+
return "resolved";
|
|
135
|
+
}
|
|
136
|
+
function addUnique(map, item, label) {
|
|
137
|
+
if (map.has(item.id))
|
|
138
|
+
throw new Error(`Duplicate ${label} id: ${item.id}`);
|
|
139
|
+
map.set(item.id, item);
|
|
140
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { CandidateSetStatus, Candidate, CandidateSet, ClaimTarget, DerivedClaimTarget, Extraction, LocatorScheme, RawSource, RawSourceKind, ReviewOutcome, ReviewStatus, SurveyInput, } from "./types.js";
|
|
2
|
+
export { SurveyInputBuilder } from "./builder.js";
|
|
3
|
+
export type { SurveyClaimRecord, SurveyInputBuilderArgs, SurveyObservationInput } from "./builder.js";
|
|
4
|
+
export { buildSurveyTrustInput } from "./to-surface.js";
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
export function buildSurveyTrustInput(input) {
|
|
2
|
+
const rawSources = indexById(input.rawSources, "raw source");
|
|
3
|
+
const extractions = indexById(input.extractions, "extraction");
|
|
4
|
+
const candidateSets = indexById(input.candidateSets, "candidate set");
|
|
5
|
+
const reviewsByCandidateSet = groupBy(input.reviewOutcomes, (review) => review.candidateSetId);
|
|
6
|
+
const claims = [];
|
|
7
|
+
const evidence = [];
|
|
8
|
+
const events = [];
|
|
9
|
+
for (const projection of input.claims) {
|
|
10
|
+
const candidateSet = requireMapValue(candidateSets, projection.candidateSetId, "candidate set");
|
|
11
|
+
const candidate = selectCandidate(candidateSet, projection.candidateId);
|
|
12
|
+
const extraction = requireMapValue(extractions, candidate.extractionId, "extraction");
|
|
13
|
+
const rawSource = requireMapValue(rawSources, extraction.sourceId, "raw source");
|
|
14
|
+
const review = selectReview(reviewsByCandidateSet.get(candidateSet.id) ?? [], candidate.id);
|
|
15
|
+
const status = projection.status ?? statusFor({ candidateSet, candidate, review });
|
|
16
|
+
assertProducerDiscipline({ status, review, extraction, rawSource, projection });
|
|
17
|
+
const claimValue = projection.value ?? candidate.value;
|
|
18
|
+
const createdAt = projection.createdAt ?? extraction.extractedAt;
|
|
19
|
+
const updatedAt = projection.updatedAt ?? review?.reviewedAt ?? input.generatedAt;
|
|
20
|
+
const evidenceId = `${projection.id}.evidence.source`;
|
|
21
|
+
claims.push({
|
|
22
|
+
id: projection.id,
|
|
23
|
+
subjectType: projection.subjectType,
|
|
24
|
+
subjectId: projection.subjectId,
|
|
25
|
+
surface: projection.surface,
|
|
26
|
+
claimType: projection.claimType,
|
|
27
|
+
fieldOrBehavior: projection.fieldOrBehavior,
|
|
28
|
+
value: claimValue,
|
|
29
|
+
status,
|
|
30
|
+
createdAt,
|
|
31
|
+
updatedAt,
|
|
32
|
+
impactLevel: projection.impactLevel,
|
|
33
|
+
confidenceBasis: {
|
|
34
|
+
sourceQuality: "moderate",
|
|
35
|
+
extractionConfidence: candidate.confidence ?? extraction.confidence,
|
|
36
|
+
reviewerAuthority: status === "verified" || status === "assumed" ? "operator" : "none",
|
|
37
|
+
evidenceStrength: status === "verified" || status === "assumed" ? "moderate" : "weak",
|
|
38
|
+
impactLevel: projection.impactLevel,
|
|
39
|
+
...projection.confidenceBasis,
|
|
40
|
+
},
|
|
41
|
+
metadata: {
|
|
42
|
+
...projection.metadata,
|
|
43
|
+
survey: {
|
|
44
|
+
rawSourceId: rawSource.id,
|
|
45
|
+
extractionId: extraction.id,
|
|
46
|
+
candidateSetId: candidateSet.id,
|
|
47
|
+
candidateId: candidate.id,
|
|
48
|
+
reviewOutcomeId: review?.id,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
evidence.push({
|
|
53
|
+
id: evidenceId,
|
|
54
|
+
claimId: projection.id,
|
|
55
|
+
evidenceType: projection.evidenceType ?? evidenceTypeFor(rawSource),
|
|
56
|
+
method: projection.evidenceMethod ?? "extraction",
|
|
57
|
+
sourceRef: rawSource.sourceRef,
|
|
58
|
+
sourceLocator: extraction.locator,
|
|
59
|
+
excerptOrSummary: extraction.excerpt ?? `Extracted ${projection.fieldOrBehavior} from ${rawSource.kind}.`,
|
|
60
|
+
observedAt: rawSource.observedAt,
|
|
61
|
+
collectedBy: projection.collectedBy,
|
|
62
|
+
integrityRef: rawSource.checksum,
|
|
63
|
+
metadata: {
|
|
64
|
+
...rawSource.metadata,
|
|
65
|
+
...extraction.metadata,
|
|
66
|
+
...candidate.metadata,
|
|
67
|
+
rawSourceKind: rawSource.kind,
|
|
68
|
+
locatorScheme: rawSource.locatorScheme,
|
|
69
|
+
confidence: candidate.confidence ?? extraction.confidence,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
events.push({
|
|
73
|
+
id: `${projection.id}.event.${status}`,
|
|
74
|
+
claimId: projection.id,
|
|
75
|
+
status,
|
|
76
|
+
actor: projection.actor ?? review?.actor ?? projection.collectedBy,
|
|
77
|
+
method: projection.eventMethod ?? eventMethodFor(status, candidateSet),
|
|
78
|
+
evidenceIds: review?.evidenceIds?.length ? review.evidenceIds : [evidenceId],
|
|
79
|
+
createdAt: review?.reviewedAt ?? input.generatedAt,
|
|
80
|
+
verifiedAt: status === "verified" || status === "assumed" ? review?.reviewedAt ?? input.generatedAt : undefined,
|
|
81
|
+
notes: review?.rationale ?? candidateSet.rationale,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
for (const derived of input.derivedClaims ?? []) {
|
|
85
|
+
addDerivedClaim({ derived, claims, evidence, events });
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
schemaVersion: 3,
|
|
89
|
+
source: input.source,
|
|
90
|
+
claims,
|
|
91
|
+
evidence,
|
|
92
|
+
policies: [],
|
|
93
|
+
events,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function addDerivedClaim(input) {
|
|
97
|
+
const { derived } = input;
|
|
98
|
+
input.claims.push({
|
|
99
|
+
id: derived.id,
|
|
100
|
+
subjectType: derived.subjectType,
|
|
101
|
+
subjectId: derived.subjectId,
|
|
102
|
+
surface: derived.surface,
|
|
103
|
+
claimType: derived.claimType,
|
|
104
|
+
fieldOrBehavior: derived.fieldOrBehavior,
|
|
105
|
+
value: derived.value,
|
|
106
|
+
status: derived.status,
|
|
107
|
+
createdAt: derived.createdAt,
|
|
108
|
+
updatedAt: derived.updatedAt,
|
|
109
|
+
impactLevel: derived.impactLevel,
|
|
110
|
+
derivationEdges: derived.inputClaimIds.map((edge) => ({
|
|
111
|
+
inputClaimId: edge.claimId,
|
|
112
|
+
method: "rule-application",
|
|
113
|
+
role: edge.role,
|
|
114
|
+
supportStrength: edge.supportStrength,
|
|
115
|
+
})),
|
|
116
|
+
metadata: derived.metadata,
|
|
117
|
+
});
|
|
118
|
+
const evidenceId = `${derived.id}.evidence.calculation`;
|
|
119
|
+
input.evidence.push({
|
|
120
|
+
id: evidenceId,
|
|
121
|
+
claimId: derived.id,
|
|
122
|
+
evidenceType: "calculation_trace",
|
|
123
|
+
method: "validation",
|
|
124
|
+
sourceRef: derived.sourceRef,
|
|
125
|
+
excerptOrSummary: derived.evidenceSummary,
|
|
126
|
+
observedAt: derived.updatedAt,
|
|
127
|
+
collectedBy: derived.collectedBy,
|
|
128
|
+
});
|
|
129
|
+
input.events.push({
|
|
130
|
+
id: `${derived.id}.event.${derived.status}`,
|
|
131
|
+
claimId: derived.id,
|
|
132
|
+
status: derived.status,
|
|
133
|
+
actor: derived.collectedBy,
|
|
134
|
+
method: "rule-application",
|
|
135
|
+
evidenceIds: [evidenceId],
|
|
136
|
+
createdAt: derived.updatedAt,
|
|
137
|
+
verifiedAt: derived.status === "verified" ? derived.updatedAt : undefined,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function statusFor(input) {
|
|
141
|
+
if (input.review)
|
|
142
|
+
return input.review.status;
|
|
143
|
+
if (input.candidateSet.status === "resolved" && input.candidateSet.selectedCandidateId === input.candidate.id) {
|
|
144
|
+
return "proposed";
|
|
145
|
+
}
|
|
146
|
+
if (input.candidateSet.status === "conflict")
|
|
147
|
+
return "disputed";
|
|
148
|
+
return "proposed";
|
|
149
|
+
}
|
|
150
|
+
function assertProducerDiscipline(input) {
|
|
151
|
+
if ((input.status === "verified" || input.status === "assumed") && !input.review) {
|
|
152
|
+
throw new Error(`Claim ${input.projection.id} cannot be ${input.status} without a review outcome`);
|
|
153
|
+
}
|
|
154
|
+
if ((input.status === "verified" || input.status === "assumed") && !input.review?.actor) {
|
|
155
|
+
throw new Error(`Claim ${input.projection.id} cannot be ${input.status} without review actor authority`);
|
|
156
|
+
}
|
|
157
|
+
if ((input.status === "verified" || input.status === "assumed") && !input.review?.reviewedAt) {
|
|
158
|
+
throw new Error(`Claim ${input.projection.id} cannot be ${input.status} without reviewedAt`);
|
|
159
|
+
}
|
|
160
|
+
if (input.rawSource.kind !== "manual-entry" && !input.extraction.locator) {
|
|
161
|
+
throw new Error(`Claim ${input.projection.id} needs a source locator for ${input.rawSource.kind}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function selectCandidate(candidateSet, candidateId) {
|
|
165
|
+
const id = candidateId ?? candidateSet.selectedCandidateId ?? candidateSet.candidates[0]?.id;
|
|
166
|
+
const candidate = candidateSet.candidates.find((item) => item.id === id);
|
|
167
|
+
if (!candidate) {
|
|
168
|
+
throw new Error(`Candidate set ${candidateSet.id} does not contain candidate ${id ?? "<none>"}`);
|
|
169
|
+
}
|
|
170
|
+
return candidate;
|
|
171
|
+
}
|
|
172
|
+
function selectReview(reviews, candidateId) {
|
|
173
|
+
return reviews.find((review) => review.candidateId === candidateId) ?? reviews.find((review) => !review.candidateId);
|
|
174
|
+
}
|
|
175
|
+
function evidenceTypeFor(rawSource) {
|
|
176
|
+
if (rawSource.kind === "uploaded-document")
|
|
177
|
+
return "document_citation";
|
|
178
|
+
if (rawSource.kind === "web-page")
|
|
179
|
+
return "crawl_observation";
|
|
180
|
+
return "attestation";
|
|
181
|
+
}
|
|
182
|
+
function eventMethodFor(status, candidateSet) {
|
|
183
|
+
if (status === "verified")
|
|
184
|
+
return "survey-review";
|
|
185
|
+
if (status === "assumed")
|
|
186
|
+
return "survey-assumption";
|
|
187
|
+
if (status === "rejected")
|
|
188
|
+
return "survey-rejection";
|
|
189
|
+
if (candidateSet.status === "conflict")
|
|
190
|
+
return "candidate-conflict";
|
|
191
|
+
return "candidate-proposal";
|
|
192
|
+
}
|
|
193
|
+
function indexById(items, label) {
|
|
194
|
+
const map = new Map();
|
|
195
|
+
for (const item of items) {
|
|
196
|
+
if (map.has(item.id))
|
|
197
|
+
throw new Error(`Duplicate ${label} id: ${item.id}`);
|
|
198
|
+
map.set(item.id, item);
|
|
199
|
+
}
|
|
200
|
+
return map;
|
|
201
|
+
}
|
|
202
|
+
function requireMapValue(map, id, label) {
|
|
203
|
+
const value = map.get(id);
|
|
204
|
+
if (!value)
|
|
205
|
+
throw new Error(`Missing ${label}: ${id}`);
|
|
206
|
+
return value;
|
|
207
|
+
}
|
|
208
|
+
function groupBy(items, getKey) {
|
|
209
|
+
const map = new Map();
|
|
210
|
+
for (const item of items) {
|
|
211
|
+
const key = getKey(item);
|
|
212
|
+
map.set(key, [...(map.get(key) ?? []), item]);
|
|
213
|
+
}
|
|
214
|
+
return map;
|
|
215
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { ConfidenceBasis, EvidenceMethod, EvidenceType, ImpactLevel, TrustStatus } from "@kontourai/surface";
|
|
2
|
+
export type RawSourceKind = "uploaded-document" | "web-page" | "api-record" | "manual-entry";
|
|
3
|
+
export type LocatorScheme = "pdf" | "text" | "html" | "structured-field";
|
|
4
|
+
export interface RawSource {
|
|
5
|
+
id: string;
|
|
6
|
+
kind: RawSourceKind;
|
|
7
|
+
sourceRef: string;
|
|
8
|
+
observedAt: string;
|
|
9
|
+
fetchedAt?: string;
|
|
10
|
+
checksum?: string;
|
|
11
|
+
locatorScheme: LocatorScheme;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
export interface Extraction {
|
|
15
|
+
id: string;
|
|
16
|
+
sourceId: string;
|
|
17
|
+
target: string;
|
|
18
|
+
value: unknown;
|
|
19
|
+
confidence?: number;
|
|
20
|
+
locator?: string;
|
|
21
|
+
excerpt?: string;
|
|
22
|
+
extractor: string;
|
|
23
|
+
extractedAt: string;
|
|
24
|
+
metadata?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export type CandidateSetStatus = "resolved" | "needs-review" | "conflict";
|
|
27
|
+
export interface Candidate {
|
|
28
|
+
id: string;
|
|
29
|
+
extractionId: string;
|
|
30
|
+
value: unknown;
|
|
31
|
+
confidence?: number;
|
|
32
|
+
sourceRank?: number;
|
|
33
|
+
metadata?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
export interface CandidateSet {
|
|
36
|
+
id: string;
|
|
37
|
+
target: string;
|
|
38
|
+
candidates: Candidate[];
|
|
39
|
+
selectedCandidateId?: string;
|
|
40
|
+
status: CandidateSetStatus;
|
|
41
|
+
rationale?: string;
|
|
42
|
+
metadata?: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
export type ReviewStatus = Extract<TrustStatus, "verified" | "assumed" | "rejected" | "proposed">;
|
|
45
|
+
export interface ReviewOutcome {
|
|
46
|
+
id: string;
|
|
47
|
+
candidateSetId: string;
|
|
48
|
+
candidateId?: string;
|
|
49
|
+
status: ReviewStatus;
|
|
50
|
+
actor?: string;
|
|
51
|
+
reviewedAt?: string;
|
|
52
|
+
rationale?: string;
|
|
53
|
+
evidenceIds?: string[];
|
|
54
|
+
metadata?: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
export interface ClaimTarget {
|
|
57
|
+
id: string;
|
|
58
|
+
candidateSetId: string;
|
|
59
|
+
candidateId?: string;
|
|
60
|
+
subjectType: string;
|
|
61
|
+
subjectId: string;
|
|
62
|
+
surface: string;
|
|
63
|
+
claimType: string;
|
|
64
|
+
fieldOrBehavior: string;
|
|
65
|
+
value?: unknown;
|
|
66
|
+
status?: TrustStatus;
|
|
67
|
+
impactLevel: ImpactLevel;
|
|
68
|
+
createdAt?: string;
|
|
69
|
+
updatedAt?: string;
|
|
70
|
+
evidenceType?: EvidenceType;
|
|
71
|
+
evidenceMethod?: EvidenceMethod;
|
|
72
|
+
confidenceBasis?: ConfidenceBasis;
|
|
73
|
+
collectedBy: string;
|
|
74
|
+
actor?: string;
|
|
75
|
+
eventMethod?: string;
|
|
76
|
+
metadata?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
export interface DerivedClaimTarget {
|
|
79
|
+
id: string;
|
|
80
|
+
subjectType: string;
|
|
81
|
+
subjectId: string;
|
|
82
|
+
surface: string;
|
|
83
|
+
claimType: string;
|
|
84
|
+
fieldOrBehavior: string;
|
|
85
|
+
value: unknown;
|
|
86
|
+
status: TrustStatus;
|
|
87
|
+
impactLevel: ImpactLevel;
|
|
88
|
+
inputClaimIds: Array<{
|
|
89
|
+
claimId: string;
|
|
90
|
+
role?: string;
|
|
91
|
+
supportStrength?: "weak" | "moderate" | "strong";
|
|
92
|
+
}>;
|
|
93
|
+
createdAt: string;
|
|
94
|
+
updatedAt: string;
|
|
95
|
+
evidenceSummary: string;
|
|
96
|
+
sourceRef: string;
|
|
97
|
+
collectedBy: string;
|
|
98
|
+
metadata?: Record<string, unknown>;
|
|
99
|
+
}
|
|
100
|
+
export interface SurveyInput {
|
|
101
|
+
source: string;
|
|
102
|
+
generatedAt: string;
|
|
103
|
+
rawSources: RawSource[];
|
|
104
|
+
extractions: Extraction[];
|
|
105
|
+
candidateSets: CandidateSet[];
|
|
106
|
+
reviewOutcomes: ReviewOutcome[];
|
|
107
|
+
claims: ClaimTarget[];
|
|
108
|
+
derivedClaims?: DerivedClaimTarget[];
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kontourai/survey",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Producer-side source, extraction, candidate, and review contracts for projecting verified claims into Surface.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"private": false,
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/kontourai/survey.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://kontourai.io/survey",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/kontourai/survey/issues"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"exports": {
|
|
20
|
+
".": "./dist/src/index.js",
|
|
21
|
+
"./fixtures/public-field-review": "./dist/fixtures/public-field-review.js",
|
|
22
|
+
"./fixtures/corrected-document-candidates": "./dist/fixtures/corrected-document-candidates.js"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist/examples/",
|
|
26
|
+
"dist/fixtures/",
|
|
27
|
+
"dist/src/",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "rm -rf dist && tsc",
|
|
32
|
+
"typecheck": "tsc --noEmit",
|
|
33
|
+
"test": "npm run build && node --test dist/tests/*.test.js",
|
|
34
|
+
"verify": "npm run typecheck && npm test"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@kontourai/surface": "^0.5.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^25.6.0",
|
|
41
|
+
"typescript": "^5.8.0"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=20"
|
|
45
|
+
}
|
|
46
|
+
}
|