Survey owns
- — Raw source identity & retrieval context
- — Extraction observations & locators
- — Candidate sets and resolutions
- — Review outcomes
- — Projection into Surface TrustInput
review workflow for producing trustworthy Surface-ready claims
Before a claim reaches Surface, someone has to form it — from a source, an extraction, competing candidates, and a review. Survey is the small contract for that producer side: it makes those observations inspectable, gives reviewers a durable workflow, and projects the reviewed records into Surface-ready claims with provenance attached, without crawling, parsing, ranking, or absorbing your domain policy.
// proposed claim changes in → auditable review results out import { buildReviewWorkbenchSessionExportForSnapshot, createPersistentReviewSessionEventStore, mountReviewWorkbench } from "@kontourai/survey/review-workbench"; const session = { items: [registrationStatusReviewItem], activeItemName: "entity-123.registrationStatus", notesByItemName: {}, decisionsByItemName: {}, actorId: "[email protected]", reviewedAt: new Date().toISOString(), }; mountReviewWorkbench(document.querySelector("#review")!, session, { eventStore: createPersistentReviewSessionEventStore({ initialEvents, persist: ({ events, expectedEventCount }) => saveReviewEvents({ events, expectedEventCount }), }), }); const exported = buildReviewWorkbenchSessionExportForSnapshot( reviewedSnapshot, persistedEvents, ); const results = exported.results;
The producer pipeline
Where the value came from — a page, a document, an API record, a manual entry — with its reference, time, and checksum.
The value pulled from that source, with a locator, an excerpt, the extractor, and a confidence.
Competing values for the same target, kept side by side instead of silently dropped.
The outcome a human or policy assigns — verified, assumed, rejected, or needs-review.
A Surface-ready claim with its full provenance trail attached, ready to be reported on.
A deliberately narrow boundary
Survey does not crawl pages, parse PDFs, rank candidates, decide review policy, or claim a value is true. It gives producers a consistent contract so the same provenance shape reaches Surface every time.
Consumer adapter contract
A producer builds ReviewItem
records from its own queue, supplies a
ReviewPresentationAdapter
for readable labels and links, persists
ReviewSessionEvent
resources, and replays those events on the server before applying a
decision.
That gives future producers a clear checklist for trustworthy claims: source identity, extraction locator, candidate history, reviewer action, actor/time, and the Surface projection are all explicit before the claim is published.
Read the integration guide →import { buildReviewItemPresentation, buildReviewWorkbenchSessionExportForSnapshot, type ReviewPresentationAdapter } from "@kontourai/survey/review-workbench"; const adapter = { labelForTarget: (target) => target === "registrationStatus" ? "Registration status" : undefined, summarizeValue: (value) => humanizeProductValue(value), linkForReviewItem: (item) => ({ label: item.metadata.producer?.displayName, href: "/review/" + encodeURIComponent(item.metadata.name), }), linkForTraceRef: (ref) => ref.kind === "claim" ? { href: "/claims/" + ref.value } : undefined, } satisfies ReviewPresentationAdapter; const readable = buildReviewItemPresentation(reviewItem, adapter); const exported = buildReviewWorkbenchSessionExportForSnapshot( reviewedSnapshot, persistedEvents, );
Authoring helpers
fieldObservation() One scalar field value with its source, extraction, review, and claim defaults filled in. repeatedObservation() A repeated field or entity list described as one aggregate observation. candidateReviewRecord() Multiple candidates for one target, assembled into a shared candidate set with links. reviewedCandidateResolution() Attaches a review outcome to the selected candidate and supersedes the rest. ReviewPresentationAdapter Product-owned labels, value summaries, and source/trace links for generic Survey review records. buildReviewItemPresentation() Turns a ReviewItem plus adapter hooks into human-readable review copy without changing canonical data. buildReviewResultPresentation() Explains a derived review result and selected value while keeping write authority on the product server. buildReviewWorkbenchSessionExportForSnapshot() Replays persisted review events against the reviewed snapshot before deriving selected candidates. validateReviewSessionEventsForSnapshot() Reports stale item or candidate references before a producer applies review results. uploadedDocumentSource() A stable RawSource for a document a producer already retrieved. apiRecordSource() A stable RawSource for a structured record pulled from an API. webPageSource() A stable RawSource for a crawled web page, with locator scheme and checksum. manualEntrySource() A stable RawSource for a value entered by hand, kept inspectable like the rest. Review apply contract
The workbench gives downstream products the same session, event, decision, and selected-candidate mechanics. That removes boilerplate from review flows without turning Survey into a product-specific approval engine.
A server apply path should load the current product record, replay persisted review events against the reviewed snapshot, derive results with Survey, validate that the target is still current, and stamp the mutating actor from authenticated product context. Browser exports are display and audit data, not write authority.
import { buildReviewWorkbenchSessionExportForSnapshot } from "@kontourai/survey/review-workbench"; const current = await loadProductRecord(recordId); const snapshot = await loadReviewedSnapshot(reviewId); const events = await loadPersistedReviewEvents(reviewId); const exported = buildReviewWorkbenchSessionExportForSnapshot( snapshot, events, ); for (const result of exported.results) { assertTargetStillMatches(current, result); await applyProductPolicy({ selectedCandidateId: result.selectedCandidateId, selectedValue: result.selectedValue, actor: auth.user.id, }); }
Example use case
A crawler reads a registration status off a public record and needs
to preserve the extraction before it becomes a claim. With
fieldObservation,
the source, extraction, review outcome, and claim travel together —
so Surface can report not just the value, but where it came from
and how fresh it is.
Conflicting candidates don't disappear. A losing source stays on the
trail as superseded,
and an unresolved conflict projects to Surface as
disputed.
import { fieldObservation, SurveyInputBuilder } from "@kontourai/survey"; const input = new SurveyInputBuilder({ source: "crawler:run-1" }) .addObservation(fieldObservation({ id: "entity-123.status.current", field: "registrationStatus", value: "ACTIVE", rawSource: { kind: "web-page", sourceRef: "https://records.test/123", observedAt: now(), locatorScheme: "html", }, extraction: { confidence: 0.97, locator: "css:#registration-status", extractor: "example-crawler", extractedAt: now(), }, reviewOutcome: { status: "verified" }, claim: { subjectType: "public-record.entity", subjectId: "entity-123", claimType: "public-data.field", impactLevel: "medium", collectedBy: "example-crawler", }, })) .build();
Built for Surface
buildSurveyTrustInput
projects Survey records into a Surface
TrustInput.
From there, Surface owns claim status, evidence, dependencies,
freshness, and the trust reports humans and agents inspect.
Survey records
source → extraction → candidate → review → claim
buildSurveyTrustInput()
───────────────────────────────
Surface TrustInput
verified registrationStatus = ACTIVE
evidence web-page · css:#registration-status
freshness owned by Surface policy