@instruments/materialgraph 0.24.0 → 0.26.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/association-types.d.ts +20 -20
- package/associations-client.d.ts +4 -4
- package/associations-client.js +3 -10
- package/attribution-types.d.ts +3 -3
- package/brand-most-sampled-types.d.ts +4 -4
- package/brand-types.d.ts +6 -6
- package/brands-client.d.ts +4 -4
- package/brands-client.js +9 -13
- package/browse-types.d.ts +8 -8
- package/by-colour-types.d.ts +18 -18
- package/by-spec-types.d.ts +14 -14
- package/catalog-discovery-types.d.ts +14 -14
- package/catalogue-client.d.ts +4 -4
- package/catalogue-client.js +38 -37
- package/catalogue-types.d.ts +4 -4
- package/citation-types.d.ts +4 -4
- package/client-browse.d.ts +4 -4
- package/client-browse.js +24 -25
- package/client-config.d.ts +2 -2
- package/client-exploration.d.ts +3 -3
- package/client-exploration.js +4 -6
- package/client-source-material-comments.d.ts +4 -4
- package/client-source-material-comments.js +4 -38
- package/client-vocabulary.d.ts +8 -8
- package/client-vocabulary.js +20 -30
- package/client.d.ts +11 -45
- package/client.js +143 -188
- package/codes-client.d.ts +2 -2
- package/codes-client.js +8 -8
- package/codes-types.d.ts +34 -34
- package/colour-aggregate-types.d.ts +24 -24
- package/colours-client.d.ts +2 -2
- package/colours-client.js +15 -15
- package/compare-types.d.ts +10 -10
- package/composition-client.d.ts +3 -3
- package/composition-client.js +8 -7
- package/composition-types.d.ts +12 -12
- package/coordinate-client.d.ts +2 -2
- package/coordinate-client.js +1 -13
- package/corpus-scope-types.d.ts +3 -3
- package/corpus-scope-types.js +1 -25
- package/correction-types.d.ts +10 -10
- package/demand-batch-types.d.ts +18 -18
- package/demand-types.d.ts +24 -24
- package/errors.d.ts +12 -12
- package/errors.js +53 -52
- package/exploration-types.d.ts +29 -22
- package/fan-deck-types.d.ts +6 -6
- package/http-transport.d.ts +13 -21
- package/http-transport.js +31 -28
- package/identify-types.d.ts +10 -10
- package/index.d.ts +0 -6
- package/index.js +0 -2
- package/match-rejection-types.d.ts +6 -6
- package/match-stream-types.d.ts +32 -32
- package/match-stream.d.ts +2 -2
- package/match-stream.js +55 -41
- package/match-types.d.ts +8 -8
- package/material-asset-types.d.ts +26 -26
- package/material-block-types.d.ts +6 -6
- package/material-query-plan-types.d.ts +26 -26
- package/material-resources-client.d.ts +5 -5
- package/material-resources-client.js +10 -20
- package/material-types.d.ts +12 -12
- package/ndjson.js +16 -8
- package/operations.d.ts +6 -6
- package/operations.js +9 -39
- package/package.json +2 -2
- package/palette-completion-types.d.ts +22 -22
- package/palette-search-types.d.ts +28 -28
- package/query-understanding-types.d.ts +43 -36
- package/render-assets-types.d.ts +8 -8
- package/resolve-client.d.ts +2 -2
- package/resolve-client.js +4 -6
- package/resolve-colour-types.d.ts +22 -6
- package/resolve-types.d.ts +10 -10
- package/run-types.d.ts +70 -70
- package/runs.d.ts +13 -26
- package/runs.js +77 -89
- package/samplize-catalogue-types.d.ts +18 -18
- package/samplize-colorvec.d.ts +20 -20
- package/samplize-colorvec.js +66 -42
- package/schema-resource-types.d.ts +38 -38
- package/schema-resource-types.js +5 -5
- package/search-card-types.d.ts +14 -5
- package/search-collapse-types.d.ts +4 -4
- package/search-mood-types.d.ts +2 -2
- package/search-refinement-types.d.ts +8 -8
- package/search-request-types.d.ts +6 -6
- package/search-response-receipt-types.d.ts +135 -34
- package/search-response-types.d.ts +2 -2
- package/search-result-validation.d.ts +3 -3
- package/search-result-validation.js +53 -36
- package/search-window-types.d.ts +2 -2
- package/slot-pool-types.d.ts +20 -20
- package/source-material-validation.d.ts +3 -3
- package/source-material-validation.js +35 -39
- package/spec-facet-types.d.ts +10 -10
- package/spec-types.d.ts +6 -6
- package/specifications.d.ts +9 -25
- package/specifications.js +15 -21
- package/sse.d.ts +2 -2
- package/sse.js +32 -16
- package/substitute-types.d.ts +22 -22
- package/suggest-types.d.ts +7 -7
- package/suggest-types.js +3 -3
- package/taxonomy-coverage-types.d.ts +8 -8
- package/types.d.ts +119 -119
- package/validation.d.ts +26 -26
- package/validation.js +97 -92
- package/webmcp.d.ts +2 -2
- package/webmcp.generated.js +94 -87
- package/project-types.d.ts +0 -79
- package/project-types.js +0 -9
- package/projects.d.ts +0 -13
- package/projects.js +0 -46
- package/run-events.d.ts +0 -106
- package/run-events.js +0 -32
- package/schedule-reference-types.d.ts +0 -46
- package/schedule-reference-types.js +0 -1
- package/schedule-references-client.d.ts +0 -14
- package/schedule-references-client.js +0 -26
- package/schedule-types.d.ts +0 -261
- package/schedule-types.js +0 -1
|
@@ -5,35 +5,61 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { OpenEnum } from "./types.js";
|
|
7
7
|
/** Inspectable metadata for an opaque, principal-bound search refinement receipt. */
|
|
8
|
-
export
|
|
8
|
+
export type SearchRefinementReceipt = {
|
|
9
9
|
token: string;
|
|
10
10
|
expiresAt: string;
|
|
11
11
|
poolSize: number;
|
|
12
12
|
schemaVersion: string;
|
|
13
13
|
projectionVersion: number;
|
|
14
|
-
}
|
|
14
|
+
};
|
|
15
15
|
/** The primary ranking source a query resolved to and reports as its mode. */
|
|
16
|
-
export type SearchMode = OpenEnum<"image" | "colour" | "text" | "lexical" | "entity-browse">;
|
|
16
|
+
export type SearchMode = OpenEnum<"image" | "colour" | "text" | "lexical" | "entity-browse" | "agent">;
|
|
17
17
|
/**
|
|
18
18
|
* Compatibility receipt for non-mode colour handling. Current one-signal
|
|
19
19
|
* ordering reports it skipped at weight 0; colour may still be diagnostic or a
|
|
20
20
|
* hard displayed-image constraint, but does not blend into score.
|
|
21
21
|
*/
|
|
22
|
-
export
|
|
22
|
+
export type SearchRerankReport = {
|
|
23
23
|
colour?: OpenEnum<"ok" | "failed" | "skipped">;
|
|
24
24
|
colourWeight?: number;
|
|
25
25
|
colourLabel?: string;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* A part of the search that can fail without stopping it.
|
|
29
|
+
*
|
|
30
|
+
* Coarse on purpose: a caller needs to know that something did not answer, not
|
|
31
|
+
* which provider it was. OPEN, and it will grow — read it with a default
|
|
32
|
+
* branch.
|
|
33
|
+
*/
|
|
34
|
+
export type SearchDegradedPart = OpenEnum<"filter-coverage" | "term-coverage">;
|
|
35
|
+
/**
|
|
36
|
+
* Which parts of the search did not answer, on EVERY response (MG-1913).
|
|
37
|
+
*
|
|
38
|
+
* `parts: []` says no part reported a failure. It does NOT promise every check
|
|
39
|
+
* ran: a check the request never needed is skipped rather than failed. ABSENT
|
|
40
|
+
* means the response came from a server that does not report this, never that
|
|
41
|
+
* nothing was degraded.
|
|
42
|
+
*/
|
|
43
|
+
export type SearchDegraded = {
|
|
44
|
+
parts: SearchDegradedPart[];
|
|
45
|
+
};
|
|
46
|
+
/** Stage counts retained when a search returns no results. */
|
|
47
|
+
export type SearchEmptyOutcomeCounts = {
|
|
29
48
|
retrieved: number;
|
|
30
49
|
afterPrune: number;
|
|
31
50
|
final: number;
|
|
32
|
-
}
|
|
51
|
+
};
|
|
33
52
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
53
|
+
* Why a search returned no results, on EVERY empty response (MG-1911).
|
|
54
|
+
*
|
|
55
|
+
* `proven-corpus-empty` is exhaustive and is the only member that supports
|
|
56
|
+
* telling someone the catalogue holds nothing. `unproven-empty` is an honest
|
|
57
|
+
* end to a search that ran without establishing that. `search-degraded` means
|
|
58
|
+
* part of the search did not answer, so the empty page describes the runtime
|
|
59
|
+
* rather than the catalogue, and the right response is to retry.
|
|
60
|
+
*
|
|
61
|
+
* Read it by `kind` with a default branch: this union has grown once and the
|
|
62
|
+
* reason and basis enums are open.
|
|
37
63
|
*/
|
|
38
64
|
export type SearchEmptyOutcome = {
|
|
39
65
|
kind: "proven-corpus-empty";
|
|
@@ -46,18 +72,93 @@ export type SearchEmptyOutcome = {
|
|
|
46
72
|
reason: OpenEnum<"allowlist-truncated" | "retrieval-window-not-exhaustive" | "source-empty" | "post-retrieval-rejected" | "pagination-empty" | "no-authoritative-empty-proof">;
|
|
47
73
|
sourceEmpty?: boolean | null;
|
|
48
74
|
counts?: SearchEmptyOutcomeCounts;
|
|
75
|
+
} | {
|
|
76
|
+
kind: "search-degraded";
|
|
77
|
+
/** Which parts did not answer. Coarse: never a provider's name. */
|
|
78
|
+
parts: SearchDegradedPart[];
|
|
79
|
+
sourceEmpty?: boolean | null;
|
|
80
|
+
counts?: SearchEmptyOutcomeCounts;
|
|
49
81
|
};
|
|
50
82
|
/** Explain-only coverage of substantive query terms in the lexical projection. */
|
|
51
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Which of the query's substantive words the catalogue holds at all
|
|
85
|
+
* (MG-1858), on every text-family response. `terms` names the words found in
|
|
86
|
+
* no document; `checkedTerms` is how many were asked about; `noneMatched` is
|
|
87
|
+
* true when no checked word is attested anywhere. `unavailable` means the read
|
|
88
|
+
* failed and never means everything matched; `skipped` means this mode never
|
|
89
|
+
* claimed to match words.
|
|
90
|
+
*/
|
|
91
|
+
export type SearchTermCoverageReceipt = {
|
|
52
92
|
status: OpenEnum<"covered" | "uncovered" | "unavailable" | "skipped">;
|
|
53
93
|
terms: string[];
|
|
94
|
+
checkedTerms: number;
|
|
95
|
+
noneMatched: boolean;
|
|
54
96
|
note?: string;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
export
|
|
97
|
+
};
|
|
98
|
+
/** The Search workflow run a ledger receipt belongs to. */
|
|
99
|
+
export type SearchRunRef = {
|
|
100
|
+
contextId: string;
|
|
101
|
+
runId: string;
|
|
102
|
+
schemaVersion: 1;
|
|
103
|
+
};
|
|
104
|
+
/** One artifact a Search workflow step read or wrote. */
|
|
105
|
+
export type SearchRunArtifactRef = {
|
|
106
|
+
artifactId: string;
|
|
107
|
+
kind: string;
|
|
108
|
+
producedBy: string;
|
|
109
|
+
runRef: SearchRunRef;
|
|
110
|
+
schemaVersion: 1;
|
|
111
|
+
};
|
|
112
|
+
/** What one Search workflow step did: its reads, its write and its time. */
|
|
113
|
+
export type SearchStageReceipt = {
|
|
114
|
+
stageId: string;
|
|
115
|
+
status: "succeeded";
|
|
116
|
+
/** The step's own work, excluding reading and writing its artifacts. */
|
|
117
|
+
durationMs: number;
|
|
118
|
+
inputArtifacts: SearchRunArtifactRef[];
|
|
119
|
+
outputArtifact: SearchRunArtifactRef;
|
|
120
|
+
inputCount: number | null;
|
|
121
|
+
outputCount: number | null;
|
|
122
|
+
runRef: SearchRunRef;
|
|
123
|
+
/** The outcome the step chose, when it chooses one. */
|
|
124
|
+
outcome?: string;
|
|
125
|
+
/** The arm a fork took and why. */
|
|
126
|
+
branch?: {
|
|
127
|
+
decision: string;
|
|
128
|
+
reason: string;
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
/** One ledger line: a step's receipt and its span since the run opened. */
|
|
132
|
+
export type SearchRunLedgerEntry = {
|
|
133
|
+
receipt: SearchStageReceipt;
|
|
134
|
+
/** The nested workflows the step ran under, outermost first. */
|
|
135
|
+
workflowPath: string[];
|
|
136
|
+
startedAtMs: number;
|
|
137
|
+
endedAtMs: number;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Outcome receipts shared by full and card search responses. `degraded`,
|
|
141
|
+
* `emptyOutcome` and `termCoverage` are on every response; `diagnostics` and
|
|
142
|
+
* `explain` are explain-only.
|
|
143
|
+
*/
|
|
144
|
+
export type SearchResponseExplainReceipts = {
|
|
145
|
+
degraded?: SearchDegraded;
|
|
58
146
|
emptyOutcome?: SearchEmptyOutcome;
|
|
59
147
|
termCoverage?: SearchTermCoverageReceipt;
|
|
60
|
-
|
|
148
|
+
/**
|
|
149
|
+
* The engine's notes written for an engineer (tier timings, cache states,
|
|
150
|
+
* index names), under `explain` only. `note` carries the reader's sentences
|
|
151
|
+
* alone (MG-1919).
|
|
152
|
+
*/
|
|
153
|
+
diagnostics?: string[];
|
|
154
|
+
/**
|
|
155
|
+
* Present under `explain` when the Search workflow answered the request:
|
|
156
|
+
* every step receipt, in completion order. Absent when the engine answered.
|
|
157
|
+
*/
|
|
158
|
+
explain?: {
|
|
159
|
+
ledger: readonly SearchRunLedgerEntry[];
|
|
160
|
+
};
|
|
161
|
+
};
|
|
61
162
|
/** One stage in the explain-only ledger of transformations that actually ran. */
|
|
62
163
|
export type SearchQueryTransformStage = {
|
|
63
164
|
stage: OpenEnum<"normalise" | "resolve-spec" | "resolve-paint" | "resolve-brand">;
|
|
@@ -68,7 +169,7 @@ export type SearchQueryTransformStage = {
|
|
|
68
169
|
reason: string;
|
|
69
170
|
};
|
|
70
171
|
/** Explain-only category gate selected by query understanding. */
|
|
71
|
-
export
|
|
172
|
+
export type SearchCategoryAnchor = {
|
|
72
173
|
/**
|
|
73
174
|
* A leaf type id; the group key when `source` is `"group"`; or the canonical
|
|
74
175
|
* category noun when `source` is `"head-noun"`. Gate on `productTypeIds`.
|
|
@@ -86,9 +187,9 @@ export interface SearchCategoryAnchor {
|
|
|
86
187
|
/** Hard category eligibility is applied inside lexical candidate selection. */
|
|
87
188
|
candidateSource?: OpenEnum<"lexical">;
|
|
88
189
|
applied: boolean;
|
|
89
|
-
}
|
|
190
|
+
};
|
|
90
191
|
/** Explain-only brand gate selected by query understanding. */
|
|
91
|
-
export
|
|
192
|
+
export type SearchBrandAnchor = {
|
|
92
193
|
brandSlug: string;
|
|
93
194
|
brandName: string;
|
|
94
195
|
confidence: number;
|
|
@@ -96,18 +197,18 @@ export interface SearchBrandAnchor {
|
|
|
96
197
|
tier: OpenEnum<"exact_id" | "exact_alias" | "lexical" | "semantic">;
|
|
97
198
|
variantCount: number;
|
|
98
199
|
applied: boolean;
|
|
99
|
-
}
|
|
200
|
+
};
|
|
100
201
|
/** A real brand candidate the engine deliberately declined to gate on. */
|
|
101
|
-
export
|
|
202
|
+
export type SearchBrandSkip = {
|
|
102
203
|
reason: OpenEnum<"ambiguous" | "weak-tier" | "too-broad">;
|
|
103
204
|
candidates?: string[];
|
|
104
|
-
}
|
|
205
|
+
};
|
|
105
206
|
/**
|
|
106
207
|
* EXPLAIN-only receipt of the query shape that executed. This is distinct from
|
|
107
208
|
* the separate Search Plan compiler operation: it reports execution and never
|
|
108
209
|
* causes it.
|
|
109
210
|
*/
|
|
110
|
-
export
|
|
211
|
+
export type SearchExecutionPlan = {
|
|
111
212
|
grain: OpenEnum<"variant" | "product">;
|
|
112
213
|
/** Which 2048D Voyage projection served a text-mode request. */
|
|
113
214
|
textLane?: OpenEnum<"image-text" | "variant-text">;
|
|
@@ -121,30 +222,30 @@ export interface SearchExecutionPlan {
|
|
|
121
222
|
};
|
|
122
223
|
queryTransform: SearchQueryTransformStage[];
|
|
123
224
|
/** Ordered, explain-only request-understanding execution trace. */
|
|
124
|
-
steps?:
|
|
225
|
+
steps?: {
|
|
125
226
|
key: string;
|
|
126
227
|
status: OpenEnum<"executed" | "skipped">;
|
|
127
228
|
reason: string;
|
|
128
229
|
durationMs: number;
|
|
129
|
-
}
|
|
230
|
+
}[];
|
|
130
231
|
categoryAnchor?: SearchCategoryAnchor;
|
|
131
232
|
brandAnchor?: SearchBrandAnchor;
|
|
132
233
|
brandSkipped?: SearchBrandSkip;
|
|
133
|
-
}
|
|
234
|
+
};
|
|
134
235
|
/** Why a compound colour constraint returned a full or short page. */
|
|
135
|
-
export
|
|
236
|
+
export type CompoundColourAbundanceReceipt = {
|
|
136
237
|
grain: OpenEnum<"variant" | "product">;
|
|
137
238
|
requested: number;
|
|
138
239
|
eligible: number;
|
|
139
240
|
candidateWindow: number;
|
|
140
241
|
sourceExhausted: boolean;
|
|
141
242
|
state: OpenEnum<"filled" | "corpus_scarcity" | "evidence_unavailable" | "retrieval_window_exhausted">;
|
|
142
|
-
}
|
|
243
|
+
};
|
|
143
244
|
/**
|
|
144
245
|
* Eligibility proof for an explicit or taxonomy-backed colour inside a compound
|
|
145
246
|
* text query. Counts describe the bounded candidate pool, not the whole corpus.
|
|
146
247
|
*/
|
|
147
|
-
export
|
|
248
|
+
export type CompoundColourConstraintReceipt = {
|
|
148
249
|
basis: OpenEnum<"explicit" | "detected-strong">;
|
|
149
250
|
family: string;
|
|
150
251
|
queryHexes: string[];
|
|
@@ -154,21 +255,21 @@ export interface CompoundColourConstraintReceipt {
|
|
|
154
255
|
unknown: number;
|
|
155
256
|
adjacent: number;
|
|
156
257
|
abundance?: CompoundColourAbundanceReceipt;
|
|
157
|
-
}
|
|
258
|
+
};
|
|
158
259
|
/** Why a hard form constraint returned a full or short page. */
|
|
159
|
-
export
|
|
260
|
+
export type CompoundFormAbundanceReceipt = {
|
|
160
261
|
grain: OpenEnum<"variant" | "product">;
|
|
161
262
|
requested: number;
|
|
162
263
|
eligible: number;
|
|
163
264
|
candidateWindow: number;
|
|
164
265
|
sourceExhausted: boolean;
|
|
165
266
|
state: OpenEnum<"filled" | "corpus_scarcity" | "evidence_unavailable" | "retrieval_window_exhausted">;
|
|
166
|
-
}
|
|
267
|
+
};
|
|
167
268
|
/**
|
|
168
269
|
* Hard form eligibility for a compound text query. Product and variant names
|
|
169
270
|
* may retrieve a candidate but never prove that it satisfies the form.
|
|
170
271
|
*/
|
|
171
|
-
export
|
|
272
|
+
export type CompoundFormConstraintReceipt = {
|
|
172
273
|
instruction: OpenEnum<"subway" | "plank" | "square" | "hexagon" | "penny-round">;
|
|
173
274
|
considered: number;
|
|
174
275
|
kept: number;
|
|
@@ -176,4 +277,4 @@ export interface CompoundFormConstraintReceipt {
|
|
|
176
277
|
contradicted: number;
|
|
177
278
|
unknown: number;
|
|
178
279
|
abundance: CompoundFormAbundanceReceipt;
|
|
179
|
-
}
|
|
280
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SearchData } from "./types.js";
|
|
2
2
|
/** Canonical Search wire response. Raw SDK methods preserve this envelope. */
|
|
3
|
-
export
|
|
3
|
+
export type SearchResponse = {
|
|
4
4
|
data: SearchData;
|
|
5
5
|
meta: {
|
|
6
6
|
operationId: "search_materials_post" | "search_materials_get";
|
|
@@ -8,4 +8,4 @@ export interface SearchResponse {
|
|
|
8
8
|
};
|
|
9
9
|
links: Record<string, never>;
|
|
10
10
|
warnings: never[];
|
|
11
|
-
}
|
|
11
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ValidationFailure } from "./validation.js";
|
|
2
2
|
/** `verdictStateSchema` — the six live cell states. */
|
|
3
3
|
export declare const VERDICT_STATES: readonly ["matched", "deviated", "failed", "unverified", "missing", "not_evaluated"];
|
|
4
4
|
/** `attributeVerdictSchema.strength`. */
|
|
@@ -22,6 +22,6 @@ export declare const VISUAL_MEANING_BASES: readonly ["canonical_attribute", "ima
|
|
|
22
22
|
* contract (nothing on the emit path parses, so stripping would invent a
|
|
23
23
|
* normalisation the wire never had).
|
|
24
24
|
*/
|
|
25
|
-
export declare
|
|
25
|
+
export declare const checkSearchResultItem: (value: unknown, what: string, fail: ValidationFailure) => void;
|
|
26
26
|
/** Prove every entry of a `results[]` array is a {@link SearchResultItem}. */
|
|
27
|
-
export declare
|
|
27
|
+
export declare const checkSearchResultItems: (items: readonly unknown[], what: string, fail: ValidationFailure) => void;
|
|
@@ -41,20 +41,21 @@ export const VISUAL_MEANING_BASES = [
|
|
|
41
41
|
];
|
|
42
42
|
// ── Leaf checks ──────────────────────────────────────────────────────────────
|
|
43
43
|
/** `palette[]` — `{ hex, proportion, name: string.nullable().optional() }`. */
|
|
44
|
-
|
|
44
|
+
const checkPaletteSwatch = (value, what, fail) => {
|
|
45
45
|
const record = requireRecord(value, what, fail);
|
|
46
46
|
requireString(record.hex, `${what}.hex`, fail);
|
|
47
47
|
requireNumber(record.proportion, `${what}.proportion`, fail);
|
|
48
48
|
// `.nullable().optional()` — absent OR null OR a string.
|
|
49
|
-
if (record.name !== undefined)
|
|
49
|
+
if (record.name !== undefined) {
|
|
50
50
|
requireNullableString(record.name, `${what}.name`, fail);
|
|
51
|
-
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
52
53
|
/**
|
|
53
54
|
* `variants[]` — one entry of a product-collapsed result's ranked variant list
|
|
54
55
|
* (`collapsedVariantSchema`). A SLIM projection, not a nested result item: the
|
|
55
56
|
* checks here are the whole shape.
|
|
56
57
|
*/
|
|
57
|
-
|
|
58
|
+
const checkCollapsedVariant = (value, what, fail) => {
|
|
58
59
|
const record = requireRecord(value, what, fail);
|
|
59
60
|
requireString(record.variantId, `${what}.variantId`, fail);
|
|
60
61
|
requireNullableString(record.variantName, `${what}.variantName`, fail);
|
|
@@ -65,16 +66,16 @@ function checkCollapsedVariant(value, what, fail) {
|
|
|
65
66
|
requireNullableString(record.imageUrl, `${what}.imageUrl`, fail);
|
|
66
67
|
requireOptionalString(record.materialBankId, `${what}.materialBankId`, fail);
|
|
67
68
|
requireNumber(record.score, `${what}.score`, fail);
|
|
68
|
-
}
|
|
69
|
+
};
|
|
69
70
|
/** `colourMeta` — three independently optional strings. */
|
|
70
|
-
|
|
71
|
+
const checkColourMeta = (value, what, fail) => {
|
|
71
72
|
const record = requireRecord(value, what, fail);
|
|
72
73
|
requireOptionalString(record.mood, `${what}.mood`, fail);
|
|
73
74
|
requireOptionalString(record.dominantFamily, `${what}.dominantFamily`, fail);
|
|
74
75
|
requireOptionalString(record.dominantHex, `${what}.dominantHex`, fail);
|
|
75
|
-
}
|
|
76
|
+
};
|
|
76
77
|
/** `searchResultSignalsSchema` — five required scores plus additive portrait. */
|
|
77
|
-
|
|
78
|
+
const checkSignals = (value, what, fail) => {
|
|
78
79
|
const record = requireRecord(value, what, fail);
|
|
79
80
|
if (record.portrait !== undefined) {
|
|
80
81
|
requireNullableNumber(record.portrait, `${what}.portrait`, fail);
|
|
@@ -82,9 +83,9 @@ function checkSignals(value, what, fail) {
|
|
|
82
83
|
for (const signal of ["image", "category", "colour", "lexical", "text"]) {
|
|
83
84
|
requireNullableNumber(record[signal], `${what}.${signal}`, fail);
|
|
84
85
|
}
|
|
85
|
-
}
|
|
86
|
+
};
|
|
86
87
|
/** `visualMeaningSchema` — note the NON-EMPTY `values` array and the closed `basis`. */
|
|
87
|
-
|
|
88
|
+
const checkVisualMeaning = (value, what, fail) => {
|
|
88
89
|
const record = requireRecord(value, what, fail);
|
|
89
90
|
requireString(record.id, `${what}.id`, fail);
|
|
90
91
|
requireString(record.label, `${what}.label`, fail);
|
|
@@ -94,39 +95,43 @@ function checkVisualMeaning(value, what, fail) {
|
|
|
94
95
|
requireOptionalString(record.sourceBasis, `${what}.sourceBasis`, fail);
|
|
95
96
|
requireOptionalString(record.version, `${what}.version`, fail);
|
|
96
97
|
requireOptionalString(record.appliedAt, `${what}.appliedAt`, fail);
|
|
97
|
-
}
|
|
98
|
+
};
|
|
98
99
|
// ── Verdict subtree ──────────────────────────────────────────────────────────
|
|
99
100
|
/**
|
|
100
101
|
* `verdictBaselineSchema` — a discriminated union on `kind`. An unknown
|
|
101
102
|
* discriminant is rejected, exactly as `z.discriminatedUnion` rejects it, and
|
|
102
103
|
* each arm carries only the fields it needs.
|
|
103
104
|
*/
|
|
104
|
-
|
|
105
|
+
const checkVerdictBaseline = (value, what, fail) => {
|
|
105
106
|
const record = requireRecord(value, what, fail);
|
|
106
107
|
const kind = requireEnum(record.kind, VERDICT_BASELINE_KINDS, `${what}.kind`, fail);
|
|
107
108
|
switch (kind) {
|
|
108
|
-
case "term":
|
|
109
|
+
case "term": {
|
|
109
110
|
requireNonEmptyString(record.term, `${what}.term`, fail);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case "presence": {
|
|
110
114
|
return;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
case "seed":
|
|
115
|
+
}
|
|
116
|
+
case "seed": {
|
|
114
117
|
requireNonEmptyString(record.variantId, `${what}.variantId`, fail);
|
|
115
118
|
return;
|
|
116
|
-
|
|
119
|
+
}
|
|
120
|
+
default: {
|
|
117
121
|
// `image` — the like-this-picture arm.
|
|
118
122
|
requireEnum(record.source, VERDICT_IMAGE_SOURCES, `${what}.source`, fail);
|
|
119
123
|
requireNullableNonEmptyString(record.variantId, `${what}.variantId`, fail);
|
|
124
|
+
}
|
|
120
125
|
}
|
|
121
|
-
}
|
|
126
|
+
};
|
|
122
127
|
/** `verdictDeviationSchema` — a named near-miss. */
|
|
123
|
-
|
|
128
|
+
const checkVerdictDeviation = (value, what, fail) => {
|
|
124
129
|
const record = requireRecord(value, what, fail);
|
|
125
130
|
requireEnum(record.direction, VERDICT_DEVIATION_DIRECTIONS, `${what}.direction`, fail);
|
|
126
131
|
requireNullableNumber(record.delta, `${what}.delta`, fail);
|
|
127
132
|
requireNullableString(record.unit, `${what}.unit`, fail);
|
|
128
133
|
requireNonEmptyString(record.label, `${what}.label`, fail);
|
|
129
|
-
}
|
|
134
|
+
};
|
|
130
135
|
/**
|
|
131
136
|
* `attributeVerdictSchema` — nine fields plus the TWO cross-field invariants its
|
|
132
137
|
* `.superRefine()` enforces. Those are relational rather than field-wise, which
|
|
@@ -134,7 +139,7 @@ function checkVerdictDeviation(value, what, fail) {
|
|
|
134
139
|
* schema's own doc calls them out as the reason a malformed cell can never reach
|
|
135
140
|
* a consumer.
|
|
136
141
|
*/
|
|
137
|
-
|
|
142
|
+
const checkAttributeVerdict = (value, what, fail) => {
|
|
138
143
|
const record = requireRecord(value, what, fail);
|
|
139
144
|
requireNonEmptyString(record.attributeId, `${what}.attributeId`, fail);
|
|
140
145
|
const state = requireEnum(record.state, VERDICT_STATES, `${what}.state`, fail);
|
|
@@ -152,9 +157,10 @@ function checkAttributeVerdict(value, what, fail) {
|
|
|
152
157
|
throw fail(`${what}.citation.count must be a positive integer`);
|
|
153
158
|
}
|
|
154
159
|
}
|
|
155
|
-
const deviation = record
|
|
156
|
-
if (deviation !== null)
|
|
160
|
+
const { deviation } = record;
|
|
161
|
+
if (deviation !== null) {
|
|
157
162
|
checkVerdictDeviation(deviation, `${what}.deviation`, fail);
|
|
163
|
+
}
|
|
158
164
|
const trustGap = requireNullableEnum(record.trustGap, VERDICT_TRUST_GAPS, `${what}.trustGap`, fail);
|
|
159
165
|
// superRefine invariant 1 — a deviation only describes a `deviated` cell.
|
|
160
166
|
if (deviation !== null && state !== "deviated") {
|
|
@@ -164,15 +170,17 @@ function checkAttributeVerdict(value, what, fail) {
|
|
|
164
170
|
if (trustGap !== null && state !== "unverified") {
|
|
165
171
|
throw fail(`${what}.trustGap is set on a cell whose state is "${state}", not "unverified"`);
|
|
166
172
|
}
|
|
167
|
-
}
|
|
173
|
+
};
|
|
168
174
|
/** `candidateVerdictSchema` — the whole report card. */
|
|
169
|
-
|
|
175
|
+
const checkCandidateVerdict = (value, what, fail) => {
|
|
170
176
|
const record = requireRecord(value, what, fail);
|
|
171
177
|
const cells = requireArray(record.cells, `${what}.cells`, fail);
|
|
172
|
-
cells.forEach((cell, index) =>
|
|
178
|
+
cells.forEach((cell, index) => {
|
|
179
|
+
checkAttributeVerdict(cell, `${what}.cells[${index}]`, fail);
|
|
180
|
+
});
|
|
173
181
|
requireEnum(record.grade, VERDICT_GRADES, `${what}.grade`, fail);
|
|
174
182
|
requireNullableBoundedNumber(record.minConfidence, `${what}.minConfidence`, fail, 0, 1);
|
|
175
|
-
}
|
|
183
|
+
};
|
|
176
184
|
// ── The item ─────────────────────────────────────────────────────────────────
|
|
177
185
|
/**
|
|
178
186
|
* Prove one wire value is a {@link SearchResultItem}, raising through `fail` at
|
|
@@ -181,7 +189,7 @@ function checkCandidateVerdict(value, what, fail) {
|
|
|
181
189
|
* contract (nothing on the emit path parses, so stripping would invent a
|
|
182
190
|
* normalisation the wire never had).
|
|
183
191
|
*/
|
|
184
|
-
export
|
|
192
|
+
export const checkSearchResultItem = (value, what, fail) => {
|
|
185
193
|
const record = requireRecord(value, what, fail);
|
|
186
194
|
requireString(record.variantId, `${what}.variantId`, fail);
|
|
187
195
|
requireString(record.brand, `${what}.brand`, fail);
|
|
@@ -209,12 +217,15 @@ export function checkSearchResultItem(value, what, fail) {
|
|
|
209
217
|
requireBoolean(record.hasImage, `${what}.hasImage`, fail);
|
|
210
218
|
requireNumber(record.score, `${what}.score`, fail);
|
|
211
219
|
const palette = requireArray(record.palette, `${what}.palette`, fail);
|
|
212
|
-
palette.forEach((swatch, index) =>
|
|
220
|
+
palette.forEach((swatch, index) => {
|
|
221
|
+
checkPaletteSwatch(swatch, `${what}.palette[${index}]`, fail);
|
|
222
|
+
});
|
|
213
223
|
if (record.colourMeta !== undefined) {
|
|
214
224
|
checkColourMeta(record.colourMeta, `${what}.colourMeta`, fail);
|
|
215
225
|
}
|
|
216
|
-
if (record.signals !== undefined)
|
|
226
|
+
if (record.signals !== undefined) {
|
|
217
227
|
checkSignals(record.signals, `${what}.signals`, fail);
|
|
228
|
+
}
|
|
218
229
|
requireOptionalBoolean(record.retired, `${what}.retired`, fail);
|
|
219
230
|
requireOptionalBoolean(record.sampleable, `${what}.sampleable`, fail);
|
|
220
231
|
requireOptionalBoolean(record.belowFloor, `${what}.belowFloor`, fail);
|
|
@@ -224,17 +235,23 @@ export function checkSearchResultItem(value, what, fail) {
|
|
|
224
235
|
}
|
|
225
236
|
if (record.variants !== undefined) {
|
|
226
237
|
const variants = requireArray(record.variants, `${what}.variants`, fail);
|
|
227
|
-
variants.forEach((variant, index) =>
|
|
238
|
+
variants.forEach((variant, index) => {
|
|
239
|
+
checkCollapsedVariant(variant, `${what}.variants[${index}]`, fail);
|
|
240
|
+
});
|
|
228
241
|
}
|
|
229
242
|
if (record.visualMeanings !== undefined) {
|
|
230
243
|
const meanings = requireArray(record.visualMeanings, `${what}.visualMeanings`, fail);
|
|
231
|
-
meanings.forEach((meaning, index) =>
|
|
244
|
+
meanings.forEach((meaning, index) => {
|
|
245
|
+
checkVisualMeaning(meaning, `${what}.visualMeanings[${index}]`, fail);
|
|
246
|
+
});
|
|
232
247
|
}
|
|
233
248
|
if (record.verdict !== undefined) {
|
|
234
249
|
checkCandidateVerdict(record.verdict, `${what}.verdict`, fail);
|
|
235
250
|
}
|
|
236
|
-
}
|
|
251
|
+
};
|
|
237
252
|
/** Prove every entry of a `results[]` array is a {@link SearchResultItem}. */
|
|
238
|
-
export
|
|
239
|
-
items.forEach((item, index) =>
|
|
240
|
-
}
|
|
253
|
+
export const checkSearchResultItems = (items, what, fail) => {
|
|
254
|
+
items.forEach((item, index) => {
|
|
255
|
+
checkSearchResultItem(item, `${what}[${index}]`, fail);
|
|
256
|
+
});
|
|
257
|
+
};
|
package/search-window-types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** The bounded candidate window that produced a search page. */
|
|
2
|
-
export
|
|
2
|
+
export type SearchWindowReceipt = {
|
|
3
3
|
/** Versioned budget profile; interpret the remaining fields under this version. */
|
|
4
4
|
profile: "interactive-r1" | (string & {});
|
|
5
5
|
/** Candidate depth used by the final retrieval. */
|
|
@@ -22,4 +22,4 @@ export interface SearchWindowReceipt {
|
|
|
22
22
|
/** Canonical candidates returned by the selected retrieval arm. */
|
|
23
23
|
hydratedCanonicalCandidates: number;
|
|
24
24
|
};
|
|
25
|
-
}
|
|
25
|
+
};
|