@instruments/materialgraph 0.17.0 → 0.19.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.
Files changed (63) hide show
  1. package/association-types.d.ts +90 -4
  2. package/associations-client.d.ts +3 -1
  3. package/associations-client.js +4 -0
  4. package/browse-types.d.ts +14 -3
  5. package/by-colour-types.d.ts +24 -6
  6. package/by-spec-types.d.ts +4 -0
  7. package/catalogue-client.d.ts +14 -2
  8. package/catalogue-client.js +23 -0
  9. package/catalogue-types.d.ts +278 -4
  10. package/citation-types.d.ts +34 -0
  11. package/citation-types.js +1 -0
  12. package/client-browse.d.ts +1 -0
  13. package/client-browse.js +1 -0
  14. package/client-vocabulary.d.ts +10 -0
  15. package/client-vocabulary.js +32 -0
  16. package/client.d.ts +28 -62
  17. package/client.js +51 -75
  18. package/composition-types.d.ts +6 -0
  19. package/corpus-scope-types.d.ts +6 -4
  20. package/errors.d.ts +1 -1
  21. package/errors.js +2 -0
  22. package/index.d.ts +6 -0
  23. package/json-value-types.d.ts +8 -0
  24. package/json-value-types.js +1 -0
  25. package/match-types.d.ts +3 -0
  26. package/material-asset-types.d.ts +71 -0
  27. package/material-resources-client.d.ts +18 -0
  28. package/material-resources-client.js +29 -0
  29. package/material-types.d.ts +59 -0
  30. package/operations.d.ts +1 -1
  31. package/operations.js +62 -0
  32. package/package.json +1 -1
  33. package/palette-search-types.d.ts +16 -2
  34. package/query-understanding-types.d.ts +5 -2
  35. package/render-assets-types.d.ts +65 -0
  36. package/render-assets-types.js +1 -0
  37. package/run-events.d.ts +13 -0
  38. package/samplize-catalogue-types.d.ts +92 -0
  39. package/samplize-catalogue-types.js +1 -0
  40. package/schedule-reference-types.d.ts +46 -0
  41. package/schedule-reference-types.js +1 -0
  42. package/schedule-references-client.d.ts +14 -0
  43. package/schedule-references-client.js +26 -0
  44. package/schedule-types.d.ts +34 -0
  45. package/search-collapse-types.d.ts +1 -1
  46. package/search-mood-types.d.ts +6 -0
  47. package/search-mood-types.js +1 -0
  48. package/search-refinement-types.d.ts +5 -0
  49. package/search-request-types.d.ts +29 -11
  50. package/search-response-receipt-types.d.ts +59 -3
  51. package/search-result-validation.js +14 -1
  52. package/search-window-types.d.ts +13 -5
  53. package/slot-pool-types.d.ts +2 -0
  54. package/spec-types.d.ts +6 -1
  55. package/specifications.d.ts +3 -1
  56. package/specifications.js +4 -0
  57. package/substitute-types.d.ts +75 -0
  58. package/substitute-types.js +1 -0
  59. package/suggest-types.d.ts +6 -0
  60. package/suggest-types.js +1 -1
  61. package/taxonomy-coverage-types.d.ts +34 -0
  62. package/taxonomy-coverage-types.js +1 -0
  63. package/types.d.ts +20 -21
@@ -1,3 +1,4 @@
1
+ /** samplizeCatalogue admits published US Samplize paint colours, regardless of stock. */
1
2
  /**
2
3
  * @module search-request-types
3
4
  * The two request shapes for the `/search` surface — the POST JSON body and the
@@ -32,8 +33,8 @@ export interface SearchInput {
32
33
  };
33
34
  mood?: string;
34
35
  /**
35
- * Re-order the final scored results. `relevance` (default) keeps the fused
36
- * score; `light` / `dark` / `vivid` / `muted` / `colourful` are the colour
36
+ * Re-order the final scored results. `relevance` (default) keeps the selected
37
+ * mode's primary score; `light` / `dark` / `vivid` / `muted` / `colourful` are the colour
37
38
  * ramps; `name` (A→Z), `name_desc` (Z→A) and `recent` (newest first) are the
38
39
  * catalogue orders — the same three `/search/browse` walks the corpus in, so
39
40
  * one word means one order on both lanes.
@@ -100,12 +101,18 @@ export interface SearchInput {
100
101
  boost?: string;
101
102
  filter?: string[];
102
103
  };
104
+ /**
105
+ * Optional multipliers for the selected mode's one ordering signal. At most
106
+ * one is applied: image for image/image-text, lexical for lexical/browse, and
107
+ * colour for colour mode. Non-mode keys are accepted for compatibility but
108
+ * cannot activate secondary scoring.
109
+ */
103
110
  weights?: {
104
111
  image?: number;
105
112
  category?: number;
106
113
  colour?: number;
107
114
  lexical?: number;
108
- /** Text rerank multiplier applied when a seeded search also carries `text` (default 0.4). */
115
+ /** Compatibility field; seeded text does not activate secondary scoring. */
109
116
  text?: number;
110
117
  };
111
118
  filters?: SearchFilter[];
@@ -120,6 +127,7 @@ export interface SearchInput {
120
127
  /** The previous response's `cursor`, passed back verbatim. Never synthesise one. */
121
128
  cursor?: Cursor;
122
129
  explain?: boolean;
130
+ /** Public POST defaults to distinct products; send `"none"` for individual variants. */
123
131
  collapse?: OpenEnum<"none" | "product">;
124
132
  /**
125
133
  * Opt-in feed total: EXACT up to 1,000, `lowerBound` beyond / for ANN pools.
@@ -141,6 +149,8 @@ export interface SearchInput {
141
149
  refinementToken?: string;
142
150
  /** Only return materials with at least one catalog image. Default false (full catalog). */
143
151
  hasImages?: boolean;
152
+ /** Require a recorded accepted sampleable=true fact; unknown and false are excluded. */
153
+ sampleableOnly?: boolean;
144
154
  /**
145
155
  * Opt-in seed-relative verdict cells (MG-629). Only meaningful with
146
156
  * `similarTo: { variantId }`: each hit's `verdict` gains `preferred` cells
@@ -156,7 +166,7 @@ export interface SearchInput {
156
166
  * `"search"` (default) is the full engine. `"typeahead"` is the as-you-type
157
167
  * profile: lexical-only with prefix match on the final token, forced
158
168
  * `view: "card"`, `limit` capped at 24, and no mood/colour detection tiers,
159
- * semantic fallback, category boost, colour rerank, refinement suggestions,
169
+ * semantic fallback, secondary scoring, refinement suggestions,
160
170
  * counts, or meanings. `textModes` is ignored under typeahead.
161
171
  */
162
172
  intent?: OpenEnum<"search" | "typeahead">;
@@ -166,22 +176,26 @@ export interface SearchInput {
166
176
  * **ABSENT means the WHOLE GRAPH** — every material MaterialGraph knows,
167
177
  * orderable or not. Absence is never a narrower default, so a caller that
168
178
  * says nothing gets materials it may not be able to buy.
169
- * Three scopes gate on CHANNEL membership, which is what "can someone buy
170
- * this" means: `"materialBankNaOrderable"` (Material Bank North America,
179
+ * Three transaction-oriented scopes gate on governed CHANNEL membership:
180
+ * `"materialBankNaOrderable"` (Material Bank North America,
171
181
  * ~277,000 materials), `"materialBankEuOrderable"` (Material Bank Europe,
172
182
  * ~65,000) and `"designShopOrderable"` (DesignShop, ~34,000, with the
173
183
  * products DesignShop hides from browse excluded).
184
+ * `"materialBankNaAndCatalogue"` is a governed discovery corpus: the single
185
+ * producer-side union of Material Bank North America and Catalogue editorial
186
+ * membership. It is not a buyability claim, and a catalogue reference alone
187
+ * does not establish membership.
174
188
  *
175
189
  * `"materialBankOrderable"` is NOT one of them, despite the name. It selects
176
190
  * materials carrying a Material Bank identity — a PROVENANCE signal, not a
177
191
  * storefront — and admits about 98% of the graph. Use it to exclude the
178
192
  * crawl-sourced brands that were never in the Material Bank feed; if you mean
179
- * orderable, use one of the three above.
193
+ * orderable, use one of the channel-backed scopes above.
180
194
  *
181
- * A scope answers what is BUYABLE. It never answers what is SUITABLE: scope
182
- * on channel, then refine on sector. A trade-only material can be right for a
183
- * room and still unbuyable, and most of what a consumer can buy is
184
- * commercial-suited product.
195
+ * A scope answers membership in its named distribution or visibility
196
+ * surface; the token-specific description states whether that means
197
+ * transaction or editorial inclusion. It never answers what is SUITABLE:
198
+ * scope on channel, then refine on sector.
185
199
  *
186
200
  * The scope is applied INSIDE the query: `limit` fills with eligible rows,
187
201
  * `counts` describe the SCOPED corpus, and the response echoes the scope.
@@ -203,6 +217,8 @@ export interface SearchGetParams {
203
217
  colours?: string;
204
218
  logic?: OpenEnum<"all" | "any">;
205
219
  mood?: string;
220
+ /** Governed corpus applied inside retrieval; absent means the whole graph. */
221
+ corpusScope?: CorpusScope;
206
222
  sort?: OpenEnum<"relevance" | "light" | "dark" | "vivid" | "muted" | "colourful" | "name" | "name_desc" | "recent">;
207
223
  tol?: OpenEnum<"tight" | "normal" | "loose">;
208
224
  /** Seed the search from this variant's image. Opaque — pass it through verbatim. */
@@ -214,6 +230,8 @@ export interface SearchGetParams {
214
230
  count?: OpenEnum<"true">;
215
231
  /** "true" — only return materials with at least one catalog image. */
216
232
  hasImages?: OpenEnum<"true">;
233
+ /** Require a recorded accepted sampleable=true fact. */
234
+ sampleableOnly?: OpenEnum<"true" | "false">;
217
235
  /** Result projection — `"full"` (default) or the lean `"card"` grid form. */
218
236
  view?: OpenEnum<"full" | "card">;
219
237
  /**
@@ -1,17 +1,63 @@
1
1
  /**
2
2
  * @module sdk/search-response-receipt-types
3
- * @description Inspectable routing, rerank, and compound-constraint receipts
4
- * emitted by ordinary Search responses.
3
+ * @description Inspectable routing, compatibility, and compound-constraint
4
+ * receipts emitted by ordinary Search responses.
5
5
  */
6
6
  import type { OpenEnum } from "./types.js";
7
+ /** Inspectable metadata for an opaque, principal-bound search refinement receipt. */
8
+ export interface SearchRefinementReceipt {
9
+ token: string;
10
+ expiresAt: string;
11
+ poolSize: number;
12
+ schemaVersion: string;
13
+ projectionVersion: number;
14
+ }
7
15
  /** The primary ranking source a query resolved to and reports as its mode. */
8
16
  export type SearchMode = OpenEnum<"image" | "colour" | "text" | "lexical" | "entity-browse">;
9
- /** Rerank-term report (absent in colour mode — there colour IS the source). */
17
+ /**
18
+ * Compatibility receipt for non-mode colour handling. Current one-signal
19
+ * ordering reports it skipped at weight 0; colour may still be diagnostic or a
20
+ * hard displayed-image constraint, but does not blend into score.
21
+ */
10
22
  export interface SearchRerankReport {
11
23
  colour?: OpenEnum<"ok" | "failed" | "skipped">;
12
24
  colourWeight?: number;
13
25
  colourLabel?: string;
14
26
  }
27
+ /** Stage counts retained when an explain-enabled search returns no results. */
28
+ export interface SearchEmptyOutcomeCounts {
29
+ retrieved: number;
30
+ afterPrune: number;
31
+ final: number;
32
+ }
33
+ /**
34
+ * Explain-only evidence for why a completed search returned no results.
35
+ * `proven-corpus-empty` is exhaustive; every other empty remains explicitly
36
+ * unproven rather than being presented as catalogue absence.
37
+ */
38
+ export type SearchEmptyOutcome = {
39
+ kind: "proven-corpus-empty";
40
+ basis: OpenEnum<"spec-allowlist" | "brand-scope">;
41
+ exhaustive: true;
42
+ sourceEmpty?: boolean | null;
43
+ counts?: SearchEmptyOutcomeCounts;
44
+ } | {
45
+ kind: "unproven-empty";
46
+ reason: OpenEnum<"allowlist-truncated" | "retrieval-window-not-exhaustive" | "source-empty" | "post-retrieval-rejected" | "pagination-empty" | "no-authoritative-empty-proof">;
47
+ sourceEmpty?: boolean | null;
48
+ counts?: SearchEmptyOutcomeCounts;
49
+ };
50
+ /** Explain-only coverage of substantive query terms in the lexical projection. */
51
+ export interface SearchTermCoverageReceipt {
52
+ status: OpenEnum<"covered" | "uncovered" | "unavailable" | "skipped">;
53
+ terms: string[];
54
+ note?: string;
55
+ }
56
+ /** Explain-only outcome receipts shared by full and card search responses. */
57
+ export interface SearchResponseExplainReceipts {
58
+ emptyOutcome?: SearchEmptyOutcome;
59
+ termCoverage?: SearchTermCoverageReceipt;
60
+ }
15
61
  /** One stage in the explain-only ledger of transformations that actually ran. */
16
62
  export type SearchQueryTransformStage = {
17
63
  stage: OpenEnum<"normalise" | "resolve-spec" | "resolve-paint" | "resolve-brand">;
@@ -63,7 +109,10 @@ export interface SearchBrandSkip {
63
109
  */
64
110
  export interface SearchExecutionPlan {
65
111
  grain: OpenEnum<"variant" | "product">;
112
+ /** Which 2048D Voyage projection served a text-mode request. */
113
+ textLane?: OpenEnum<"image-text" | "variant-text">;
66
114
  weights: {
115
+ portrait: number;
67
116
  image: number;
68
117
  category: number;
69
118
  colour: number;
@@ -71,6 +120,13 @@ export interface SearchExecutionPlan {
71
120
  text: number;
72
121
  };
73
122
  queryTransform: SearchQueryTransformStage[];
123
+ /** Ordered, explain-only request-understanding execution trace. */
124
+ steps?: Array<{
125
+ key: string;
126
+ status: OpenEnum<"executed" | "skipped">;
127
+ reason: string;
128
+ durationMs: number;
129
+ }>;
74
130
  categoryAnchor?: SearchCategoryAnchor;
75
131
  brandAnchor?: SearchBrandAnchor;
76
132
  brandSkipped?: SearchBrandSkip;
@@ -73,9 +73,12 @@ function checkColourMeta(value, what, fail) {
73
73
  requireOptionalString(record.dominantFamily, `${what}.dominantFamily`, fail);
74
74
  requireOptionalString(record.dominantHex, `${what}.dominantHex`, fail);
75
75
  }
76
- /** `searchResultSignalsSchema` — five nullable numbers, all required keys. */
76
+ /** `searchResultSignalsSchema` — five required scores plus additive portrait. */
77
77
  function checkSignals(value, what, fail) {
78
78
  const record = requireRecord(value, what, fail);
79
+ if (record.portrait !== undefined) {
80
+ requireNullableNumber(record.portrait, `${what}.portrait`, fail);
81
+ }
79
82
  for (const signal of ["image", "category", "colour", "lexical", "text"]) {
80
83
  requireNullableNumber(record[signal], `${what}.${signal}`, fail);
81
84
  }
@@ -140,6 +143,15 @@ function checkAttributeVerdict(value, what, fail) {
140
143
  requireNullableString(record.value, `${what}.value`, fail);
141
144
  requireNullableBoundedNumber(record.confidence, `${what}.confidence`, fail, 0, 1);
142
145
  requireNullableString(record.sourceBasis, `${what}.sourceBasis`, fail);
146
+ if (record.citation !== undefined) {
147
+ const citation = requireRecord(record.citation, `${what}.citation`, fail);
148
+ requireNonEmptyString(citation.citationId, `${what}.citation.citationId`, fail);
149
+ requireNonEmptyString(citation.sourceType, `${what}.citation.sourceType`, fail);
150
+ const count = requireNumber(citation.count, `${what}.citation.count`, fail);
151
+ if (!Number.isInteger(count) || count <= 0) {
152
+ throw fail(`${what}.citation.count must be a positive integer`);
153
+ }
154
+ }
143
155
  const deviation = record.deviation;
144
156
  if (deviation !== null)
145
157
  checkVerdictDeviation(deviation, `${what}.deviation`, fail);
@@ -204,6 +216,7 @@ export function checkSearchResultItem(value, what, fail) {
204
216
  if (record.signals !== undefined)
205
217
  checkSignals(record.signals, `${what}.signals`, fail);
206
218
  requireOptionalBoolean(record.retired, `${what}.retired`, fail);
219
+ requireOptionalBoolean(record.sampleable, `${what}.sampleable`, fail);
207
220
  requireOptionalBoolean(record.belowFloor, `${what}.belowFloor`, fail);
208
221
  requireOptionalBoolean(record.admittedOnColour, `${what}.admittedOnColour`, fail);
209
222
  if (record.siblingCount !== undefined) {
@@ -4,14 +4,22 @@ export interface SearchWindowReceipt {
4
4
  profile: "interactive-r1" | (string & {});
5
5
  /** Candidate depth used by the final retrieval. */
6
6
  candidateTier: number;
7
- /** Every candidate retrieval, including required fallbacks and optional recovery. */
7
+ /** Candidate retrieval count; `searchMaterials` reports exactly one selected retrieval. */
8
8
  retrievalRounds: number;
9
9
  /** Candidate-retrieval wall time only, in milliseconds. */
10
10
  retrievalMs: number;
11
11
  /** True when the serving source proved there were no more candidates. */
12
12
  exhaustive: boolean;
13
- /** True when product-grain scarcity caused one jump to the deep ceiling. */
14
- deepened: boolean;
15
- /** True when a still-short page exhausted its bounded recovery allowance. */
16
- budgetExhausted: boolean;
13
+ /**
14
+ * Candidate attrition through the selected retrieval source. Absent when the
15
+ * response path did not perform ordinary retrieval (for example typeahead).
16
+ */
17
+ candidateCounts?: {
18
+ /** Provider-returned matches before bounded selection; null for SQL/exact arms. */
19
+ rawProviderMatches: number | null;
20
+ /** Matches selected from that provider response; null for SQL/exact arms. */
21
+ selectedMatches: number | null;
22
+ /** Canonical candidates returned by the selected retrieval arm. */
23
+ hydratedCanonicalCandidates: number;
24
+ };
17
25
  }
@@ -25,6 +25,7 @@
25
25
  * TOLERANT-PARSING CONTRACT: response enums are widened with {@link OpenEnum}
26
26
  * so a new server value still type-checks; objects are read structurally.
27
27
  */
28
+ import type { VerdictCitation } from "./citation-types.js";
28
29
  import type { VariantId } from "./identifiers.js";
29
30
  import type { OpenEnum } from "./types.js";
30
31
  /**
@@ -147,6 +148,7 @@ export interface SlotPoolVerdictCell {
147
148
  */
148
149
  sourceBasis: string | null;
149
150
  trustGap: OpenEnum<"below_confidence" | "basis_unmet" | "proposed"> | null;
151
+ citation?: VerdictCitation;
150
152
  }
151
153
  /** Why a candidate is labelled. An eligible candidate carries none of these. */
152
154
  export type SlotPoolFlag = OpenEnum<"below-floor" | "required-not-applied" | "discontinued" | "superseded" | "unverified-value">;
package/spec-types.d.ts CHANGED
@@ -64,6 +64,11 @@ export interface SpecTermFilter {
64
64
  attributeId: string;
65
65
  term: string;
66
66
  }
67
+ /** A negative spec criterion; absence of a value remains unproven. */
68
+ export interface SpecExclusionFilter {
69
+ attributeId: string;
70
+ excludesTerm: string;
71
+ }
67
72
  /**
68
73
  * A presence spec criterion: the attribute must have ANY accepted value —
69
74
  * "has an EPD on record", "has a measured slip figure at all". Not supported for
@@ -94,4 +99,4 @@ export interface CertificationProgrammeFilter {
94
99
  * presence check. The union the search engine applies as a restriction BEFORE
95
100
  * ranking. Identical in shape to the SDK's `SearchFilter`.
96
101
  */
97
- export type SpecFilter = SpecTermFilter | SpecPresenceFilter;
102
+ export type SpecFilter = SpecTermFilter | SpecExclusionFilter | SpecPresenceFilter;
@@ -14,7 +14,9 @@
14
14
  * hand-format the `attribute:value` string the `bySpec` route splits on its
15
15
  * first `:`.
16
16
  */
17
- import { type CertificationProgrammeFilter, type SpecPresenceFilter, type SpecTermFilter } from "./spec-types.js";
17
+ import { type CertificationProgrammeFilter, type SpecExclusionFilter, type SpecPresenceFilter, type SpecTermFilter } from "./spec-types.js";
18
+ /** A hard criterion excluding one known canonical value while retaining only variants with known values. */
19
+ export declare function excludeSpec(attributeId: string, excludesTerm: string): SpecExclusionFilter;
18
20
  /**
19
21
  * A term-equality criterion for `search({ filters })` — the attribute must
20
22
  * carry this canonical value.
package/specifications.js CHANGED
@@ -15,6 +15,10 @@
15
15
  * first `:`.
16
16
  */
17
17
  import { CERTIFICATION_PROGRAMME_ATTRIBUTE_ID, } from "./spec-types.js";
18
+ /** A hard criterion excluding one known canonical value while retaining only variants with known values. */
19
+ export function excludeSpec(attributeId, excludesTerm) {
20
+ return { attributeId, excludesTerm };
21
+ }
18
22
  /**
19
23
  * A term-equality criterion for `search({ filters })` — the attribute must
20
24
  * carry this canonical value.
@@ -0,0 +1,75 @@
1
+ import type { BySpecVerdict } from "./by-spec-types.js";
2
+ import type { VariantId } from "./identifiers.js";
3
+ import type { MaterialSuccessor } from "./material-types.js";
4
+ export type SubstituteSignatureFamily = "textile" | "tile" | "coating" | "lighting_electrical" | "acoustic" | "surface" | "furniture" | "sanitaryware" | "fittings" | "architectural_hardware";
5
+ export interface SubstituteSignatureCriterion {
6
+ role: "primary_material" | "performance";
7
+ attributeId: string;
8
+ term: string;
9
+ }
10
+ export interface AvailableSubstituteSignature {
11
+ family: SubstituteSignatureFamily;
12
+ form: string;
13
+ criteria: [SubstituteSignatureCriterion, SubstituteSignatureCriterion];
14
+ }
15
+ export interface UnsupportedSubstituteSignature {
16
+ family: SubstituteSignatureFamily;
17
+ form: string;
18
+ reason: string;
19
+ }
20
+ export interface InsufficientSubstituteSignature {
21
+ family: SubstituteSignatureFamily;
22
+ form: string;
23
+ missingRoles: ("primary_material" | "performance")[];
24
+ }
25
+ export interface FindSubstitutesOptions {
26
+ excludeBrands?: string[];
27
+ diversityBoost?: number;
28
+ limit?: number;
29
+ cursor?: string;
30
+ includeSamplingArtifacts?: boolean;
31
+ includeUnavailable?: boolean;
32
+ }
33
+ export interface SubstituteMatchedCriterion {
34
+ attributeId: string;
35
+ confidence: number | null;
36
+ sourceBasis: string | null;
37
+ }
38
+ export interface SubstituteResultItem {
39
+ variantId: VariantId;
40
+ brandSlug: string;
41
+ brand: string;
42
+ product: string;
43
+ variant: string;
44
+ color: string | null;
45
+ imageUrl: string | null;
46
+ hex: string | null;
47
+ matched: SubstituteMatchedCriterion[];
48
+ minConfidence: number | null;
49
+ baseScore: number;
50
+ diversityAdjustment: number;
51
+ score: number;
52
+ verdict: BySpecVerdict;
53
+ }
54
+ export interface AvailableSubstitutesResponse {
55
+ status: "available";
56
+ signatureUsed: AvailableSubstituteSignature;
57
+ items: SubstituteResultItem[];
58
+ candidatePoolSize: number;
59
+ droppedUnavailable: number;
60
+ supersededBy: MaterialSuccessor | null;
61
+ nextCursor?: string;
62
+ }
63
+ export interface UnsupportedSubstitutesResponse {
64
+ status: "unsupported";
65
+ signature: UnsupportedSubstituteSignature;
66
+ items: [];
67
+ supersededBy: MaterialSuccessor | null;
68
+ }
69
+ export interface InsufficientSubstitutesResponse {
70
+ status: "insufficient_signature";
71
+ signature: InsufficientSubstituteSignature;
72
+ items: [];
73
+ supersededBy: MaterialSuccessor | null;
74
+ }
75
+ export type FindSubstitutesResponse = AvailableSubstitutesResponse | UnsupportedSubstitutesResponse | InsufficientSubstitutesResponse;
@@ -0,0 +1 @@
1
+ export {};
@@ -12,6 +12,7 @@
12
12
  * `mg.searchVocabulary()` covers attribute/value tokens. Suggestions are a page
13
13
  * of the best matches, never a census of matching entities.
14
14
  */
15
+ import type { CorpusScope, CorpusScopeReceipt } from "./corpus-scope-types.js";
15
16
  /** Which kind of entity a suggestion is — and therefore what `refId` means. */
16
17
  export type SuggestKind = "product" | "brand" | "category";
17
18
  /** How the query met the suggestion's label. Strongest first. */
@@ -44,6 +45,8 @@ export interface SuggestResponse {
44
45
  query: string;
45
46
  /** Ranked best-match-first. Empty when nothing came close — a miss, not an error. */
46
47
  suggestions: Suggestion[];
48
+ /** Present only when a narrowing governed corpus was applied. */
49
+ corpusScope?: CorpusScopeReceipt;
47
50
  }
48
51
  /** Options for {@link MaterialGraphClient.suggest}. */
49
52
  export interface SuggestOptions {
@@ -51,6 +54,8 @@ export interface SuggestOptions {
51
54
  limit?: number;
52
55
  /** Restrict to these kinds. Omit for all of them. */
53
56
  kind?: SuggestKind | SuggestKind[];
57
+ /** Governed corpus membership; absent means the whole graph. */
58
+ corpusScope?: CorpusScope;
54
59
  }
55
60
  /**
56
61
  * Shape the query string for a suggest call.
@@ -64,4 +69,5 @@ export declare function suggestQuery(q: string, options?: SuggestOptions): {
64
69
  q: string;
65
70
  limit?: number;
66
71
  kind?: string;
72
+ corpusScope?: CorpusScope;
67
73
  };
package/suggest-types.js CHANGED
@@ -24,5 +24,5 @@ export function suggestQuery(q, options) {
24
24
  const kind = Array.isArray(options?.kind)
25
25
  ? options.kind.join(",")
26
26
  : options?.kind;
27
- return { q, limit: options?.limit, kind };
27
+ return { q, limit: options?.limit, kind, corpusScope: options?.corpusScope };
28
28
  }
@@ -0,0 +1,34 @@
1
+ /** Exact, source-path-grained status coverage for primary product typing. */
2
+ export interface ProductTypeStatusCoverageCounts {
3
+ variants: number;
4
+ accepted: number;
5
+ proposed: number;
6
+ proposedBelowThreshold: number;
7
+ /** Proposed rows with no confidence remain explicit rather than thresholded. */
8
+ proposedUnknownConfidence: number;
9
+ otherStatus: number;
10
+ missingPrimary: number;
11
+ }
12
+ export interface ProductTypeStatusCoverageSourcePath extends ProductTypeStatusCoverageCounts {
13
+ /** Complete stored source path; null means the product retained no path. */
14
+ sourcePath: string | null;
15
+ }
16
+ /** Current primary-assignment coverage, never an inferred acceptance decision. */
17
+ export interface ProductTypeStatusCoverage {
18
+ computedAt: string;
19
+ basis: {
20
+ count: "exact";
21
+ universe: "non_superseded_variants";
22
+ assignment: "variant_primary_only";
23
+ sourcePath: "products.source_category_path";
24
+ /** Reporting cutoff only: higher-confidence proposals remain proposed. */
25
+ comparisonThreshold: number;
26
+ };
27
+ totals: ProductTypeStatusCoverageCounts;
28
+ sourcePaths: ProductTypeStatusCoverageSourcePath[];
29
+ }
30
+ export interface ProductTypeCoverageOptions {
31
+ [key: string]: number | undefined;
32
+ /** Reporting cutoff in [0,1], default 0.85; it never accepts a proposal. */
33
+ comparisonThreshold?: number;
34
+ }
@@ -0,0 +1 @@
1
+ export {};
package/types.d.ts CHANGED
@@ -32,18 +32,12 @@ import type { MaterialDetail, MaterialTile } from "./material-types.js";
32
32
  import type { QueryUnderstanding } from "./query-understanding-types.js";
33
33
  import type { CollapsedVariant, SearchAnatomyMember } from "./search-collapse-types.js";
34
34
  import type { SearchDisambiguation, SearchSuggestion } from "./search-refinement-types.js";
35
- import type { CompoundColourConstraintReceipt, CompoundFormConstraintReceipt, SearchExecutionPlan, SearchMode, SearchRerankReport } from "./search-response-receipt-types.js";
35
+ import type { CompoundColourConstraintReceipt, CompoundFormConstraintReceipt, SearchExecutionPlan, SearchMode, SearchRefinementReceipt, SearchRerankReport, SearchResponseExplainReceipts } from "./search-response-receipt-types.js";
36
36
  import type { SearchWindowReceipt } from "./search-window-types.js";
37
37
  export type * from "./search-response-receipt-types.js";
38
+ export type { MoodInterpretation } from "./search-mood-types.js";
38
39
  export type OpenEnum<T extends string> = T | (string & {});
39
- /**
40
- * A JSON value, recursively — exactly what survives a `jsonb` round-trip
41
- * unchanged. Used where a payload's SHAPE belongs to its producer but its values
42
- * must still be JSON: `Date`, `bigint`, `undefined`, and functions are not.
43
- */
44
- export type JsonValue = string | number | boolean | null | JsonValue[] | {
45
- [key: string]: JsonValue;
46
- };
40
+ export type { JsonValue } from "./json-value-types.js";
47
41
  /**
48
42
  * One palette swatch of a material's main image — colour DERIVED FROM PRODUCT
49
43
  * IMAGERY, so read it as visual likeness, never as a declared colour spec.
@@ -90,11 +84,13 @@ export type ImageSource = OpenEnum<"r2" | "origin">;
90
84
  export type { DimensionEntry, MaterialAvailability, MaterialDetail, MaterialFacet, MaterialSuccessor, MaterialTile, } from "./material-types.js";
91
85
  /** Per-signal scores, present on a result when `explain` was requested. */
92
86
  export interface SearchResultSignals {
87
+ /** Voyage similarity in the dedicated variant text-portrait space. */
88
+ portrait?: number | null;
93
89
  image: number | null;
94
90
  category: number | null;
95
91
  colour: number | null;
96
92
  lexical: number | null;
97
- /** Text→image RERANK cosine — non-null only for a seeded search carrying `text`. */
93
+ /** Compatibility slot for retired seeded secondary scoring; currently null. */
98
94
  text: number | null;
99
95
  }
100
96
  /** An accepted/measured visual meaning — descriptive evidence, never a ranking cause. */
@@ -118,6 +114,8 @@ export interface VisualMeaning {
118
114
  * `visualMeanings` is not "this material has no visual meaning".
119
115
  */
120
116
  export interface SearchResultItem {
117
+ /** Accepted sampleability fact. Absent means unknown, never false. */
118
+ sampleable?: boolean;
121
119
  /** Opaque — round-trip verbatim into `material()`, `pairings()`, `similarTo`. */
122
120
  variantId: VariantId;
123
121
  brand: string;
@@ -132,7 +130,7 @@ export interface SearchResultItem {
132
130
  * Populated on EVERY lane: `search()` (all four arms), `match()`, and
133
131
  * `matchStream()` frames.
134
132
  * ABSENT means no MB identity is known for the variant — never that the SKU
135
- * cannot be ordered. Presence is the orderability tell; absence is silence.
133
+ * cannot be ordered. Presence identifies the source; it does not establish sampleability.
136
134
  */
137
135
  materialBankId?: string;
138
136
  manufacturerCode?: string;
@@ -190,7 +188,7 @@ export interface SearchResultItem {
190
188
  siblings?: SearchAnatomyMember[];
191
189
  siblingsTruncated?: boolean;
192
190
  };
193
- /** Fused score — range [0, sum of active weights]; see `maxScore`. */
191
+ /** Selected mode's weighted primary score; see `maxScore`. */
194
192
  score: number;
195
193
  /**
196
194
  * Match only. How close this material is to the query, as an ABSOLUTE
@@ -274,6 +272,8 @@ export interface SearchResultItem {
274
272
  * card does not carry.
275
273
  */
276
274
  export interface SearchCardItem {
275
+ /** Accepted sampleability fact. Absent means unknown, never false. */
276
+ sampleable?: boolean;
277
277
  /** Opaque — round-trip verbatim. */
278
278
  variantId: VariantId;
279
279
  productId: ProductId | null;
@@ -378,14 +378,6 @@ export interface SearchFacets {
378
378
  absent: SearchAbsentFacet[];
379
379
  counts: Record<string, SearchFacetCount>;
380
380
  }
381
- /** Inspectable metadata for an opaque, principal-bound search refinement receipt. */
382
- export interface SearchRefinementReceipt {
383
- token: string;
384
- expiresAt: string;
385
- poolSize: number;
386
- schemaVersion: string;
387
- projectionVersion: number;
388
- }
389
381
  /**
390
382
  * The search response envelope. `view` discriminates the `results` union:
391
383
  * `"full"` (default) carries {@link SearchResultItem}s, `"card"` the lean
@@ -398,7 +390,7 @@ export interface SearchRefinementReceipt {
398
390
  * you asked for it. Follow `cursor` for the rest. "I found 24 materials" is
399
391
  * wrong whenever `limit` was 24.
400
392
  */
401
- export interface SearchResponse {
393
+ export interface SearchResponse extends SearchResponseExplainReceipts {
402
394
  view: OpenEnum<"full" | "card">;
403
395
  /** THIS PAGE. Its length is a page size, never a total. */
404
396
  results: SearchResultItem[];
@@ -436,6 +428,11 @@ export interface SearchResponse {
436
428
  timings?: Record<string, number>;
437
429
  /** A detected mood term overridden by a stronger colour reading. */
438
430
  supersededMoodId?: string;
431
+ /**
432
+ * Explicit standard-search mood reading; null ids mean no selected mood.
433
+ * Absent when mood was not evaluated or an older server produced the result.
434
+ */
435
+ moodInterpretation?: import("./search-mood-types.js").MoodInterpretation;
439
436
  /**
440
437
  * Present when the query had multiple defensible readings. Says which one
441
438
  * ran, or leaves every reading non-default when the engine chose none. Every
@@ -711,6 +708,8 @@ export interface PairingsOptions {
711
708
  categories?: string;
712
709
  /** Page size, 1–24 inclusive (default 12). The server rejects (400), not clamps, values outside this range. */
713
710
  limit?: number;
711
+ /** Return sampled order evidence only, without board or colour fallback. */
712
+ sampledOnly?: boolean;
714
713
  /** Graph-owned order applied within fixed cospec → considered → colour tiers. */
715
714
  order?: PairingOrderMode;
716
715
  /** Optional Material Bank/orderable gate; requires an explicit `order`. */