@kontourai/survey 0.4.1 → 0.4.3

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 CHANGED
@@ -185,11 +185,13 @@ assumed.
185
185
 
186
186
  ## Source-of-authority observations
187
187
 
188
- Use `sourceOfAuthorityObservation` when a producer treats the raw source as
189
- authoritative for the extracted target: an official publication, registration
190
- platform page, policy document, contract record, or system-of-record response.
191
- The helper does not decide whether the source is truly authoritative. It
192
- enforces record discipline around the producer's declared source posture.
188
+ Use `sourceOfAuthorityObservationBuilder` when a producer treats the raw source
189
+ as authoritative for the extracted target: an official publication,
190
+ registration platform page, policy document, contract record, or
191
+ system-of-record response. The builder does not decide whether the source is
192
+ truly authoritative. It guides producers through the source, extraction,
193
+ source-authority posture, review outcome, and claim fields that make the
194
+ declared source posture auditable.
193
195
 
194
196
  Verified or assumed source-of-authority observations require:
195
197
 
@@ -207,14 +209,14 @@ reserved for actor, credential, role, organization, policy, or system authority.
207
209
  ```ts
208
210
  import {
209
211
  buildSurveyTrustInput,
210
- sourceOfAuthorityObservation,
212
+ sourceOfAuthorityObservationBuilder,
211
213
  SurveyInputBuilder,
212
214
  uploadedDocumentSource,
213
215
  } from "@kontourai/survey";
214
216
 
215
217
  const observedAt = new Date().toISOString();
216
218
  const rawSource = uploadedDocumentSource({
217
- sourceRef: "https://rules.example.test/standard-deduction.pdf",
219
+ sourceRef: "https://rules.example.test/thresholds.pdf",
218
220
  observedAt,
219
221
  checksum: "abc123",
220
222
  locatorScheme: "pdf",
@@ -223,35 +225,36 @@ const rawSource = uploadedDocumentSource({
223
225
  const surveyInput = new SurveyInputBuilder({
224
226
  source: "rule-producer:run-1",
225
227
  })
226
- .addObservation(sourceOfAuthorityObservation({
227
- id: "rule.standard-deduction.mfj.2026",
228
- field: "federal.standardDeduction.mfj.2026",
229
- value: 30000,
230
- sourceAuthority: {
228
+ .addObservation(sourceOfAuthorityObservationBuilder({
229
+ id: "rule.threshold.primary.2026",
230
+ field: "regulatedRule.threshold.primary.2026",
231
+ value: 1200,
232
+ })
233
+ .withSourceAuthority({
231
234
  authorityClass: "official_publication",
232
235
  scope: {
233
- jurisdiction: "federal",
236
+ jurisdiction: "example",
234
237
  productArea: "regulated-rule",
235
- taxYear: 2026,
238
+ effectiveYear: 2026,
236
239
  },
237
240
  sourceVersion: "2026",
238
241
  declaredBy: "rule-producer",
239
- },
240
- rawSource,
241
- extraction: {
242
+ })
243
+ .fromSource(rawSource)
244
+ .withExtraction({
242
245
  confidence: 0.94,
243
- locator: "pdf:page=12;table=standard-deduction;row=mfj",
246
+ locator: "pdf:page=12;table=thresholds;row=primary",
244
247
  extractor: "rule-producer",
245
248
  extractedAt: observedAt,
246
- },
247
- reviewOutcome: {
249
+ })
250
+ .withReviewOutcome({
248
251
  status: "verified",
249
252
  actor: "rule-reviewer",
250
253
  reviewedAt: new Date().toISOString(),
251
- },
252
- claim: {
254
+ })
255
+ .forClaim({
253
256
  subjectType: "regulated-rule",
254
- subjectId: "federal:standard-deduction:mfj:2026",
257
+ subjectId: "example:threshold:primary:2026",
255
258
  surface: "regulated.rules",
256
259
  claimType: "regulated.rule-value",
257
260
  status: "verified",
@@ -259,18 +262,25 @@ const surveyInput = new SurveyInputBuilder({
259
262
  evidenceType: "policy_rule",
260
263
  evidenceMethod: "extraction",
261
264
  collectedBy: "rule-producer",
262
- },
263
- }))
265
+ })
266
+ .build())
264
267
  .build();
265
268
 
266
269
  const trustInput = buildSurveyTrustInput(surveyInput);
267
270
  ```
268
271
 
269
- Contextual claims such as "this return position is compliant" or "this camp is
270
- eligible for an 8-year-old in June" are not source-of-authority observations.
272
+ `sourceOfAuthorityObservation` remains available as the lower-level object
273
+ factory when a producer already has the full observation input assembled.
274
+
275
+ Contextual claims such as "this submission is compliant" or "this listing is
276
+ eligible for a specific requester" are not source-of-authority observations.
271
277
  They are Surface claims with Claim Dependencies on source-of-authority claims
272
278
  and other product facts. The vertical product owns that domain logic.
273
279
 
280
+ For the reusable producer workflow, including manual confirmation state,
281
+ source references, Survey review outcomes, and Surface report boundaries, see
282
+ [Source-Authority Review Pattern](docs/source-authority-review-pattern.md).
283
+
274
284
  ## Reviewed candidate resolutions
275
285
 
276
286
  Use `reviewedCandidateResolution` when a producer has multiple candidate
@@ -13,7 +13,7 @@ export { fieldObservation } from "./field-observation.js";
13
13
  export type { FieldObservationInput } from "./field-observation.js";
14
14
  export { repeatedObservation } from "./repeated-observation.js";
15
15
  export type { RepeatedObservationInput } from "./repeated-observation.js";
16
- export { sourceOfAuthorityObservation } from "./source-of-authority-observation.js";
17
- export type { SourceAuthorityClass, SourceAuthorityMetadata, SourceOfAuthorityObservationInput, } from "./source-of-authority-observation.js";
16
+ export { sourceOfAuthorityObservation, sourceOfAuthorityObservationBuilder, SourceOfAuthorityObservationBuilder, } from "./source-of-authority-observation.js";
17
+ export type { SourceAuthorityClass, SourceAuthorityMetadata, SourceOfAuthorityObservationBuilderArgs, SourceOfAuthorityObservationInput, } from "./source-of-authority-observation.js";
18
18
  export { apiRecordSource, manualEntrySource, uploadedDocumentSource, webPageSource, } from "./raw-source.js";
19
19
  export type { ApiRecordSourceInput, ChecksumInput, ManualEntrySourceInput, RawSourceInput, UploadedDocumentSourceInput, WebPageSourceInput, } from "./raw-source.js";
package/dist/src/index.js CHANGED
@@ -5,5 +5,5 @@ export { buildSurveyTrustInput } from "./to-surface.js";
5
5
  export { buildCanonicalReviewProofPayload, buildReviewProofAnchor, canonicalReviewProofJson, hashCanonicalReviewProofPayload, } from "./review-proof.js";
6
6
  export { fieldObservation } from "./field-observation.js";
7
7
  export { repeatedObservation } from "./repeated-observation.js";
8
- export { sourceOfAuthorityObservation } from "./source-of-authority-observation.js";
8
+ export { sourceOfAuthorityObservation, sourceOfAuthorityObservationBuilder, SourceOfAuthorityObservationBuilder, } from "./source-of-authority-observation.js";
9
9
  export { apiRecordSource, manualEntrySource, uploadedDocumentSource, webPageSource, } from "./raw-source.js";
@@ -28,4 +28,24 @@ export interface SourceOfAuthorityObservationInput<TValue> {
28
28
  candidateSet?: SurveyObservationInput["candidateSet"];
29
29
  metadata?: Record<string, unknown>;
30
30
  }
31
+ export interface SourceOfAuthorityObservationBuilderArgs<TValue> {
32
+ id: string;
33
+ field: string;
34
+ value: TValue;
35
+ }
36
+ export declare class SourceOfAuthorityObservationBuilder<TValue> {
37
+ private readonly state;
38
+ constructor(args: SourceOfAuthorityObservationBuilderArgs<TValue>);
39
+ static create<TValue>(args: SourceOfAuthorityObservationBuilderArgs<TValue>): SourceOfAuthorityObservationBuilder<TValue>;
40
+ withSourceAuthority(sourceAuthority: SourceAuthorityMetadata): this;
41
+ fromSource(rawSource: SourceOfAuthorityObservationInput<TValue>["rawSource"]): this;
42
+ withExtraction(extraction: SourceOfAuthorityObservationInput<TValue>["extraction"]): this;
43
+ withReviewOutcome(reviewOutcome: SourceOfAuthorityObservationInput<TValue>["reviewOutcome"]): this;
44
+ forClaim(claim: SourceOfAuthorityObservationInput<TValue>["claim"]): this;
45
+ withCandidate(candidate: SourceOfAuthorityObservationInput<TValue>["candidate"]): this;
46
+ withCandidateSet(candidateSet: SourceOfAuthorityObservationInput<TValue>["candidateSet"]): this;
47
+ withMetadata(metadata: Record<string, unknown>): this;
48
+ build(): SurveyObservationInput;
49
+ }
50
+ export declare function sourceOfAuthorityObservationBuilder<TValue>(args: SourceOfAuthorityObservationBuilderArgs<TValue>): SourceOfAuthorityObservationBuilder<TValue>;
31
51
  export declare function sourceOfAuthorityObservation<TValue>(input: SourceOfAuthorityObservationInput<TValue>): SurveyObservationInput;
@@ -1,4 +1,51 @@
1
1
  import { buildObservation } from "./observation-helper.js";
2
+ export class SourceOfAuthorityObservationBuilder {
3
+ state;
4
+ constructor(args) {
5
+ this.state = { ...args };
6
+ }
7
+ static create(args) {
8
+ return new SourceOfAuthorityObservationBuilder(args);
9
+ }
10
+ withSourceAuthority(sourceAuthority) {
11
+ this.state.sourceAuthority = sourceAuthority;
12
+ return this;
13
+ }
14
+ fromSource(rawSource) {
15
+ this.state.rawSource = rawSource;
16
+ return this;
17
+ }
18
+ withExtraction(extraction) {
19
+ this.state.extraction = extraction;
20
+ return this;
21
+ }
22
+ withReviewOutcome(reviewOutcome) {
23
+ this.state.reviewOutcome = reviewOutcome;
24
+ return this;
25
+ }
26
+ forClaim(claim) {
27
+ this.state.claim = claim;
28
+ return this;
29
+ }
30
+ withCandidate(candidate) {
31
+ this.state.candidate = candidate;
32
+ return this;
33
+ }
34
+ withCandidateSet(candidateSet) {
35
+ this.state.candidateSet = candidateSet;
36
+ return this;
37
+ }
38
+ withMetadata(metadata) {
39
+ this.state.metadata = metadata;
40
+ return this;
41
+ }
42
+ build() {
43
+ return sourceOfAuthorityObservation(completeBuilderState(this.state));
44
+ }
45
+ }
46
+ export function sourceOfAuthorityObservationBuilder(args) {
47
+ return SourceOfAuthorityObservationBuilder.create(args);
48
+ }
2
49
  export function sourceOfAuthorityObservation(input) {
3
50
  assertSourceAuthority(input.sourceAuthority, input.id);
4
51
  assertVerifiedPosture(input);
@@ -26,6 +73,27 @@ export function sourceOfAuthorityObservation(input) {
26
73
  defaultExcerpt: `${input.field}: ${valueSummary(input.value)}`,
27
74
  });
28
75
  }
76
+ function completeBuilderState(state) {
77
+ return {
78
+ id: state.id,
79
+ field: state.field,
80
+ value: state.value,
81
+ sourceAuthority: requireBuilderField(state.sourceAuthority, state.id, "sourceAuthority"),
82
+ rawSource: requireBuilderField(state.rawSource, state.id, "rawSource"),
83
+ extraction: requireBuilderField(state.extraction, state.id, "extraction"),
84
+ reviewOutcome: state.reviewOutcome,
85
+ claim: requireBuilderField(state.claim, state.id, "claim"),
86
+ candidate: state.candidate,
87
+ candidateSet: state.candidateSet,
88
+ metadata: state.metadata,
89
+ };
90
+ }
91
+ function requireBuilderField(value, observationId, field) {
92
+ if (value === undefined) {
93
+ throw new Error(`Source-of-authority observation ${observationId} builder needs ${field}`);
94
+ }
95
+ return value;
96
+ }
29
97
  function assertSourceAuthority(sourceAuthority, observationId) {
30
98
  if (!sourceAuthority.authorityClass) {
31
99
  throw new Error(`Source-of-authority observation ${observationId} needs sourceAuthority.authorityClass`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontourai/survey",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Producer-side source, extraction, candidate, and review contracts for projecting verified claims into Surface.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -35,7 +35,7 @@
35
35
  "check:content-boundary": "node scripts/check-content-boundary.cjs"
36
36
  },
37
37
  "dependencies": {
38
- "@kontourai/surface": "git+https://github.com/kontourai/surface.git#9f2a18fb2c7c2430e81879d730b2a9b37c92f017"
38
+ "@kontourai/surface": "^0.5.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^25.6.0",