@kontourai/survey 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +211 -9
  2. package/dist/examples/review-workbench/downstream-public-directory-adapter.d.ts +3 -0
  3. package/dist/examples/review-workbench/downstream-public-directory-adapter.js +262 -0
  4. package/dist/examples/review-workbench/review-queue-session.d.ts +54 -0
  5. package/dist/examples/review-workbench/review-queue-session.js +122 -0
  6. package/dist/examples/review-workbench/review-surface-preview.d.ts +55 -0
  7. package/dist/examples/review-workbench/review-surface-preview.js +104 -0
  8. package/dist/examples/review-workbench/review-workbench-data.d.ts +261 -0
  9. package/dist/examples/review-workbench/review-workbench-data.js +199 -0
  10. package/dist/examples/review-workbench/review-workbench.d.ts +7 -0
  11. package/dist/examples/review-workbench/review-workbench.js +488 -0
  12. package/dist/fixtures/downstream-public-directory-proposal.d.ts +100 -0
  13. package/dist/fixtures/downstream-public-directory-proposal.js +59 -0
  14. package/dist/fixtures/public-directory-review-resource.d.ts +156 -0
  15. package/dist/fixtures/public-directory-review-resource.js +157 -0
  16. package/dist/fixtures/regulated-document-review-resource.d.ts +121 -0
  17. package/dist/fixtures/regulated-document-review-resource.js +131 -0
  18. package/dist/src/builder.d.ts +4 -1
  19. package/dist/src/builder.js +7 -0
  20. package/dist/src/index.d.ts +8 -4
  21. package/dist/src/index.js +4 -2
  22. package/dist/src/learning-projections.d.ts +19 -0
  23. package/dist/src/learning-projections.js +77 -0
  24. package/dist/src/raw-source.d.ts +15 -0
  25. package/dist/src/raw-source.js +22 -0
  26. package/dist/src/review-proof.d.ts +28 -0
  27. package/dist/src/review-proof.js +58 -1
  28. package/dist/src/review-resource.d.ts +111 -0
  29. package/dist/src/review-resource.js +1 -0
  30. package/dist/src/to-surface.js +226 -13
  31. package/dist/src/types.d.ts +17 -1
  32. package/package.json +10 -4
@@ -0,0 +1,122 @@
1
+ import { publicDirectoryReviewItemFixture, reviewWorkbenchQueueFixtures } from "./review-workbench-data.js";
2
+ export const workbenchDecisionDefinitions = {
3
+ "accept-proposed": {
4
+ label: "Accept proposed",
5
+ effect: "Proposed value becomes the verified review outcome.",
6
+ candidateRole: "proposed",
7
+ status: "verified",
8
+ },
9
+ "keep-current": {
10
+ label: "Keep current",
11
+ effect: "Current value remains the verified review outcome.",
12
+ candidateRole: "current",
13
+ status: "verified",
14
+ },
15
+ "reject-proposed": {
16
+ label: "Reject proposed",
17
+ effect: "Proposed value is rejected and the current value remains unmodified.",
18
+ candidateRole: "proposed",
19
+ status: "rejected",
20
+ },
21
+ };
22
+ export function initialReviewWorkbenchState(item = publicDirectoryReviewItemFixture) {
23
+ return {
24
+ item,
25
+ note: "",
26
+ decision: undefined,
27
+ reviewedAt: "2026-06-04T00:00:00.000Z",
28
+ actorId: "review-workbench-operator",
29
+ };
30
+ }
31
+ export function initialReviewQueueSessionState(items = reviewWorkbenchQueueFixtures) {
32
+ return {
33
+ items,
34
+ activeItemName: items[0]?.metadata.name ?? "",
35
+ notesByItemName: {},
36
+ decisionsByItemName: {},
37
+ reviewedAt: "2026-06-04T00:00:00.000Z",
38
+ actorId: "review-workbench-operator",
39
+ };
40
+ }
41
+ export function currentReviewWorkbenchState(session) {
42
+ const item = currentReviewItem(session);
43
+ return {
44
+ item,
45
+ note: session.notesByItemName[item.metadata.name] ?? "",
46
+ decision: session.decisionsByItemName[item.metadata.name],
47
+ reviewedAt: session.reviewedAt,
48
+ actorId: session.actorId,
49
+ };
50
+ }
51
+ export function currentReviewItem(session) {
52
+ const item = session.items.find((entry) => entry.metadata.name === session.activeItemName) ?? session.items[0];
53
+ if (!item) {
54
+ throw new Error("Review queue session has no ReviewItems.");
55
+ }
56
+ return item;
57
+ }
58
+ export function deriveQueueRowStatus(item, session) {
59
+ const decision = session.decisionsByItemName[item.metadata.name];
60
+ if (decision === "reject-proposed") {
61
+ return "rejected";
62
+ }
63
+ if (decision === "accept-proposed" || decision === "keep-current" || item.spec.candidateSetStatus === "resolved") {
64
+ return "resolved";
65
+ }
66
+ if (item.spec.candidateSetStatus === "escalated") {
67
+ return "escalated";
68
+ }
69
+ if (item.metadata.name === session.activeItemName) {
70
+ return "in-review";
71
+ }
72
+ return "pending";
73
+ }
74
+ export function nextUnresolvedItemName(session) {
75
+ const activeIndex = session.items.findIndex((item) => item.metadata.name === session.activeItemName);
76
+ const orderedItems = [
77
+ ...session.items.slice(Math.max(activeIndex, 0) + 1),
78
+ ...session.items.slice(0, Math.max(activeIndex, 0) + 1),
79
+ ];
80
+ return orderedItems.find((item) => deriveQueueRowStatus(item, session) === "pending")?.metadata.name;
81
+ }
82
+ export function reviewSessionSummary(session) {
83
+ return session.items.reduce((summary, item) => {
84
+ const decision = session.decisionsByItemName[item.metadata.name];
85
+ if (decision === "accept-proposed") {
86
+ return { ...summary, accepted: summary.accepted + 1 };
87
+ }
88
+ if (decision === "keep-current") {
89
+ return { ...summary, keptCurrent: summary.keptCurrent + 1 };
90
+ }
91
+ if (decision === "reject-proposed") {
92
+ return { ...summary, rejected: summary.rejected + 1 };
93
+ }
94
+ if (item.spec.candidateSetStatus === "escalated") {
95
+ return { ...summary, escalated: summary.escalated + 1 };
96
+ }
97
+ if (item.spec.candidateSetStatus === "resolved") {
98
+ return { ...summary, accepted: summary.accepted + 1 };
99
+ }
100
+ return { ...summary, unresolved: summary.unresolved + 1 };
101
+ }, {
102
+ accepted: 0,
103
+ keptCurrent: 0,
104
+ rejected: 0,
105
+ escalated: 0,
106
+ unresolved: 0,
107
+ });
108
+ }
109
+ export function candidateForDecision(item, decision) {
110
+ const definition = workbenchDecisionDefinitions[decision];
111
+ const candidate = item.spec.candidates.find((entry) => entry.role === definition.candidateRole);
112
+ if (!candidate) {
113
+ throw new Error(`ReviewItem ${item.metadata.name} has no ${definition.candidateRole} candidate.`);
114
+ }
115
+ return candidate;
116
+ }
117
+ export function selectedCandidateRole(state) {
118
+ if (!state.decision) {
119
+ return undefined;
120
+ }
121
+ return workbenchDecisionDefinitions[state.decision].candidateRole;
122
+ }
@@ -0,0 +1,55 @@
1
+ import { type ReviewDecision, type ReviewItem } from "../../src/review-resource.js";
2
+ export interface SurfaceProjectionPreview {
3
+ readonly canonicalClaim: PreviewClaim;
4
+ readonly candidateHistory: PreviewCandidateHistory[];
5
+ readonly sourceEvidence: PreviewSourceEvidence;
6
+ readonly reviewEvent?: PreviewReviewEvent;
7
+ readonly integrityPosture: PreviewIntegrityPosture;
8
+ readonly authorityTrace: PreviewAuthorityTrace;
9
+ readonly postureDisclaimer: string;
10
+ }
11
+ export interface PreviewClaim {
12
+ readonly candidateId: string;
13
+ readonly claimId: string;
14
+ readonly value: string;
15
+ readonly status: string;
16
+ }
17
+ export interface PreviewCandidateHistory {
18
+ readonly candidateId: string;
19
+ readonly value: string;
20
+ readonly historyLabel: string;
21
+ }
22
+ export interface PreviewSourceEvidence {
23
+ readonly sourceRef: string;
24
+ readonly sourceId: string;
25
+ readonly excerpt: string;
26
+ readonly extractionId: string;
27
+ readonly extractor: string;
28
+ readonly observedAt: string;
29
+ readonly sourceAuthority?: PreviewSourceAuthority;
30
+ }
31
+ export interface PreviewSourceAuthority {
32
+ readonly authorityClass: string;
33
+ readonly declaredBy: string;
34
+ readonly scope: string;
35
+ }
36
+ export interface PreviewReviewEvent {
37
+ readonly actor: string;
38
+ readonly reviewedAt: string;
39
+ readonly status: string;
40
+ readonly rationale: string;
41
+ readonly reviewOutcomeId: string;
42
+ }
43
+ export interface PreviewIntegrityPosture {
44
+ readonly candidateSetId: string;
45
+ readonly rawSourceId: string;
46
+ readonly extractionId: string;
47
+ readonly checksum: string;
48
+ }
49
+ export interface PreviewAuthorityTrace {
50
+ readonly status: "empty" | "provided";
51
+ readonly label: string;
52
+ readonly detail: string;
53
+ }
54
+ export declare function buildSurfaceProjectionPreview(item: ReviewItem, decision: ReviewDecision | undefined): SurfaceProjectionPreview | undefined;
55
+ export declare function formatValue(value: unknown): string;
@@ -0,0 +1,104 @@
1
+ export function buildSurfaceProjectionPreview(item, decision) {
2
+ const selectedCandidate = selectedPreviewCandidate(item, decision);
3
+ if (!selectedCandidate || !decision) {
4
+ return undefined;
5
+ }
6
+ const projection = decision.spec.projection ?? selectedCandidate.projection;
7
+ return {
8
+ canonicalClaim: buildPreviewClaim(selectedCandidate, decision, projection),
9
+ candidateHistory: buildCandidateHistory(item, selectedCandidate),
10
+ sourceEvidence: buildSourceEvidence(selectedCandidate),
11
+ reviewEvent: buildReviewEvent(decision, projection),
12
+ integrityPosture: buildIntegrityPosture(item, selectedCandidate, projection),
13
+ authorityTrace: portableAuthorityTrace(selectedCandidate.producer?.authorityTrace),
14
+ postureDisclaimer: postureDisclaimer(),
15
+ };
16
+ }
17
+ export function formatValue(value) {
18
+ return typeof value === "string" ? value : JSON.stringify(value);
19
+ }
20
+ function selectedPreviewCandidate(item, decision) {
21
+ if (!decision?.spec.candidateId) {
22
+ return undefined;
23
+ }
24
+ const candidate = item.spec.candidates.find((entry) => entry.id === decision.spec.candidateId);
25
+ if (!candidate) {
26
+ throw new Error(`ReviewItem ${item.metadata.name} has no candidate ${decision.spec.candidateId}.`);
27
+ }
28
+ return candidate;
29
+ }
30
+ function buildPreviewClaim(candidate, decision, projection) {
31
+ return {
32
+ candidateId: candidate.id,
33
+ claimId: projection?.claimId ?? candidate.claimTarget.claimId ?? candidate.claimTarget.fieldOrBehavior,
34
+ value: formatValue(candidate.value),
35
+ status: decision.spec.status,
36
+ };
37
+ }
38
+ function buildCandidateHistory(item, selectedCandidate) {
39
+ return item.spec.candidates
40
+ .filter((candidate) => candidate.id !== selectedCandidate.id)
41
+ .map((candidate) => ({
42
+ candidateId: candidate.id,
43
+ value: formatValue(candidate.value),
44
+ historyLabel: "Unselected candidate history",
45
+ }));
46
+ }
47
+ function buildSourceEvidence(candidate) {
48
+ return {
49
+ sourceRef: candidate.source.sourceRef,
50
+ sourceId: candidate.source.sourceId ?? candidate.source.sourceRef,
51
+ excerpt: candidate.locator?.excerpt ?? "No source excerpt provided.",
52
+ extractionId: candidate.extraction.extractionId ?? "not provided",
53
+ extractor: candidate.extraction.extractor ?? "unknown",
54
+ observedAt: candidate.source.observedAt ?? candidate.source.fetchedAt ?? "unknown",
55
+ sourceAuthority: sourceAuthorityFromProducer(candidate.producer?.sourceAuthority),
56
+ };
57
+ }
58
+ function buildReviewEvent(decision, projection) {
59
+ return {
60
+ actor: decision.spec.actor?.id ?? "unknown",
61
+ reviewedAt: decision.spec.reviewedAt ?? "not recorded",
62
+ status: decision.spec.status,
63
+ rationale: decision.spec.rationale || "No reviewer rationale provided.",
64
+ reviewOutcomeId: projection?.reviewOutcomeId ?? "not provided",
65
+ };
66
+ }
67
+ function buildIntegrityPosture(item, candidate, projection) {
68
+ return {
69
+ candidateSetId: projection?.candidateSetId ?? item.spec.projection?.candidateSetId ?? "not provided",
70
+ rawSourceId: projection?.rawSourceId ?? candidate.source.sourceId ?? "not provided",
71
+ extractionId: projection?.extractionId ?? candidate.extraction.extractionId ?? "not provided",
72
+ checksum: candidate.source.checksum ?? "not provided",
73
+ };
74
+ }
75
+ function postureDisclaimer() {
76
+ return "Survey records source and review posture for projection; it does not validate real-world truth.";
77
+ }
78
+ function sourceAuthorityFromProducer(value) {
79
+ if (!isRecord(value)) {
80
+ return undefined;
81
+ }
82
+ return {
83
+ authorityClass: String(value.authorityClass ?? "not provided"),
84
+ declaredBy: String(value.declaredBy ?? "not provided"),
85
+ scope: String(value.scope ?? "not provided"),
86
+ };
87
+ }
88
+ function portableAuthorityTrace(value) {
89
+ if (Array.isArray(value) && value.length > 0) {
90
+ return {
91
+ status: "provided",
92
+ label: "Portable authority trace provided",
93
+ detail: `${value.length} authority trace entr${value.length === 1 ? "y" : "ies"} supplied by the fixture.`,
94
+ };
95
+ }
96
+ return {
97
+ status: "empty",
98
+ label: "Empty / not provided",
99
+ detail: "No portable authority trace is present. SourceAuthority metadata is shown as source evidence and is not promoted into authorityTrace.",
100
+ };
101
+ }
102
+ function isRecord(value) {
103
+ return typeof value === "object" && value !== null && !Array.isArray(value);
104
+ }
@@ -0,0 +1,261 @@
1
+ import { type ReviewItem } from "../../src/review-resource.js";
2
+ export declare const publicDirectoryReviewItemFixture: {
3
+ apiVersion: "survey.kontourai.io/v1alpha1";
4
+ kind: "ReviewItem";
5
+ metadata: {
6
+ name: string;
7
+ labels: {
8
+ domain: string;
9
+ };
10
+ producer: {
11
+ displayName: string;
12
+ slug: string;
13
+ };
14
+ };
15
+ spec: {
16
+ target: string;
17
+ selectedCandidateId: string;
18
+ candidateSetStatus: "resolved";
19
+ rationale: string;
20
+ candidates: ({
21
+ id: string;
22
+ role: "current";
23
+ value: string;
24
+ confidence: number;
25
+ source: {
26
+ sourceId: string;
27
+ sourceRef: string;
28
+ kind: "web-page";
29
+ observedAt: string;
30
+ fetchedAt: string;
31
+ locatorScheme: "html";
32
+ };
33
+ locator: {
34
+ scheme: "html";
35
+ locator: string;
36
+ excerpt: string;
37
+ };
38
+ extraction: {
39
+ extractionId: string;
40
+ target: string;
41
+ confidence: number;
42
+ extractor: string;
43
+ extractedAt: string;
44
+ };
45
+ claimTarget: {
46
+ claimId: string;
47
+ subjectType: string;
48
+ subjectId: string;
49
+ surface: string;
50
+ claimType: string;
51
+ fieldOrBehavior: string;
52
+ impactLevel: "medium";
53
+ collectedBy: string;
54
+ };
55
+ projection: {
56
+ rawSourceId: string;
57
+ extractionId: string;
58
+ candidateSetId: string;
59
+ candidateId: string;
60
+ reviewOutcomeId: string;
61
+ claimId: string;
62
+ };
63
+ producer: {
64
+ sourceAuthority: {
65
+ authorityClass: string;
66
+ declaredBy: string;
67
+ scope: string;
68
+ };
69
+ proposalId?: undefined;
70
+ oldValue?: undefined;
71
+ };
72
+ } | {
73
+ id: string;
74
+ role: "proposed";
75
+ value: string;
76
+ confidence: number;
77
+ source: {
78
+ sourceId: string;
79
+ sourceRef: string;
80
+ kind: "web-page";
81
+ observedAt: string;
82
+ fetchedAt: string;
83
+ locatorScheme: "html";
84
+ };
85
+ locator: {
86
+ scheme: "html";
87
+ locator: string;
88
+ excerpt: string;
89
+ };
90
+ extraction: {
91
+ extractionId: string;
92
+ target: string;
93
+ confidence: number;
94
+ extractor: string;
95
+ extractedAt: string;
96
+ };
97
+ claimTarget: {
98
+ claimId: string;
99
+ subjectType: string;
100
+ subjectId: string;
101
+ surface: string;
102
+ claimType: string;
103
+ fieldOrBehavior: string;
104
+ impactLevel: "medium";
105
+ collectedBy: string;
106
+ };
107
+ projection: {
108
+ rawSourceId: string;
109
+ extractionId: string;
110
+ candidateSetId: string;
111
+ candidateId: string;
112
+ claimId: string;
113
+ reviewOutcomeId?: undefined;
114
+ };
115
+ producer: {
116
+ proposalId: string;
117
+ oldValue: string;
118
+ sourceAuthority: {
119
+ authorityClass: string;
120
+ declaredBy: string;
121
+ scope: string;
122
+ };
123
+ };
124
+ })[];
125
+ };
126
+ status: {
127
+ observedCandidateCount: number;
128
+ selectedCandidateId: string;
129
+ reviewDecisionName: string;
130
+ };
131
+ };
132
+ export declare const reviewWorkbenchQueueFixtures: (ReviewItem | {
133
+ apiVersion: "survey.kontourai.io/v1alpha1";
134
+ kind: "ReviewItem";
135
+ metadata: {
136
+ name: string;
137
+ labels: {
138
+ domain: string;
139
+ };
140
+ producer: {
141
+ displayName: string;
142
+ slug: string;
143
+ };
144
+ };
145
+ spec: {
146
+ target: string;
147
+ selectedCandidateId: string;
148
+ candidateSetStatus: "resolved";
149
+ rationale: string;
150
+ candidates: ({
151
+ id: string;
152
+ role: "current";
153
+ value: string;
154
+ confidence: number;
155
+ source: {
156
+ sourceId: string;
157
+ sourceRef: string;
158
+ kind: "web-page";
159
+ observedAt: string;
160
+ fetchedAt: string;
161
+ locatorScheme: "html";
162
+ };
163
+ locator: {
164
+ scheme: "html";
165
+ locator: string;
166
+ excerpt: string;
167
+ };
168
+ extraction: {
169
+ extractionId: string;
170
+ target: string;
171
+ confidence: number;
172
+ extractor: string;
173
+ extractedAt: string;
174
+ };
175
+ claimTarget: {
176
+ claimId: string;
177
+ subjectType: string;
178
+ subjectId: string;
179
+ surface: string;
180
+ claimType: string;
181
+ fieldOrBehavior: string;
182
+ impactLevel: "medium";
183
+ collectedBy: string;
184
+ };
185
+ projection: {
186
+ rawSourceId: string;
187
+ extractionId: string;
188
+ candidateSetId: string;
189
+ candidateId: string;
190
+ reviewOutcomeId: string;
191
+ claimId: string;
192
+ };
193
+ producer: {
194
+ sourceAuthority: {
195
+ authorityClass: string;
196
+ declaredBy: string;
197
+ scope: string;
198
+ };
199
+ proposalId?: undefined;
200
+ oldValue?: undefined;
201
+ };
202
+ } | {
203
+ id: string;
204
+ role: "proposed";
205
+ value: string;
206
+ confidence: number;
207
+ source: {
208
+ sourceId: string;
209
+ sourceRef: string;
210
+ kind: "web-page";
211
+ observedAt: string;
212
+ fetchedAt: string;
213
+ locatorScheme: "html";
214
+ };
215
+ locator: {
216
+ scheme: "html";
217
+ locator: string;
218
+ excerpt: string;
219
+ };
220
+ extraction: {
221
+ extractionId: string;
222
+ target: string;
223
+ confidence: number;
224
+ extractor: string;
225
+ extractedAt: string;
226
+ };
227
+ claimTarget: {
228
+ claimId: string;
229
+ subjectType: string;
230
+ subjectId: string;
231
+ surface: string;
232
+ claimType: string;
233
+ fieldOrBehavior: string;
234
+ impactLevel: "medium";
235
+ collectedBy: string;
236
+ };
237
+ projection: {
238
+ rawSourceId: string;
239
+ extractionId: string;
240
+ candidateSetId: string;
241
+ candidateId: string;
242
+ claimId: string;
243
+ reviewOutcomeId?: undefined;
244
+ };
245
+ producer: {
246
+ proposalId: string;
247
+ oldValue: string;
248
+ sourceAuthority: {
249
+ authorityClass: string;
250
+ declaredBy: string;
251
+ scope: string;
252
+ };
253
+ };
254
+ })[];
255
+ };
256
+ status: {
257
+ observedCandidateCount: number;
258
+ selectedCandidateId: string;
259
+ reviewDecisionName: string;
260
+ };
261
+ })[];