@instruments/materialgraph 0.25.0 → 0.27.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 (158) hide show
  1. package/association-types.d.ts +38 -27
  2. package/associations-client.d.ts +4 -4
  3. package/associations-client.js +3 -10
  4. package/attribution-types.d.ts +4 -4
  5. package/brand-types.d.ts +14 -6
  6. package/brands-client.d.ts +7 -38
  7. package/brands-client.js +10 -40
  8. package/by-colour-types.d.ts +58 -31
  9. package/by-spec-types.d.ts +6 -73
  10. package/by-spec-types.js +7 -5
  11. package/catalog-discovery-types.d.ts +11 -26
  12. package/catalogue-client.d.ts +16 -35
  13. package/catalogue-client.js +32 -67
  14. package/catalogue-types.d.ts +44 -4
  15. package/categories-client.d.ts +63 -0
  16. package/categories-client.js +48 -0
  17. package/category-types.d.ts +114 -0
  18. package/citation-types.d.ts +4 -4
  19. package/client-config.d.ts +4 -6
  20. package/client-config.js +2 -4
  21. package/client-source-material-comments.d.ts +4 -4
  22. package/client-source-material-comments.js +4 -38
  23. package/client-vocabulary.d.ts +7 -9
  24. package/client-vocabulary.js +22 -30
  25. package/client.d.ts +110 -244
  26. package/client.js +217 -387
  27. package/codes-client.d.ts +2 -2
  28. package/codes-client.js +8 -8
  29. package/codes-types.d.ts +55 -34
  30. package/colour-aggregate-types.d.ts +24 -24
  31. package/colours-client.d.ts +6 -11
  32. package/colours-client.js +11 -19
  33. package/coordinate-client.d.ts +2 -2
  34. package/coordinate-client.js +1 -13
  35. package/corpus-scope-types.d.ts +3 -3
  36. package/corpus-scope-types.js +1 -25
  37. package/demand-batch-types.d.ts +18 -18
  38. package/demand-types.d.ts +24 -24
  39. package/errors.d.ts +13 -13
  40. package/errors.js +54 -52
  41. package/http-transport.d.ts +13 -21
  42. package/http-transport.js +31 -28
  43. package/identify-types.d.ts +54 -44
  44. package/identify-types.js +5 -3
  45. package/index.d.ts +11 -27
  46. package/index.js +4 -6
  47. package/list-variant-facets-types.d.ts +60 -0
  48. package/list-variants-types.d.ts +142 -0
  49. package/list-variants-types.js +12 -0
  50. package/match-stream-types.d.ts +45 -32
  51. package/match-stream-types.js +2 -0
  52. package/match-stream.d.ts +2 -2
  53. package/match-stream.js +67 -49
  54. package/match-types.d.ts +32 -8
  55. package/material-asset-types.d.ts +89 -69
  56. package/material-block-types.d.ts +8 -6
  57. package/material-composition-client.d.ts +21 -0
  58. package/material-composition-client.js +13 -0
  59. package/material-composition-types.d.ts +403 -0
  60. package/material-query-plan-types.d.ts +61 -145
  61. package/material-resources-client.d.ts +12 -10
  62. package/material-resources-client.js +27 -22
  63. package/material-types.d.ts +16 -24
  64. package/ndjson.js +16 -8
  65. package/operations.d.ts +6 -6
  66. package/operations.js +29 -156
  67. package/package.json +5 -1
  68. package/palette-search-types.d.ts +87 -52
  69. package/query-understanding-types.d.ts +65 -40
  70. package/resolve-client.d.ts +8 -12
  71. package/resolve-client.js +9 -13
  72. package/resolve-colour-types.d.ts +8 -8
  73. package/resolve-types.d.ts +10 -10
  74. package/response-schemas.d.ts +20 -0
  75. package/response-schemas.generated.d.ts +5 -0
  76. package/response-schemas.generated.js +160 -0
  77. package/response-schemas.js +113 -0
  78. package/run-types.d.ts +64 -145
  79. package/runs.d.ts +9 -58
  80. package/runs.js +60 -149
  81. package/samplize-catalogue-types.d.ts +18 -18
  82. package/samplize-colorvec.d.ts +20 -20
  83. package/samplize-colorvec.js +66 -42
  84. package/schema-resource-types.d.ts +52 -39
  85. package/schema-resource-types.js +5 -5
  86. package/search-card-types.d.ts +26 -4
  87. package/search-index-plan-types.d.ts +70 -0
  88. package/search-refinement-types.d.ts +10 -40
  89. package/search-refinement-types.js +1 -0
  90. package/search-request-types.d.ts +121 -204
  91. package/search-response-receipt-types.d.ts +13 -253
  92. package/search-response-types.d.ts +2 -2
  93. package/search-result-validation.d.ts +3 -19
  94. package/search-result-validation.js +42 -183
  95. package/source-material-validation.d.ts +3 -3
  96. package/source-material-validation.js +35 -39
  97. package/spec-facet-types.d.ts +11 -16
  98. package/spec-types.d.ts +23 -16
  99. package/spec-types.js +8 -7
  100. package/specifications.d.ts +14 -72
  101. package/specifications.js +39 -89
  102. package/sse.d.ts +2 -2
  103. package/sse.js +32 -16
  104. package/substitute-types.d.ts +22 -22
  105. package/suggest-types.d.ts +11 -17
  106. package/suggest-types.js +3 -3
  107. package/taxonomy-coverage-types.d.ts +8 -8
  108. package/types.d.ts +202 -405
  109. package/validation.d.ts +26 -26
  110. package/validation.js +97 -92
  111. package/webmcp.d.ts +3 -3
  112. package/webmcp.generated.js +10 -93
  113. package/brand-most-sampled-types.d.ts +0 -33
  114. package/browse-types.d.ts +0 -236
  115. package/client-browse.d.ts +0 -78
  116. package/client-browse.js +0 -72
  117. package/client-exploration.d.ts +0 -9
  118. package/client-exploration.js +0 -7
  119. package/compare-types.d.ts +0 -89
  120. package/composition-client.d.ts +0 -33
  121. package/composition-client.js +0 -27
  122. package/composition-types.d.ts +0 -455
  123. package/composition-types.js +0 -10
  124. package/correction-types.d.ts +0 -88
  125. package/exploration-types.d.ts +0 -118
  126. package/exploration-types.js +0 -1
  127. package/fan-deck-types.d.ts +0 -42
  128. package/fan-deck-types.js +0 -9
  129. package/match-rejection-types.d.ts +0 -43
  130. package/match-rejection-types.js +0 -7
  131. package/palette-completion-types.d.ts +0 -115
  132. package/palette-completion-types.js +0 -1
  133. package/project-types.d.ts +0 -79
  134. package/project-types.js +0 -9
  135. package/projects.d.ts +0 -13
  136. package/projects.js +0 -46
  137. package/render-assets-types.d.ts +0 -65
  138. package/render-assets-types.js +0 -1
  139. package/run-events.d.ts +0 -106
  140. package/run-events.js +0 -32
  141. package/schedule-reference-types.d.ts +0 -46
  142. package/schedule-reference-types.js +0 -1
  143. package/schedule-references-client.d.ts +0 -14
  144. package/schedule-references-client.js +0 -26
  145. package/schedule-types.d.ts +0 -261
  146. package/schedule-types.js +0 -1
  147. package/search-collapse-types.d.ts +0 -69
  148. package/search-collapse-types.js +0 -1
  149. package/search-mood-types.d.ts +0 -6
  150. package/search-mood-types.js +0 -1
  151. package/search-window-types.d.ts +0 -25
  152. package/search-window-types.js +0 -1
  153. package/slot-pool-types.d.ts +0 -372
  154. package/slot-pool-types.js +0 -1
  155. /package/{brand-most-sampled-types.js → category-types.js} +0 -0
  156. /package/{browse-types.js → list-variant-facets-types.js} +0 -0
  157. /package/{compare-types.js → material-composition-types.js} +0 -0
  158. /package/{correction-types.js → search-index-plan-types.js} +0 -0
@@ -1,3 +1,4 @@
1
+ import type { ColourCategoryGate } from "./by-colour-types.js";
1
2
  import type { CorpusScope, CorpusScopeReceipt } from "./corpus-scope-types.js";
2
3
  /**
3
4
  * Wire types for MULTI-COLOUR search — `POST /api/v1/search/palettes` and
@@ -17,67 +18,91 @@ import type { OklabTriple, OpenEnum } from "./types.js";
17
18
  /** How the per-colour scores are combined across a palette. */
18
19
  export type PaletteLogic = OpenEnum<"all" | "any">;
19
20
  /** One queried palette colour — exactly one of `hex` or `oklab`. */
20
- export interface PaletteQueryColour {
21
+ export type PaletteQueryColour = {
21
22
  hex?: string;
22
23
  oklab?: OklabTriple;
23
24
  /**
24
- * Share of the surface this colour should occupy, in (0,1]. Stating it
25
- * CHANGES the ranking: a colour asked for at 0.6 rewards candidates whose own
26
- * swatch sits near 0.6, not merely candidates that contain the colour.
25
+ * Share of the surface this colour should occupy, in (0,1]. A colour stated
26
+ * below 5% is dropped; otherwise not applied, since a palette is ordered by
27
+ * its first colour alone.
27
28
  */
28
29
  proportion?: number;
29
- /** Relative importance; defaults to 1 and is normalised across the query. */
30
+ /** Relative importance. Not applied: a palette is ordered by its first colour. */
30
31
  weight?: number;
31
- }
32
+ };
32
33
  /** One gradient stop — exactly one of `hex` or `oklab`. Order is meaningful. */
33
- export interface GradientStop {
34
+ export type GradientStop = {
34
35
  hex?: string;
35
36
  oklab?: OklabTriple;
36
- }
37
- export interface SearchPaletteInput {
37
+ };
38
+ export type SearchPaletteInput = {
39
+ /**
40
+ * HARD category filter: category-group or product-type names or keys.
41
+ * Absent, the page holds surface materials only, so lights, taps and
42
+ * furniture are left out.
43
+ */
44
+ category?: string[];
38
45
  corpusScope?: CorpusScope;
39
- /** The palette to match, 1–8 colours. */
46
+ /**
47
+ * The palette to match, 1–8 colours. The page is ordered by the FIRST colour;
48
+ * the rest come back in `query.droppedColours`.
49
+ */
40
50
  colours: PaletteQueryColour[];
41
51
  /**
42
- * `all` (the default) requires every queried colour to clear a per-colour
43
- * eligibility floor and scores the weighted geometric mean; `any` is a
44
- * noisy-OR and never rejects a candidate for missing one colour.
52
+ * Kept so existing callers still parse: the one search orders the page by
53
+ * the first colour with no eligibility floor, so `all` and `any` return the
54
+ * same page.
45
55
  */
46
56
  logic?: PaletteLogic;
47
57
  /** Results to return; defaults to 24, capped at 48. */
48
58
  limit?: number;
49
- }
50
- export interface SearchGradientInput {
59
+ };
60
+ export type SearchGradientInput = {
61
+ /**
62
+ * HARD category filter: category-group or product-type names or keys.
63
+ * Absent, the page holds surface materials only, so lights, taps and
64
+ * furniture are left out.
65
+ */
66
+ category?: string[];
51
67
  corpusScope?: CorpusScope;
52
68
  /** The ordered colour transition, 2–6 stops. */
53
69
  stops: GradientStop[];
54
70
  /** Results to return; defaults to 24, capped at 48. */
55
71
  limit?: number;
56
- }
72
+ };
57
73
  /**
58
74
  * One swatch used for scoring. Samplize paint uses its selected published hex;
59
75
  * other materials use colorscope palettes extracted from imagery. `name` is null when no human
60
76
  * name was resolved — unnamed, not colourless.
61
77
  */
62
- export interface CandidateSwatch {
78
+ export type CandidateSwatch = {
63
79
  hex: string;
64
80
  proportion: number;
65
81
  name: string | null;
66
- }
82
+ };
67
83
  /** Why a queried colour (or gradient sample) scored what it scored. */
68
- export interface ColourMatchReceipt {
84
+ export type ColourMatchReceipt = {
69
85
  queryHex: string;
70
- /** `colourScore × proportionScore` for the best-matching swatch. */
86
+ /** `colourScore × proportionScore`, so `colourScore` on the one search. */
71
87
  score: number;
72
- /** OKLab closeness alone, in [0,1]. */
88
+ /**
89
+ * Closeness in [0,1] of the matched swatch to the queried colour, from plain
90
+ * OKLab distance with lightness counted in full. Not a confidence.
91
+ */
73
92
  colourScore: number;
74
- /** Proportion agreement alone, in [0,1]. */
93
+ /** Proportion agreement; always 1, since no proportion is applied. */
75
94
  proportionScore: number;
76
95
  /** The swatch that produced the score, or null when nothing matched. */
77
96
  matched: CandidateSwatch | null;
78
- }
97
+ /**
98
+ * Whether `matched` has a hue compatible with the queried colour, at the
99
+ * response's `hueGate` thresholds. A flag, never a gate: an incompatible
100
+ * swatch still scores and ranks. Absent when there is no `matched` swatch.
101
+ */
102
+ hueCompatible?: boolean;
103
+ };
79
104
  /** Identity and evidence shared by both multi-colour match shapes. */
80
- export interface MultiColourMatchBase {
105
+ export type MultiColourMatchBase = {
81
106
  /** Opaque — round-trip verbatim. */
82
107
  variantId: VariantId;
83
108
  brand: string;
@@ -87,6 +112,11 @@ export interface MultiColourMatchBase {
87
112
  color: string | null;
88
113
  variantName: string | null;
89
114
  imageUrl: string | null;
115
+ /**
116
+ * SHA-256 of the displayed image `imageUrl` points at, as a hex digest.
117
+ * ABSENT means no hash is on record, never that there is no image.
118
+ */
119
+ imageSha256?: string;
90
120
  /** MB has retired or hidden this SKU. */
91
121
  retired: boolean;
92
122
  /**
@@ -103,80 +133,85 @@ export interface MultiColourMatchBase {
103
133
  category: string | null;
104
134
  /** The candidate's full extracted palette — the evidence scored against. */
105
135
  palette: CandidateSwatch[];
106
- /** The aggregate match score in [0,1]; higher is closer. */
136
+ /**
137
+ * Closeness in [0,1] of the material's own colour to the searched colour,
138
+ * the page's order. Not a confidence or a percentage.
139
+ */
107
140
  score: number;
108
- }
109
- export interface PaletteMatch extends MultiColourMatchBase {
141
+ };
142
+ export type PaletteMatch = {
110
143
  /** One receipt per queried colour, in query order. */
111
144
  colours: ColourMatchReceipt[];
112
- }
113
- export interface GradientMatch extends MultiColourMatchBase {
145
+ } & MultiColourMatchBase;
146
+ export type GradientMatch = {
114
147
  /**
115
- * Distinct matched thirds of the path over 3. A material owning only one end
116
- * of the transition caps out around 0.33 — coverage is what separates a real
117
- * gradient match from a good match on a single stop.
148
+ * Thirds of the path where the material holds a swatch near a sampled point,
149
+ * over 3. A receipt beside the order, which is by the first stop.
118
150
  */
119
151
  coverage: number;
120
152
  /** One receipt per sampled point along the path, in path order. */
121
153
  samples: ColourMatchReceipt[];
122
- }
154
+ } & MultiColourMatchBase;
123
155
  /**
124
- * The hue-family ADMISSION gate the page was scored under: a candidate swatch
125
- * may satisfy a query colour only if colorscope's `isHueCompatible` admits it
126
- * at these exact thresholds. A refused swatch is absent from that colour's
127
- * matching entirely — it did not merely rank low. Admission, not ranking: it
128
- * decides which swatches count, never their order. Server-side and fixed (no
129
- * request knob); the receipt exists so a threshold change is visible on the
130
- * wire.
156
+ * The thresholds behind every receipt's `hueCompatible`: the exact values
157
+ * passed to colorscope's `isHueCompatible`, fixed server-side with no request
158
+ * knob. A FLAG, never admission or ranking: every swatch still scores, and the
159
+ * page and its order are the same with or without it.
131
160
  */
132
- export interface HueGateReceipt {
161
+ export type HueGateReceipt = {
133
162
  /** Below this query chroma the colour is achromatic and any hue is admitted. */
134
163
  achromaticQueryChroma: number;
135
164
  /** A swatch must carry at least this share of the query colour's chroma. */
136
165
  minChromaRatio: number;
137
166
  /** Floor on the cosine agreement between the two hue vectors. */
138
167
  minHueCosine: number;
139
- }
168
+ };
140
169
  /**
141
170
  * A PAGE, NOT A CORPUS. `count` is `matches.length` under `limit` (24 default,
142
171
  * 48 max) — this surface states no corpus total and has no cursor, so "N
143
172
  * materials match this palette" is not a claim you can make from it.
144
173
  */
145
- export interface SearchPaletteResponse {
174
+ export type SearchPaletteResponse = {
146
175
  corpusScope?: CorpusScopeReceipt;
147
176
  /** The query as interpreted — check it before trusting a surprising order. */
148
177
  query: {
149
178
  /** Colours that actually ran after minor stated shares were omitted. */
150
- colours: Array<{
179
+ colours: {
151
180
  hex: string;
152
181
  proportion?: number;
153
182
  weight?: number;
154
- }>;
183
+ }[];
155
184
  /** Colours not searched because their stated share was below 5%. */
156
- droppedColours: Array<{
185
+ droppedColours: {
157
186
  hex: string;
158
187
  proportion?: number;
159
188
  weight?: number;
160
- }>;
189
+ }[];
161
190
  logic: PaletteLogic;
162
191
  /** `no_effective_colours` means no material query ran. */
163
192
  outcome: OpenEnum<"matches" | "no_effective_colours">;
164
193
  };
165
- /** The hue-family admission gate this page was scored under. */
166
- hueGate: HueGateReceipt;
194
+ /** The category gate the page ran under. */
195
+ categoryGate?: ColourCategoryGate;
196
+ /** The thresholds behind each receipt's `hueCompatible`. Absent only on responses stored before it existed. */
197
+ hueGate?: HueGateReceipt;
167
198
  /** `matches.length`, capped by `limit`. Never a corpus total. */
168
199
  count: number;
169
200
  matches: PaletteMatch[];
170
- }
201
+ };
171
202
  /** A PAGE, NOT A CORPUS — see {@link SearchPaletteResponse}. */
172
- export interface SearchGradientResponse {
203
+ export type SearchGradientResponse = {
204
+ /** The category gate the page ran under. */
205
+ categoryGate?: ColourCategoryGate;
173
206
  corpusScope?: CorpusScopeReceipt;
174
207
  query: {
175
208
  stops: string[];
176
209
  /** The sampled path points the search actually ran against. */
177
210
  samples: string[];
178
211
  };
212
+ /** The thresholds behind each sample receipt's `hueCompatible`. */
213
+ hueGate?: HueGateReceipt;
179
214
  /** `matches.length`, capped by `limit`. Never a corpus total. */
180
215
  count: number;
181
216
  matches: GradientMatch[];
182
- }
217
+ };
@@ -3,7 +3,7 @@ import type { ColorResolution } from "@instruments/colorscope/naming";
3
3
  import type { SearchFilter } from "./search-refinement-types.js";
4
4
  import type { OpenEnum } from "./types.js";
5
5
  export type QuerySenseKind = OpenEnum<"brand" | "product" | "paint_identity" | "category" | "material" | "colour" | "attribute" | "attribute_value" | "certification">;
6
- export interface QuerySense {
6
+ export type QuerySense = {
7
7
  id: string;
8
8
  kind: QuerySenseKind;
9
9
  label: string;
@@ -28,14 +28,14 @@ export interface QuerySense {
28
28
  hex?: string;
29
29
  };
30
30
  reason?: string;
31
- }
32
- export interface CanonicalLexicalAuthorityReceipt {
31
+ };
32
+ export type CanonicalLexicalAuthorityReceipt = {
33
33
  authority: OpenEnum<"taxonomy" | "colorscope">;
34
34
  version: string;
35
35
  revision: string;
36
36
  digest?: string;
37
- }
38
- export interface CanonicalLexicalReading {
37
+ };
38
+ export type CanonicalLexicalReading = {
39
39
  matchTarget?: MatchTarget;
40
40
  colorResolution?: ColorResolution;
41
41
  authority: OpenEnum<"taxonomy" | "colorscope">;
@@ -63,8 +63,8 @@ export interface CanonicalLexicalReading {
63
63
  snapshot?: string;
64
64
  source: string;
65
65
  };
66
- }
67
- export interface CanonicalLexicalMatch {
66
+ };
67
+ export type CanonicalLexicalMatch = {
68
68
  original: string;
69
69
  canonical: string;
70
70
  rule: OpenEnum<"exact" | "plural-to-singular" | "typo-to-canonical">;
@@ -80,24 +80,24 @@ export interface CanonicalLexicalMatch {
80
80
  rule: OpenEnum<"exact" | "plural-to-singular" | "typo-to-canonical">;
81
81
  authorities: CanonicalLexicalAuthorityReceipt[];
82
82
  };
83
- }
84
- export interface CanonicalLexicalReceipt {
83
+ };
84
+ export type CanonicalLexicalReceipt = {
85
85
  original: string;
86
86
  outcome: OpenEnum<"resolved" | "ambiguous" | "declined" | "partial" | "unresolved">;
87
87
  matches: CanonicalLexicalMatch[];
88
88
  unresolved: CanonicalLexicalMatch[];
89
- }
90
- export interface QueryResidualReceipt {
89
+ };
90
+ export type QueryResidualReceipt = {
91
91
  kind: OpenEnum<"compound" | "descriptive" | "ambiguous" | "empty">;
92
92
  tokens: string[];
93
93
  resolvedTokens: string[];
94
94
  unresolvedTokens: string[];
95
95
  resolvedRatio: number;
96
96
  comparisonFrame: boolean;
97
- }
97
+ };
98
98
  /** Deterministic criteria compiled from the query before retrieval. */
99
- export interface QueryCriteriaReceipt {
100
- applied: Array<{
99
+ export type QueryCriteriaReceipt = {
100
+ applied: {
101
101
  criterion: SearchFilter;
102
102
  lane: OpenEnum<"filter" | "preference">;
103
103
  lexicalSignal?: {
@@ -114,30 +114,30 @@ export interface QueryCriteriaReceipt {
114
114
  };
115
115
  source: OpenEnum<"compiled" | "taxonomy-adapter">;
116
116
  span: string;
117
- }>;
118
- conflicts: Array<{
117
+ }[];
118
+ conflicts: {
119
119
  attributeId: string;
120
120
  caller: SearchFilter;
121
121
  compiled: SearchFilter;
122
122
  reason: string;
123
- }>;
124
- exclusions: Array<{
123
+ }[];
124
+ exclusions: {
125
125
  criterion: SearchFilter;
126
126
  execution: OpenEnum<"blocked-positive-only-contract">;
127
127
  lane: OpenEnum<"hard" | "soft">;
128
128
  missingValuePolicy: OpenEnum<"retain-unknown">;
129
129
  span: string;
130
- }>;
130
+ }[];
131
131
  preferences: SearchFilter[];
132
132
  residualText: string | null;
133
- unresolved: Array<{
133
+ unresolved: {
134
134
  code: OpenEnum<"missing-searchable-attribute" | "missing-dimension-pair-contract" | "missing-explicit-comparator" | "negative-criterion-contract-blocked" | "registry-contract-drift" | "unsupported-numeric-format" | "unsupported-unit" | "unsupported-strict-comparator">;
135
135
  reason: string;
136
136
  span: string;
137
- }>;
138
- }
137
+ }[];
138
+ };
139
139
  /** How the query named or inferred a product type before retrieval. */
140
- export interface QueryProductTypeReceipt {
140
+ export type QueryProductTypeReceipt = {
141
141
  kind: OpenEnum<"leaf" | "group" | "vector" | "ambiguous" | "none">;
142
142
  gate: OpenEnum<"hard" | "constrain" | "none">;
143
143
  pass: OpenEnum<"taxonomy" | "synonym" | "display-name" | "group" | "head-noun" | "vector" | "none">;
@@ -152,14 +152,14 @@ export interface QueryProductTypeReceipt {
152
152
  vectorPassRan: boolean;
153
153
  registryVersion: string;
154
154
  durationMs: number;
155
- candidates: Array<{
155
+ candidates: {
156
156
  productTypeId: string;
157
157
  displayName: string;
158
158
  similarity: number;
159
- }>;
160
- }
159
+ }[];
160
+ };
161
161
  /** The selected retrieval arm; null when the path is browse or criteria-only. */
162
- export interface QueryArmReceipt {
162
+ export type QueryArmReceipt = {
163
163
  arm: OpenEnum<"dense" | "lexical" | "colour"> | null;
164
164
  reason: string;
165
165
  reasonDetail?: OpenEnum<"derived-colour-veto" | "typo-recovery" | "literal-compound-without-type">;
@@ -169,8 +169,8 @@ export interface QueryArmReceipt {
169
169
  productTypeIds: string[];
170
170
  residual: QueryResidualReceipt;
171
171
  registryVersion: string;
172
- }
173
- export interface QueryAmbiguityReceipt {
172
+ };
173
+ export type QueryAmbiguityReceipt = {
174
174
  outcome: OpenEnum<"applied" | "abstained" | "refused" | "timeout">;
175
175
  modelId: string | null;
176
176
  providerRan: boolean;
@@ -182,24 +182,45 @@ export interface QueryAmbiguityReceipt {
182
182
  routing: OpenEnum<"compound" | "descriptive"> | null;
183
183
  productTypeIds: string[];
184
184
  changedArm: boolean;
185
- }
186
- export interface QueryCategoryScopeReceipt {
185
+ };
186
+ export type QueryCategoryScopeReceipt = {
187
187
  source: OpenEnum<"caller" | "anchor">;
188
188
  mechanism: OpenEnum<"sql-predicate" | "provider-filter" | "allowlist" | "prune">;
189
189
  variantCount: number | null;
190
190
  ceiling: number;
191
191
  specScanBounded?: boolean;
192
192
  [key: string]: unknown;
193
- }
194
- export interface QuerySpecAllowlistReceipt {
193
+ };
194
+ export type QuerySpecAllowlistReceipt = {
195
195
  limit: number;
196
196
  returned: number;
197
197
  retrieved?: number;
198
198
  truncated: boolean;
199
199
  emptyMeansScarcity: boolean;
200
200
  outcome?: OpenEnum<"corpus-scarcity" | "retrieval-miss" | "unknown">;
201
- }
202
- export interface QueryUnsatisfiableNarrowing {
201
+ };
202
+ /**
203
+ * Whether the phrase-reading step turned the query's descriptive words into
204
+ * filters and preferences. Present only on the workflow lane.
205
+ */
206
+ export type QueryPhraseReadingReceipt = {
207
+ outcome: OpenEnum<"skipped">;
208
+ reason: string;
209
+ } | {
210
+ outcome: OpenEnum<"read">;
211
+ /** Which model read the phrase: `jev`, or `second` behind it. */
212
+ reader: OpenEnum<"jev" | "second">;
213
+ elapsedMs: number;
214
+ leftAsText: string[];
215
+ rows: {
216
+ kind: OpenEnum<"want" | "avoid">;
217
+ attributeId: string;
218
+ values: string[];
219
+ confidence: number;
220
+ applied: boolean;
221
+ }[];
222
+ };
223
+ export type QueryUnsatisfiableNarrowing = {
203
224
  narrowing: OpenEnum<"product-type">;
204
225
  gate: OpenEnum<"hard">;
205
226
  productTypeId: string;
@@ -207,16 +228,19 @@ export interface QueryUnsatisfiableNarrowing {
207
228
  productTypeIds: string[];
208
229
  pass: string;
209
230
  evidence: OpenEnum<"zero-accepted-variants">;
210
- relaxedTo: OpenEnum<"none">;
211
- }
231
+ relaxedDisplayName?: string;
232
+ relaxedProductTypeId?: string;
233
+ relaxedProductTypeIds?: string[];
234
+ relaxedTo: OpenEnum<"head-noun" | "none">;
235
+ };
212
236
  /** Inspectable interpretation of the raw query by ordinary MaterialGraph search. */
213
- export interface QueryUnderstanding {
237
+ export type QueryUnderstanding = {
214
238
  version: OpenEnum<"1">;
215
239
  rawQuery: string;
216
240
  normalisedQuery: string;
217
241
  residualText: string;
218
242
  status: OpenEnum<"resolved" | "ambiguous" | "partial" | "unresolved">;
219
- mode: OpenEnum<"image" | "colour" | "text" | "lexical" | "entity-browse">;
243
+ mode: OpenEnum<"image" | "colour" | "text" | "lexical" | "entity-browse" | "attribute">;
220
244
  senses: QuerySense[];
221
245
  canonicalLexical?: CanonicalLexicalReceipt;
222
246
  criteria?: QueryCriteriaReceipt;
@@ -226,4 +250,5 @@ export interface QueryUnderstanding {
226
250
  categoryScope?: QueryCategoryScopeReceipt;
227
251
  specAllowlist?: QuerySpecAllowlistReceipt;
228
252
  unsatisfiableNarrowing?: QueryUnsatisfiableNarrowing;
229
- }
253
+ phraseReading?: QueryPhraseReadingReceipt;
254
+ };
@@ -17,9 +17,7 @@
17
17
  * silently the moment the registry moves.
18
18
  * - The whole phrase, any vocabulary → {@link resolvePhrasesRequest}. Batched,
19
19
  * deterministic, and it says so out loud when a word means nothing here.
20
- * - You already know it is an attribute, or a value under a known attribute →
21
- * `mg.resolveAttribute()` / `mg.resolveAttributeValue()`.
22
- * - You want to EXPLAIN a token you already hold → `mg.glossary(term)`.
20
+ * - You already know it is an attribute → `mg.listAttributes({ query })`.
23
21
  * - You want to complete a name as someone types → `mg.suggest()`.
24
22
  * - You want MATERIALS → `mg.search()`. This lens never returns one.
25
23
  */
@@ -56,9 +54,8 @@ import type { VocabularySearchOptions, VocabularySearchResponse } from "./types.
56
54
  * could have caught comes back unresolved rather than slow.
57
55
  *
58
56
  * Deterministic — the same batch resolves to the same bytes every time. Instead
59
- * use `mg.search()` when you want materials rather than words, `mg.suggest()` to
60
- * complete a name as someone types, and `mg.glossary()` to EXPLAIN a token you
61
- * have already resolved.
57
+ * use `mg.search()` when you want materials rather than words, and
58
+ * `mg.suggest()` to complete a name as someone types.
62
59
  *
63
60
  * - **Every reading says what stands behind it.** `coverage.variants` is how
64
61
  * many variants carry it corpus-wide, and `0` is a measured answer rather
@@ -76,15 +73,14 @@ import type { VocabularySearchOptions, VocabularySearchResponse } from "./types.
76
73
  * resolved independently, so one meaningless phrase never spoils the batch.
77
74
  * @param options `category` to scope the coverage answer, and an `AbortSignal`.
78
75
  */
79
- export declare function resolvePhrasesRequest(transport: HttpTransport, phrases: string[], scope?: ResolvePhrasesScope): Promise<ResolveResponse>;
76
+ export declare const resolvePhrasesRequest: (transport: HttpTransport, phrases: string[], scope?: ResolvePhrasesScope) => Promise<ResolveResponse>;
80
77
  /**
81
78
  * THE QUESTION: "is 'FloorScore' an attribute or a value, and what is it called
82
79
  * here?" The catch-all for ONE phrase when you do not know which half of an
83
80
  * `attribute:value` pair it belongs to. Backs `mg.searchVocabulary()`.
84
81
  *
85
- * Instead use `mg.resolveAttribute()` / `mg.resolveAttributeValue()` once you do
86
- * know, {@link resolvePhrasesRequest} when you have SEVERAL phrases or the
87
- * phrase might name a brand, paint, colour or category rather than a spec, and
88
- * `mg.glossary()` to EXPLAIN a term rather than find it.
82
+ * Instead use `mg.listAttributes({ query })` once you do know the attribute,
83
+ * or {@link resolvePhrasesRequest} when you have SEVERAL phrases or the phrase
84
+ * might name a brand, paint, colour or category rather than a spec.
89
85
  */
90
- export declare function searchVocabularyRequest(transport: HttpTransport, query: string, options?: VocabularySearchOptions, signal?: AbortSignal): Promise<VocabularySearchResponse>;
86
+ export declare const searchVocabularyRequest: (transport: HttpTransport, query: string, options?: VocabularySearchOptions, signal?: AbortSignal) => Promise<VocabularySearchResponse>;
package/resolve-client.js CHANGED
@@ -29,9 +29,8 @@ import { resolveOperation } from "./operations.js";
29
29
  * could have caught comes back unresolved rather than slow.
30
30
  *
31
31
  * Deterministic — the same batch resolves to the same bytes every time. Instead
32
- * use `mg.search()` when you want materials rather than words, `mg.suggest()` to
33
- * complete a name as someone types, and `mg.glossary()` to EXPLAIN a token you
34
- * have already resolved.
32
+ * use `mg.search()` when you want materials rather than words, and
33
+ * `mg.suggest()` to complete a name as someone types.
35
34
  *
36
35
  * - **Every reading says what stands behind it.** `coverage.variants` is how
37
36
  * many variants carry it corpus-wide, and `0` is a measured answer rather
@@ -49,11 +48,11 @@ import { resolveOperation } from "./operations.js";
49
48
  * resolved independently, so one meaningless phrase never spoils the batch.
50
49
  * @param options `category` to scope the coverage answer, and an `AbortSignal`.
51
50
  */
52
- export function resolvePhrasesRequest(transport, phrases, scope) {
51
+ export const resolvePhrasesRequest = async (transport, phrases, scope) => {
53
52
  // A bare signal is what this took before `category` existed; keep accepting it
54
53
  // so no published call site had to change to gain coverage.
55
54
  const options = scope instanceof AbortSignal ? { signal: scope } : (scope ?? {});
56
- return transport.requestJson(resolveOperation("resolve_phrases"), {
55
+ return await transport.requestJson(resolveOperation("resolve_phrases"), {
57
56
  body: {
58
57
  phrases,
59
58
  ...(options.category === undefined
@@ -62,17 +61,14 @@ export function resolvePhrasesRequest(transport, phrases, scope) {
62
61
  },
63
62
  signal: options.signal,
64
63
  });
65
- }
64
+ };
66
65
  /**
67
66
  * THE QUESTION: "is 'FloorScore' an attribute or a value, and what is it called
68
67
  * here?" The catch-all for ONE phrase when you do not know which half of an
69
68
  * `attribute:value` pair it belongs to. Backs `mg.searchVocabulary()`.
70
69
  *
71
- * Instead use `mg.resolveAttribute()` / `mg.resolveAttributeValue()` once you do
72
- * know, {@link resolvePhrasesRequest} when you have SEVERAL phrases or the
73
- * phrase might name a brand, paint, colour or category rather than a spec, and
74
- * `mg.glossary()` to EXPLAIN a term rather than find it.
70
+ * Instead use `mg.listAttributes({ query })` once you do know the attribute,
71
+ * or {@link resolvePhrasesRequest} when you have SEVERAL phrases or the phrase
72
+ * might name a brand, paint, colour or category rather than a spec.
75
73
  */
76
- export function searchVocabularyRequest(transport, query, options, signal) {
77
- return transport.requestJson(resolveOperation("catalog_vocabulary_search"), { query: { q: query, limit: options?.limit, kind: options?.kind }, signal });
78
- }
74
+ export const searchVocabularyRequest = async (transport, query, options, signal) => await transport.requestJson(resolveOperation("catalog_vocabulary_search"), { query: { kind: options?.kind, limit: options?.limit, q: query }, signal });
@@ -8,15 +8,15 @@ import type { CorpusScope } from "./corpus-scope-types.js";
8
8
  import type { VariantId } from "./identifiers.js";
9
9
  import type { OpenEnum } from "./types.js";
10
10
  /** Options for `resolveColour`. */
11
- export interface ResolveColourOptions {
11
+ export type ResolveColourOptions = {
12
12
  /**
13
13
  * Sets `inScope` on each catalogue variant the lookup reports. It never
14
14
  * narrows the lookup. Absent leaves every `inScope` null.
15
15
  */
16
16
  corpusScope?: CorpusScope;
17
- }
17
+ };
18
18
  /** One catalogue variant carrying the named paint. */
19
- export interface ResolveColourCatalogueVariant {
19
+ export type ResolveColourCatalogueVariant = {
20
20
  variantId: VariantId;
21
21
  /** The brand exactly as stored, suspect or not. */
22
22
  brand: {
@@ -32,7 +32,7 @@ export interface ResolveColourCatalogueVariant {
32
32
  * made it. The variant is still the right one for the name.
33
33
  */
34
34
  parentageSuspect: boolean;
35
- }
35
+ };
36
36
  /**
37
37
  * Whether the named paint is a variant in the catalogue. Exact, global, and
38
38
  * never narrowed by `corpusScope`, and run only for a `brand` library hit.
@@ -50,18 +50,18 @@ export type ResolveColourVariant = ({
50
50
  status: "not-looked-up";
51
51
  reason: OpenEnum<"reference-colour" | "descriptive-colour" | "no-paint-identity" | "generic-colour" | "several-paints">;
52
52
  };
53
- export interface ResolveColourResponse {
53
+ export type ResolveColourResponse = {
54
54
  /** Examples within the governed range. They do not replace its representative or bounds. */
55
55
  rangeSamples?: string[];
56
56
  /** Explicit manufacturer choices for an ambiguous paint name. Never selected automatically. */
57
- alternatives?: Array<{
57
+ alternatives?: {
58
58
  query: string;
59
59
  name: string;
60
60
  hex: string;
61
61
  libraryId: string;
62
62
  libraryName: string;
63
63
  code?: string;
64
- }>;
64
+ }[];
65
65
  /** Generic meaning; maker-specific paint identity is carried by match. */
66
66
  genericResolution: ColorResolution;
67
67
  match: {
@@ -80,4 +80,4 @@ export interface ResolveColourResponse {
80
80
  /** The catalogue lookup for the name. Absent from servers that predate it. */
81
81
  variant?: ResolveColourVariant;
82
82
  } | null;
83
- }
83
+ };