@kontourai/survey 1.11.0 → 1.13.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/dist/example-data/public-directory-review-resource.d.ts +2 -0
- package/dist/example-data/public-directory-review-resource.js +1 -0
- package/dist/examples/review-workbench/downstream-public-directory-adapter.js +3 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/review-resource.d.ts +47 -0
- package/dist/src/review-workbench/review-queue-session.d.ts +30 -0
- package/dist/src/review-workbench/review-queue-session.js +30 -0
- package/dist/src/review-workbench/review-session-replay.js +7 -2
- package/dist/src/review-workbench/review-workbench-css.generated.js +615 -1417
- package/dist/src/review-workbench/review-workbench-data.d.ts +4 -0
- package/dist/src/review-workbench/review-workbench-data.js +172 -0
- package/dist/src/review-workbench/review-workbench-element.d.ts +5 -1
- package/dist/src/review-workbench/review-workbench-element.js +86 -3
- package/dist/src/review-workbench/review-workbench.css +615 -1417
- package/dist/src/review-workbench/review-workbench.d.ts +22 -2
- package/dist/src/review-workbench/review-workbench.js +513 -536
- package/dist/src/review-workbench/review-workbench.standalone.css +615 -1418
- package/package.json +1 -1
|
@@ -40,6 +40,7 @@ export declare const publicDirectoryReviewItemExample: {
|
|
|
40
40
|
confidence: number;
|
|
41
41
|
extractor: string;
|
|
42
42
|
extractedAt: string;
|
|
43
|
+
model?: undefined;
|
|
43
44
|
};
|
|
44
45
|
claimTarget: {
|
|
45
46
|
claimId: string;
|
|
@@ -91,6 +92,7 @@ export declare const publicDirectoryReviewItemExample: {
|
|
|
91
92
|
target: string;
|
|
92
93
|
confidence: number;
|
|
93
94
|
extractor: string;
|
|
95
|
+
model: string;
|
|
94
96
|
extractedAt: string;
|
|
95
97
|
};
|
|
96
98
|
claimTarget: {
|
|
@@ -110,7 +110,8 @@ function proposedReviewCandidate(proposal, field, diff, selectedRole) {
|
|
|
110
110
|
sourceRef: diff.sourceUrl ?? proposal.sourceUrl,
|
|
111
111
|
observedAt: proposal.createdAt,
|
|
112
112
|
excerpt: diff.excerpt ?? `Proposed ${field} value from downstream extraction.`,
|
|
113
|
-
extractor:
|
|
113
|
+
extractor: "downstream-directory-extractor",
|
|
114
|
+
model: proposal.extractionModel,
|
|
114
115
|
extractedAt: proposal.createdAt,
|
|
115
116
|
confidence: diff.confidence,
|
|
116
117
|
sourceRank: selectedRole === "proposed" ? 1 : 2,
|
|
@@ -193,6 +194,7 @@ function candidateExtraction(args, extractionId) {
|
|
|
193
194
|
target: args.field,
|
|
194
195
|
confidence: args.confidence,
|
|
195
196
|
extractor: args.extractor,
|
|
197
|
+
...(args.model ? { model: args.model } : {}),
|
|
196
198
|
extractedAt: args.extractedAt,
|
|
197
199
|
};
|
|
198
200
|
}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type { CandidateSetStatus, Candidate, CandidateSet, ClaimTarget, EscalationDimension, EscalationRecord, Extraction, Interpretation, LocatorScheme, ProvenanceResolution, RawSource, RawSourceKind, ReviewAuthorizing, ReviewAuthorizingAuthorizedAction, ReviewAuthorizingExchange, ReviewAuthorizingExplicitStatement, ReviewAuthorizingKind, ReviewOutcome, ReviewStatus, SurveyInput, } from "./types.js";
|
|
2
2
|
export { SURVEY_INPUT_CONTRACT_VERSION } from "./types.js";
|
|
3
3
|
export { reviewResourceApiVersion } from "./review-resource.js";
|
|
4
|
-
export type { CandidateRole, ClaimTargetHint, ProducerPolicy, ExtractionReference, ResourceEnvelope, ResourceMetadata, ReviewActor, ReviewCandidate, ReviewDecision, ReviewDecisionMode, ReviewDecisionSpec, ReviewDecisionStatus, ReviewItem, ReviewItemSpec, ReviewItemStatus, ReviewLocator, ReviewResource, ReviewResourceApiVersion, ReviewResourceKind, ReviewSession, ReviewSessionEvent, ReviewSessionEventSpec, ReviewSessionEventStatus, ReviewSessionEventType, ReviewSessionSpec, ReviewSessionStatus, SourceReference, SurveyRecordProjectionHint, } from "./review-resource.js";
|
|
4
|
+
export type { CandidateRole, ClaimTargetHint, ProducerPolicy, ExtractionReference, ResourceEnvelope, ResourceMetadata, ReviewActor, ReviewCandidate, ReviewDecision, ReviewDecisionMode, ReviewDecisionSpec, ReviewDecisionStatus, ReviewItem, ReviewItemSpec, ReviewItemStatus, ReviewLocator, ReviewResource, ReviewResourceApiVersion, ReviewResourceKind, ReviewSession, ReviewSessionEvent, ReviewSessionEventSpec, ReviewSessionEventStatus, ReviewSessionEventType, ReviewSessionSpec, ReviewSessionStatus, ReviewValueDescriptor, ReviewValueType, SourceReference, SurveyRecordProjectionHint, } from "./review-resource.js";
|
|
5
5
|
export { candidateReviewRecord, candidateSetStatusFor, SurveyInputBuilder } from "./builder.js";
|
|
6
6
|
export type { CandidateReviewRecordInput, SurveyClaimRecord, SurveyInputBuilderArgs, SurveyObservationInput, } from "./builder.js";
|
|
7
7
|
export { reviewedCandidateResolution } from "./reviewed-candidate-resolution.js";
|
|
@@ -35,7 +35,16 @@ export interface ExtractionReference {
|
|
|
35
35
|
extractionId?: string;
|
|
36
36
|
target: string;
|
|
37
37
|
confidence?: number;
|
|
38
|
+
/** The extraction tool/pipeline that produced this candidate (e.g. a crawler or parser). */
|
|
38
39
|
extractor?: string;
|
|
40
|
+
/**
|
|
41
|
+
* The model or model-version that generated this candidate, when the producer
|
|
42
|
+
* knows it (e.g. an LLM id or a dated extraction-model tag). Distinct from
|
|
43
|
+
* `extractor` (the tool): a reviewer wants to know *which model* proposed a
|
|
44
|
+
* value for trust/calibration. Producer-provided provenance; Survey only
|
|
45
|
+
* carries and displays it.
|
|
46
|
+
*/
|
|
47
|
+
model?: string;
|
|
39
48
|
extractedAt?: string;
|
|
40
49
|
}
|
|
41
50
|
export interface ClaimTargetHint {
|
|
@@ -96,6 +105,28 @@ export interface ReviewCandidate {
|
|
|
96
105
|
projection?: SurveyRecordProjectionHint;
|
|
97
106
|
producer?: Record<string, unknown>;
|
|
98
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Well-known neutral value-type vocabulary for {@link ReviewValueDescriptor}.
|
|
110
|
+
* Survey defines NO field-schema system of its own; this deliberately MIRRORS
|
|
111
|
+
* the shape an upstream field-schema owner already uses (e.g. traverse's
|
|
112
|
+
* `TargetFieldSchema.type` / `ExtractionProposal.valueType`), so a producer can
|
|
113
|
+
* carry a reviewed field's declared type down to the review UI WITHOUT Survey
|
|
114
|
+
* importing that owner's package (structural match, zero coupling).
|
|
115
|
+
*/
|
|
116
|
+
export type ReviewValueType = "string" | "number" | "boolean" | "date" | "enum" | "array" | "object";
|
|
117
|
+
/**
|
|
118
|
+
* Optional, producer-supplied descriptor of a reviewed field's declared value
|
|
119
|
+
* shape. Purely descriptive: the workbench uses it ONLY to pick a typed editor
|
|
120
|
+
* (an enum `<select>`, a date/number input) and to validate a reviewer's edit
|
|
121
|
+
* before "Use proposed". Survey never re-derives, coerces, or overrides a
|
|
122
|
+
* candidate's value from it — a producer can still surface an out-of-shape
|
|
123
|
+
* candidate, which is exactly what a typed reviewer catches.
|
|
124
|
+
*/
|
|
125
|
+
export interface ReviewValueDescriptor {
|
|
126
|
+
type: ReviewValueType;
|
|
127
|
+
/** Allowed values — meaningful with `type: "enum"`; ignored otherwise. */
|
|
128
|
+
enumValues?: string[];
|
|
129
|
+
}
|
|
99
130
|
export interface ReviewItemSpec {
|
|
100
131
|
target: string;
|
|
101
132
|
candidates: ReviewCandidate[];
|
|
@@ -104,6 +135,13 @@ export interface ReviewItemSpec {
|
|
|
104
135
|
rationale?: string;
|
|
105
136
|
producerPolicy?: ProducerPolicy;
|
|
106
137
|
projection?: SurveyRecordProjectionHint;
|
|
138
|
+
/**
|
|
139
|
+
* Optional neutral descriptor of the reviewed field's declared value type.
|
|
140
|
+
* When present, the workbench renders a typed editor and validates a
|
|
141
|
+
* reviewer's inline edit against it before accepting the proposed value.
|
|
142
|
+
* Absent → a plain text editor with no validation (today's behavior).
|
|
143
|
+
*/
|
|
144
|
+
valueDescriptor?: ReviewValueDescriptor;
|
|
107
145
|
}
|
|
108
146
|
export interface ReviewItemStatus {
|
|
109
147
|
observedCandidateCount?: number;
|
|
@@ -130,6 +168,15 @@ export interface ReviewDecisionSpec {
|
|
|
130
168
|
* their own admissible block. */
|
|
131
169
|
authorizing?: ReviewAuthorizing;
|
|
132
170
|
projection?: SurveyRecordProjectionHint;
|
|
171
|
+
/**
|
|
172
|
+
* Reviewer-edited override for the proposed candidate's value, captured when the
|
|
173
|
+
* reviewer edits the inline proposed-value editor before choosing "Use proposed".
|
|
174
|
+
* Only meaningful when the decision selects the proposed candidate. Downstream
|
|
175
|
+
* consumers should read the effective value as `editedValue ?? <selected candidate value>`
|
|
176
|
+
* rather than assuming the candidate's original value was applied verbatim.
|
|
177
|
+
* Additive/optional: absent means the candidate's original value was used unchanged.
|
|
178
|
+
*/
|
|
179
|
+
editedValue?: unknown;
|
|
133
180
|
}
|
|
134
181
|
export interface ReviewDecisionStatus {
|
|
135
182
|
appliedToClaimIds?: string[];
|
|
@@ -9,6 +9,12 @@ export interface ReviewWorkbenchState {
|
|
|
9
9
|
readonly decision?: ReviewWorkbenchDecision;
|
|
10
10
|
readonly reviewedAt: string;
|
|
11
11
|
readonly actorId: string;
|
|
12
|
+
/**
|
|
13
|
+
* Reviewer-edited override for the item's proposed value (inline edit in the
|
|
14
|
+
* field-diff card). Additive/optional: undefined means no edit was made and the
|
|
15
|
+
* proposed candidate's original value applies.
|
|
16
|
+
*/
|
|
17
|
+
readonly editedValue?: unknown;
|
|
12
18
|
}
|
|
13
19
|
export interface ReviewQueueSessionState {
|
|
14
20
|
readonly items: readonly ReviewItem[];
|
|
@@ -17,6 +23,13 @@ export interface ReviewQueueSessionState {
|
|
|
17
23
|
readonly decisionsByItemName: Readonly<Record<string, ReviewWorkbenchDecision>>;
|
|
18
24
|
readonly reviewedAt: string;
|
|
19
25
|
readonly actorId: string;
|
|
26
|
+
/**
|
|
27
|
+
* Reviewer-edited overrides for proposed values, keyed by ReviewItem name.
|
|
28
|
+
* Additive/optional: a session built before this field existed behaves exactly
|
|
29
|
+
* as before (every lookup resolves to undefined, meaning "use the candidate's
|
|
30
|
+
* original value").
|
|
31
|
+
*/
|
|
32
|
+
readonly editedValuesByItemName?: Readonly<Record<string, unknown>>;
|
|
20
33
|
}
|
|
21
34
|
export interface ReviewSessionSummary {
|
|
22
35
|
readonly accepted: number;
|
|
@@ -53,8 +66,25 @@ export declare function deriveQueueRowStatus(item: ReviewItem, session: ReviewQu
|
|
|
53
66
|
export declare function nextUnresolvedItemName(session: ReviewQueueSessionState): string | undefined;
|
|
54
67
|
export declare function reviewSessionSummary(session: ReviewQueueSessionState): ReviewSessionSummary;
|
|
55
68
|
export declare function candidateForDecision(item: ReviewItem, decision: ReviewWorkbenchDecision): ReviewCandidate;
|
|
69
|
+
/**
|
|
70
|
+
* The value that should actually be applied for a decision: the reviewer's inline
|
|
71
|
+
* edit when one was made for an accept-proposed decision, otherwise the selected
|
|
72
|
+
* candidate's original value. Consumers reading `ReviewWorkbenchResult` should
|
|
73
|
+
* prefer `effectiveValue`/`effectiveDisplayValue`, which are already computed with
|
|
74
|
+
* this rule; this helper exists for callers deriving the value from raw session
|
|
75
|
+
* state directly.
|
|
76
|
+
*/
|
|
77
|
+
export declare function effectiveValueForDecision(item: ReviewItem, decision: ReviewWorkbenchDecision, editedValue?: unknown): unknown;
|
|
56
78
|
export declare function selectedCandidateRole(state: ReviewWorkbenchState): ReviewCandidate["role"] | undefined;
|
|
57
79
|
export declare function buildReviewSessionResource(session: ReviewQueueSessionState, events?: readonly ReviewSessionEvent[], sessionName?: string): ReviewSession;
|
|
58
80
|
export declare function buildReviewSessionEvents(session: ReviewQueueSessionState, sessionName?: string): ReviewSessionEvent[];
|
|
59
81
|
export declare function replayReviewSessionEvents(startState: ReviewQueueSessionState, events: readonly ReviewSessionEvent[]): ReviewQueueSessionState;
|
|
82
|
+
/**
|
|
83
|
+
* Detects the explicit "clear this ReviewItem's decision" replay signal (emitted
|
|
84
|
+
* by the workbench's "Change" / undo control): a decision event whose
|
|
85
|
+
* `data.workbenchDecision` is the literal `null` sentinel, as opposed to `undefined`
|
|
86
|
+
* (no decision info present — event is ignored by replay, same as before this
|
|
87
|
+
* feature existed).
|
|
88
|
+
*/
|
|
89
|
+
export declare function isClearedWorkbenchDecisionEvent(event: ReviewSessionEvent): boolean;
|
|
60
90
|
export declare function buildReviewSessionEvent(session: ReviewQueueSessionState, spec: Omit<ReviewSessionEventSpec, "actor">): ReviewSessionEvent;
|
|
@@ -37,6 +37,7 @@ export function initialReviewQueueSessionState(items = reviewWorkbenchQueueExamp
|
|
|
37
37
|
activeItemName: items[0]?.metadata.name ?? "",
|
|
38
38
|
notesByItemName: {},
|
|
39
39
|
decisionsByItemName: {},
|
|
40
|
+
editedValuesByItemName: {},
|
|
40
41
|
reviewedAt: "2026-06-04T00:00:00.000Z",
|
|
41
42
|
actorId: "review-workbench-operator",
|
|
42
43
|
};
|
|
@@ -47,6 +48,7 @@ export function currentReviewWorkbenchState(session) {
|
|
|
47
48
|
item,
|
|
48
49
|
note: session.notesByItemName[item.metadata.name] ?? "",
|
|
49
50
|
decision: session.decisionsByItemName[item.metadata.name],
|
|
51
|
+
editedValue: session.editedValuesByItemName?.[item.metadata.name],
|
|
50
52
|
reviewedAt: session.reviewedAt,
|
|
51
53
|
actorId: session.actorId,
|
|
52
54
|
};
|
|
@@ -117,6 +119,18 @@ export function candidateForDecision(item, decision) {
|
|
|
117
119
|
}
|
|
118
120
|
return candidate;
|
|
119
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* The value that should actually be applied for a decision: the reviewer's inline
|
|
124
|
+
* edit when one was made for an accept-proposed decision, otherwise the selected
|
|
125
|
+
* candidate's original value. Consumers reading `ReviewWorkbenchResult` should
|
|
126
|
+
* prefer `effectiveValue`/`effectiveDisplayValue`, which are already computed with
|
|
127
|
+
* this rule; this helper exists for callers deriving the value from raw session
|
|
128
|
+
* state directly.
|
|
129
|
+
*/
|
|
130
|
+
export function effectiveValueForDecision(item, decision, editedValue) {
|
|
131
|
+
const candidate = candidateForDecision(item, decision);
|
|
132
|
+
return decision === "accept-proposed" && editedValue !== undefined ? editedValue : candidate.value;
|
|
133
|
+
}
|
|
120
134
|
export function selectedCandidateRole(state) {
|
|
121
135
|
if (!state.decision) {
|
|
122
136
|
return undefined;
|
|
@@ -238,6 +252,10 @@ export function replayReviewSessionEvents(startState, events) {
|
|
|
238
252
|
}
|
|
239
253
|
if ((event.spec.eventType === "decision-changed" || event.spec.eventType === "decision-submitted")
|
|
240
254
|
&& event.spec.reviewItemName) {
|
|
255
|
+
if (isClearedWorkbenchDecisionEvent(event)) {
|
|
256
|
+
const { [event.spec.reviewItemName]: _removed, ...remainingDecisions } = session.decisionsByItemName;
|
|
257
|
+
return { ...session, decisionsByItemName: remainingDecisions };
|
|
258
|
+
}
|
|
241
259
|
const decision = workbenchDecisionFromEvent(event);
|
|
242
260
|
return decision
|
|
243
261
|
? {
|
|
@@ -252,6 +270,18 @@ export function replayReviewSessionEvents(startState, events) {
|
|
|
252
270
|
return session;
|
|
253
271
|
}, startState);
|
|
254
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* Detects the explicit "clear this ReviewItem's decision" replay signal (emitted
|
|
275
|
+
* by the workbench's "Change" / undo control): a decision event whose
|
|
276
|
+
* `data.workbenchDecision` is the literal `null` sentinel, as opposed to `undefined`
|
|
277
|
+
* (no decision info present — event is ignored by replay, same as before this
|
|
278
|
+
* feature existed).
|
|
279
|
+
*/
|
|
280
|
+
export function isClearedWorkbenchDecisionEvent(event) {
|
|
281
|
+
return event.spec.data !== undefined
|
|
282
|
+
&& "workbenchDecision" in event.spec.data
|
|
283
|
+
&& event.spec.data.workbenchDecision === null;
|
|
284
|
+
}
|
|
255
285
|
export function buildReviewSessionEvent(session, spec) {
|
|
256
286
|
return {
|
|
257
287
|
apiVersion: reviewResourceApiVersion,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { candidateForDecision, workbenchDecisionDefinitions, } from "./review-queue-session.js";
|
|
1
|
+
import { candidateForDecision, isClearedWorkbenchDecisionEvent, workbenchDecisionDefinitions, } from "./review-queue-session.js";
|
|
2
2
|
export function validateReviewSessionEventsForSnapshot(snapshot, events) {
|
|
3
3
|
const itemsByName = new Map(snapshot.items.map((item) => [item.metadata.name, item]));
|
|
4
4
|
const sequenceIssues = validateEventSequence(events);
|
|
@@ -35,7 +35,12 @@ export function validateReviewSessionEventsForSnapshot(snapshot, events) {
|
|
|
35
35
|
message: `ReviewSessionEvent ${event.metadata.name} is a decision event but does not reference a ReviewItem.`,
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
-
if (event.spec.eventType === "decision-changed" || event.spec.eventType === "decision-submitted")
|
|
38
|
+
if ((event.spec.eventType === "decision-changed" || event.spec.eventType === "decision-submitted")
|
|
39
|
+
&& isClearedWorkbenchDecisionEvent(event)) {
|
|
40
|
+
// Explicit "clear this ReviewItem's decision" signal (undo). No candidate/status
|
|
41
|
+
// expectations apply — the event carries no selected candidate.
|
|
42
|
+
}
|
|
43
|
+
else if (event.spec.eventType === "decision-changed" || event.spec.eventType === "decision-submitted") {
|
|
39
44
|
const decision = replayableWorkbenchDecision(event.spec.data?.workbenchDecision);
|
|
40
45
|
if (!decision) {
|
|
41
46
|
issues.push({
|