@instruments/materialgraph 0.18.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 (55) hide show
  1. package/association-types.d.ts +29 -4
  2. package/browse-types.d.ts +14 -3
  3. package/by-colour-types.d.ts +24 -6
  4. package/by-spec-types.d.ts +4 -0
  5. package/catalogue-client.d.ts +3 -0
  6. package/catalogue-client.js +4 -0
  7. package/catalogue-types.d.ts +3 -1
  8. package/citation-types.d.ts +34 -0
  9. package/citation-types.js +1 -0
  10. package/client-browse.d.ts +1 -0
  11. package/client-browse.js +1 -0
  12. package/client-vocabulary.d.ts +10 -0
  13. package/client-vocabulary.js +32 -0
  14. package/client.d.ts +22 -45
  15. package/client.js +40 -55
  16. package/composition-types.d.ts +6 -0
  17. package/corpus-scope-types.d.ts +1 -1
  18. package/errors.d.ts +1 -1
  19. package/errors.js +2 -0
  20. package/index.d.ts +6 -0
  21. package/json-value-types.d.ts +8 -0
  22. package/json-value-types.js +1 -0
  23. package/match-types.d.ts +3 -0
  24. package/material-resources-client.d.ts +3 -0
  25. package/material-resources-client.js +4 -0
  26. package/material-types.d.ts +24 -0
  27. package/operations.d.ts +1 -1
  28. package/operations.js +37 -0
  29. package/package.json +1 -1
  30. package/palette-search-types.d.ts +16 -2
  31. package/render-assets-types.d.ts +65 -0
  32. package/render-assets-types.js +1 -0
  33. package/run-events.d.ts +13 -0
  34. package/samplize-catalogue-types.d.ts +92 -0
  35. package/samplize-catalogue-types.js +1 -0
  36. package/schedule-reference-types.d.ts +46 -0
  37. package/schedule-reference-types.js +1 -0
  38. package/schedule-references-client.d.ts +14 -0
  39. package/schedule-references-client.js +26 -0
  40. package/schedule-types.d.ts +34 -0
  41. package/search-mood-types.d.ts +6 -0
  42. package/search-mood-types.js +1 -0
  43. package/search-refinement-types.d.ts +5 -0
  44. package/search-request-types.d.ts +5 -0
  45. package/search-response-receipt-types.d.ts +8 -0
  46. package/search-result-validation.js +10 -0
  47. package/slot-pool-types.d.ts +2 -0
  48. package/spec-types.d.ts +6 -1
  49. package/specifications.d.ts +3 -1
  50. package/specifications.js +4 -0
  51. package/substitute-types.d.ts +75 -0
  52. package/substitute-types.js +1 -0
  53. package/taxonomy-coverage-types.d.ts +34 -0
  54. package/taxonomy-coverage-types.js +1 -0
  55. package/types.d.ts +15 -18
@@ -11,6 +11,7 @@
11
11
  * Present them as separate sections, and never describe a pairing as available.
12
12
  */
13
13
  import type { Cursor, VariantId } from "./identifiers.js";
14
+ import type { ProductTypeReceipt } from "./material-types.js";
14
15
  /**
15
16
  * Why an association is believed.
16
17
  *
@@ -42,8 +43,16 @@ export interface DeclaredAssociation {
42
43
  brand: string;
43
44
  product: string;
44
45
  variantName: string | null;
46
+ /** The role played by this endpoint of the declared edge. */
47
+ role: "finish" | "product";
48
+ /** The directed relationship asserted by the manufacturer. */
49
+ relation: "applicable_finish";
50
+ /** Accepted sampleability when known; absent means unknown. */
51
+ sampleable?: boolean;
45
52
  /** Canonical thumbnail; null when the variant has no eligible image. */
46
53
  imageUrl: string | null;
54
+ /** Review receipt; proposed types are never accepted categories. */
55
+ productTypeReceipt: ProductTypeReceipt;
47
56
  declared: DeclaredProvenance;
48
57
  }
49
58
  /**
@@ -77,12 +86,13 @@ export interface AssociatedOptions {
77
86
  */
78
87
  limit?: number;
79
88
  /**
80
- * Orderability scope. `material_bank` returns only associations pointing at a
81
- * variant carrying a Material Bank SKU — the ones a caller can actually
82
- * order. Today every visible variant carries one, so this currently removes
83
- * nothing; it tracks orderability rather than a snapshot of it.
89
+ * Source identity scope. `material_bank` returns associations pointing at a
90
+ * variant carrying a Material Bank SKU. A SKU alone does not establish current
91
+ * sampleability; use `sampleableOnly` for an accepted availability fact.
84
92
  */
85
93
  corpus?: "all" | "material_bank";
94
+ /** Return only associations whose effective sampleability is true. */
95
+ sampleableOnly?: boolean;
86
96
  /**
87
97
  * The previous response's `nextCursor`, passed back verbatim. A cursor is
88
98
  * bound to its subject, direction and corpus — replaying it against a
@@ -134,6 +144,21 @@ export interface ApplicabilitySourceEntry {
134
144
  factRevisions: string[];
135
145
  /** Active facts from this source only. */
136
146
  facts: ApplicabilityFact[];
147
+ /** Source endpoints that could not be resolved during reconciliation. */
148
+ unresolved: UnresolvedApplicabilityEndpoint[];
149
+ }
150
+ export interface UnresolvedApplicabilityEndpoint {
151
+ subjectLocator: string;
152
+ subjectKind: "product" | "variant" | "unknown";
153
+ finishLocator: string;
154
+ finishKind: "variant" | "unknown";
155
+ reason: "subject_unresolved" | "finish_unresolved" | "both_unresolved" | "unsupported_subject_kind";
156
+ declaringBrandId: string | null;
157
+ source: {
158
+ authority: string;
159
+ locator: string;
160
+ revision: string;
161
+ };
137
162
  }
138
163
  /** Source-grained response; sources are never merged or given hidden precedence. */
139
164
  export interface ApplicabilityResponse {
package/browse-types.d.ts CHANGED
@@ -26,6 +26,8 @@ export interface BrowseResultItem {
26
26
  productId: ProductId | null;
27
27
  color: string | null;
28
28
  variantName: string | null;
29
+ /** MaterialGraph record creation time, not a manufacturer release date. */
30
+ recordCreatedAt: string | null;
29
31
  imageUrl: string | null;
30
32
  scalars: {
31
33
  l: number | null;
@@ -165,11 +167,20 @@ export interface BrowseParams {
165
167
  */
166
168
  types?: string;
167
169
  /**
168
- * Comma-separated brand slugs (`farrow-ball`) or display names
169
- * (`Farrow & Ball`), case-insensitive. One brand plus a colour `sort` is that
170
- * brand's fan deck. An unknown brand is a 400 naming it, never an empty page.
170
+ * Comma-separated canonical brand ids, exact slugs (`farrow-ball`), or exact
171
+ * display names (`Farrow & Ball`). Canonical ids and slugs are case-sensitive
172
+ * and opaque; display names are case-insensitive. One brand plus a colour `sort` is that brand's
173
+ * fan deck. An unknown brand is a typed 400 naming it, and an exact display
174
+ * name shared by multiple brands is a typed 400 with the candidates; neither
175
+ * becomes an empty page.
171
176
  */
172
177
  brands?: string;
178
+ /**
179
+ * Positive manufacturer declarations. accepts_finishes includes variants of
180
+ * product-level declarations; it does not assert variant-specific applicability.
181
+ * Absence means no role filter.
182
+ */
183
+ role?: "finish" | "accepts_finishes";
173
184
  /**
174
185
  * Typed attribute filters, in the SAME grammar `search` takes — a term, a
175
186
  * term SET (OR within the entry), a presence check or a numeric range, each
@@ -169,12 +169,17 @@ export interface ByColourResponse {
169
169
  colours: string[];
170
170
  categories?: string[];
171
171
  /**
172
- * Echoed brand filter as resolved SLUGS — what the names you passed
173
- * resolved to. Present only when a brand scope applied.
172
+ * Echoed brand filter as resolved SLUGS — what the canonical ids, slugs,
173
+ * or exact names you passed resolved to. Present only when a brand scope
174
+ * applied.
174
175
  */
175
176
  brands?: string[];
176
177
  /** Echoed `family` filter, normalised. Present only when one was applied. */
177
178
  family?: string;
179
+ /** Applied single-colour containment order. */
180
+ order?: "representative" | "nearest";
181
+ /** Applied maximum OKLab distance to each reported match hex. */
182
+ maxColourDistance?: number;
178
183
  oklab?: OklabTriple;
179
184
  };
180
185
  /** `matches.length` — THIS PAGE. Not a corpus total; this surface states none. */
@@ -186,6 +191,12 @@ export interface ByColourResponse {
186
191
  * what says so in counts rather than adjectives.
187
192
  */
188
193
  familyGate?: ColourFamilyGate;
194
+ /** Applied `maxColourDistance` threshold and its page-bounded drop count. */
195
+ proximityGate?: {
196
+ maxColourDistance: number;
197
+ considered: number;
198
+ dropped: number;
199
+ };
189
200
  /**
190
201
  * Present only when `category` was asked for. It states that variants without
191
202
  * an accepted primary product type were excluded by the hard gate; absence
@@ -230,8 +241,10 @@ export interface ByColourParams {
230
241
  /** HARD category filter — display names or taxonomy ids (repeatable). */
231
242
  category?: string | string[];
232
243
  /**
233
- * HARD brand filter (repeatable) — a brand SLUG (`sherwin-williams`) or its
234
- * display name (`Sherwin-Williams`), case-insensitive.
244
+ * HARD brand filter (repeatable) — a canonical brand id, exact brand SLUG
245
+ * (`sherwin-williams`), or exact display name (`Sherwin-Williams`). Canonical
246
+ * ids and slugs are case-sensitive and opaque; display names are
247
+ * case-insensitive.
235
248
  *
236
249
  * This is how the CROSS-BRAND question is asked: pass one brand's colour as
237
250
  * `hex` and scope to another to get that brand's nearest colours to it. It is
@@ -239,8 +252,9 @@ export interface ByColourParams {
239
252
  * filtering a returned page instead comes back short, because a
240
253
  * nearest-neighbour scan does not know to look further.
241
254
  *
242
- * An unknown brand is a 400 naming it, never an empty page. Omitting it (or
243
- * passing an empty list) searches every brand.
255
+ * An unknown brand is a typed 400 naming it, and an exact display name shared
256
+ * by multiple brands is a typed 400 with the candidates; neither becomes an
257
+ * empty page. Omitting it (or passing an empty list) searches every brand.
244
258
  */
245
259
  brand?: string | string[];
246
260
  /**
@@ -260,6 +274,10 @@ export interface ByColourParams {
260
274
  * drop.
261
275
  */
262
276
  family?: string;
277
+ /** Single-colour order; omitted keeps representative browsing order. */
278
+ order?: "representative" | "nearest";
279
+ /** Maximum OKLab distance to each match's reported hex. Single-colour only. */
280
+ maxColourDistance?: number;
263
281
  /** Narrow retrieval inside the server query; absent means the whole graph. */
264
282
  corpusScope?: CorpusScope;
265
283
  limit?: number;
@@ -1,4 +1,5 @@
1
1
  import type { ValueResolution } from "./catalog-discovery-types.js";
2
+ import type { VerdictCitation } from "./citation-types.js";
2
3
  import type { VariantId } from "./identifiers.js";
3
4
  /**
4
5
  * One criterion a match satisfied, with the trust behind it.
@@ -71,6 +72,7 @@ export interface BySpecVerdictCell {
71
72
  * - `proposed` — the value is awaiting acceptance and is not yet on record.
72
73
  */
73
74
  trustGap: "below_confidence" | "basis_unmet" | "proposed" | null;
75
+ citation?: VerdictCitation;
74
76
  }
75
77
  /**
76
78
  * A match's full report card: every cell, the rolled-up grade, weakest confidence.
@@ -131,6 +133,8 @@ export interface BySpecUnresolvedCriterion {
131
133
  attributeId: string;
132
134
  /** The parsed value — never overwritten by the attribute id when that id is unknown. */
133
135
  value: string;
136
+ /** Why pre-flight declined it; absent on responses captured before classification. */
137
+ reason?: "unknown_attribute_or_term" | "not_a_specification";
134
138
  /** Ranked candidates for whichever half failed. See {@link ValueResolution}. */
135
139
  resolution: ValueResolution;
136
140
  }
@@ -1,10 +1,13 @@
1
1
  import type { CatalogDocumentList, CatalogPageListResult, CatalogProductReferenceReadResult, CatalogueChannelCollectionsResponse, CatalogueCollectionsOptions, CatalogueDocumentAccessResult, CataloguePageRepresentationReadResult, CatalogueReferenceBatchResponse } from "./catalogue-types.js";
2
2
  import type { HttpTransport } from "./http-transport.js";
3
3
  import type { VariantId } from "./identifiers.js";
4
+ import type { SamplizeCatalogueOptions, SamplizeCataloguePage } from "./samplize-catalogue-types.js";
4
5
  /** Catalogue publication operations inherited by the public SDK client. */
5
6
  export declare class CatalogueClient {
6
7
  #private;
7
8
  protected constructor(transport: HttpTransport);
9
+ /** Complete version-pinned Samplize paint corpus; stock never limits eligibility. */
10
+ samplizeCatalogue(options?: SamplizeCatalogueOptions, signal?: AbortSignal): Promise<SamplizeCataloguePage>;
8
11
  /**
9
12
  * Read exact, verified brand-publication page relationships for variants.
10
13
  * Missing evidence stays explicit; this operation never guesses a page from
@@ -5,6 +5,10 @@ export class CatalogueClient {
5
5
  constructor(transport) {
6
6
  this.#transport = transport;
7
7
  }
8
+ /** Complete version-pinned Samplize paint corpus; stock never limits eligibility. */
9
+ samplizeCatalogue(options = {}, signal) {
10
+ return this.#transport.requestJson(resolveOperation("samplize_catalogue_products"), { query: { ...options }, signal });
11
+ }
8
12
  /**
9
13
  * Read exact, verified brand-publication page relationships for variants.
10
14
  * Missing evidence stays explicit; this operation never guesses a page from
@@ -2,6 +2,8 @@
2
2
  export interface CatalogueReference {
3
3
  anchor: {
4
4
  coordinateSpace: "normalized_0_1000";
5
+ /** Page carrying the printed code; defaults to page.documentPage. Do not draw it on another page. */
6
+ documentPage?: number;
5
7
  height: number;
6
8
  kind: "printed_code";
7
9
  width: number;
@@ -53,7 +55,7 @@ export interface CatalogueReference {
53
55
  brandItemCode: string;
54
56
  };
55
57
  status: "verified";
56
- isPrimary: true;
58
+ isPrimary: boolean;
57
59
  }
58
60
  export type CatalogueReferenceResult = {
59
61
  variantId: string;
@@ -0,0 +1,34 @@
1
+ /** Small handle carried by a verdict cell. Resolve it only when evidence is opened. */
2
+ export interface VerdictCitation {
3
+ citationId: string;
4
+ sourceType: string;
5
+ count: number;
6
+ }
7
+ export interface ResolvedVerdictCitation {
8
+ citationId: string;
9
+ sourceType: string;
10
+ source: {
11
+ kind: "source_record" | "source_material" | "source_fact" | "url" | "asset" | "download" | "manual_note" | "agent_output";
12
+ /** Canonical source/fact/asset/download id, a public source URL, or the claim-source handle when no public reference is available. */
13
+ ref: string;
14
+ title?: string;
15
+ url?: string;
16
+ /** Same-origin public asset proxy path when retained bytes are available. */
17
+ publicPath?: string;
18
+ sourceId?: string;
19
+ sourceFactId?: string;
20
+ sourceAssetId?: string;
21
+ sourceDownloadId?: string;
22
+ locator?: {
23
+ page?: number;
24
+ selector?: string;
25
+ xPath?: string;
26
+ imageBox?: {
27
+ x: number;
28
+ y: number;
29
+ width: number;
30
+ height: number;
31
+ };
32
+ };
33
+ };
34
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -52,6 +52,7 @@ export declare function browseQuery(params: BrowseParams): {
52
52
  count: BrowseParams["count"];
53
53
  types: BrowseParams["types"];
54
54
  brands: BrowseParams["brands"];
55
+ role: BrowseParams["role"];
55
56
  filters: string[] | undefined;
56
57
  facetCounts: string | undefined;
57
58
  corpusScope: BrowseParams["corpusScope"];
package/client-browse.js CHANGED
@@ -28,6 +28,7 @@ export function browseQuery(params) {
28
28
  count: params.count,
29
29
  types: params.types,
30
30
  brands: params.brands,
31
+ role: params.role,
31
32
  filters: params.filters?.map((entry) => JSON.stringify(entry)),
32
33
  facetCounts: params.facetCounts?.join(","),
33
34
  corpusScope: params.corpusScope,
@@ -0,0 +1,10 @@
1
+ import { HttpTransport } from "./http-transport.js";
2
+ import type { ColourFacetsResponse, ResolveAttributeOptions, ResolveAttributeResponse, ResolveAttributeValueOptions, ResolveAttributeValueResponse, ResolveColourResponse, SuggestColourResponse, SuggestOptions, SuggestResponse } from "./types.js";
3
+ export declare function colourFacets(transport: HttpTransport, signal?: AbortSignal): Promise<ColourFacetsResponse>;
4
+ export declare function resolveColour(transport: HttpTransport, name: string, signal?: AbortSignal): Promise<ResolveColourResponse>;
5
+ export declare function suggestColour(transport: HttpTransport, q: string, options?: {
6
+ limit?: number;
7
+ }, signal?: AbortSignal): Promise<SuggestColourResponse>;
8
+ export declare function suggest(transport: HttpTransport, q: string, options?: SuggestOptions, signal?: AbortSignal): Promise<SuggestResponse>;
9
+ export declare function resolveAttribute(transport: HttpTransport, q: string, options?: ResolveAttributeOptions, signal?: AbortSignal): Promise<ResolveAttributeResponse>;
10
+ export declare function resolveAttributeValue(transport: HttpTransport, attributeId: string, query: string, options?: ResolveAttributeValueOptions, signal?: AbortSignal): Promise<ResolveAttributeValueResponse>;
@@ -0,0 +1,32 @@
1
+ import { HttpTransport } from "./http-transport.js";
2
+ import { resolveOperation } from "./operations.js";
3
+ import { suggestQuery } from "./suggest-types.js";
4
+ export function colourFacets(transport, signal) {
5
+ return transport.requestJson(resolveOperation("get_colour_facets"), { signal });
6
+ }
7
+ export function resolveColour(transport, name, signal) {
8
+ return transport.requestJson(resolveOperation("resolve_colour_name"), { query: { name }, signal });
9
+ }
10
+ export function suggestColour(transport, q, options, signal) {
11
+ return transport.requestJson(resolveOperation("suggest_colour_names"), { query: { q, limit: options?.limit }, signal });
12
+ }
13
+ export function suggest(transport, q, options, signal) {
14
+ return transport.requestJson(resolveOperation("search_suggest"), { query: suggestQuery(q, options), signal });
15
+ }
16
+ export function resolveAttribute(transport, q, options, signal) {
17
+ return transport.requestJson(resolveOperation("catalog_resolve_attribute"), {
18
+ query: {
19
+ q,
20
+ limit: options?.limit,
21
+ facetableOnly: options?.facetableOnly,
22
+ },
23
+ signal,
24
+ });
25
+ }
26
+ export function resolveAttributeValue(transport, attributeId, query, options, signal) {
27
+ return transport.requestJson(resolveOperation("catalog_resolve_value"), {
28
+ query: { q: query, limit: options?.limit },
29
+ pathParams: { attributeId },
30
+ signal,
31
+ });
32
+ }
package/client.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { CatalogueClient } from "./catalogue-client.js";
2
2
  import type { MaterialGraphClientOptions } from "./client-config.js";
3
3
  import { type RateLimit } from "./errors.js";
4
+ import { ScheduleReferencesClient } from "./schedule-references-client.js";
4
5
  export * from "./client-config.js";
5
6
  import { type BrowseNamespace } from "./client-browse.js";
6
7
  import { type ExplorationNamespace } from "./client-exploration.js";
@@ -11,6 +12,7 @@ export type { SourceMaterialCommentsNamespace } from "./client-source-material-c
11
12
  import type { ApplicabilityOptions, AssociatedOptions } from "./association-types.js";
12
13
  import type { BrandsOptions } from "./brand-types.js";
13
14
  import type { ByColourParams, ByColourResponse } from "./by-colour-types.js";
15
+ import type { ResolvedVerdictCitation } from "./citation-types.js";
14
16
  import { CodesClient } from "./codes-client.js";
15
17
  import type { CodeAdvisoryInput, CodeAdvisoryResponse } from "./codes-types.js";
16
18
  import { ColoursClient } from "./colours-client.js";
@@ -26,6 +28,8 @@ import type { CapabilityManifestResponse, CreatePublicRunRequest, CreatePublicRu
26
28
  import type { FinishScheduleResponse, GetRunScheduleOptions } from "./schedule-types.js";
27
29
  import type { SchemaResource, SchemaResourceResponse } from "./schema-resource-types.js";
28
30
  import type { SlotPoolsRequest, SlotPoolsResponse } from "./slot-pool-types.js";
31
+ import type { FindSubstitutesOptions, FindSubstitutesResponse } from "./substitute-types.js";
32
+ import type { ProductTypeCoverageOptions, ProductTypeStatusCoverage } from "./taxonomy-coverage-types.js";
29
33
  import type { ApplicableSpecsResponse, BrandOptions, BySpecOptions, BySpecResponse, ColourFacetsResponse, CoordinateInput, CoordinateResponse, DemandBatchInput, DemandBatchResponse, DemandParams, DemandResponse, ExtractPaletteInput, ExtractPaletteResponse, GlossaryTermResponse, MaterialResponse, MaterialsBatchDetailResponse, MaterialsBatchGetOptions, MaterialsBatchOptions, MaterialsBatchTileResponse, PairingsOptions, PairingsResponse, ResolveAttributeOptions, ResolveAttributeResponse, ResolveAttributeValueOptions, ResolveAttributeValueResponse, ResolveColourResponse, SearchGetParams, SearchInput, SearchResponse, SiblingsResponse, SpecFacetsDistributionResponse, SpecFacetsListResponse, SuggestColourResponse, SuggestOptions, SuggestResponse, TaxonomyResponse, VocabularySearchOptions, WhoamiResponse } from "./types.js";
30
34
  /**
31
35
  * The MaterialGraph client — every lens on the graph, on one object.
@@ -64,6 +68,7 @@ import type { ApplicableSpecsResponse, BrandOptions, BySpecOptions, BySpecRespon
64
68
  */
65
69
  export declare class MaterialGraphClient extends CatalogueClient {
66
70
  #private;
71
+ readonly scheduleReferences: ScheduleReferencesClient;
67
72
  readonly baseUrl: string;
68
73
  /**
69
74
  * THE QUESTION: "show me everything in this category / this brand, in a plain
@@ -218,6 +223,7 @@ export declare class MaterialGraphClient extends CatalogueClient {
218
223
  siblings(variantId: VariantId, signal?: AbortSignal): Promise<SiblingsResponse>;
219
224
  materialBlocks(variantId: VariantId, signal?: AbortSignal): Promise<import("./material-block-types.js").MaterialBlockProjection>;
220
225
  materialAssets(variantId: VariantId, signal?: AbortSignal): Promise<import("./material-asset-types.js").MaterialAssetProjection>;
226
+ materialRenderAssets(variantId: VariantId, signal?: AbortSignal): Promise<import("./render-assets-types.js").MaterialRenderAssets>;
221
227
  materialDocuments(variantId: VariantId, options?: MaterialDocumentPageOptions, signal?: AbortSignal): Promise<import("./material-asset-types.js").MaterialDocumentPage>;
222
228
  /**
223
229
  * THE QUESTION: "what does the schema DEFINE?" — the governed static registry.
@@ -238,10 +244,12 @@ export declare class MaterialGraphClient extends CatalogueClient {
238
244
  *
239
245
  * READ `item.source` BEFORE PHRASING: the rail mixes three tiers of evidence —
240
246
  * `cospec` (real orders), `considered` (board activity), `colour` (palette
241
- * look-alike). Only `cospec` supports "specified together". `cospecCount` tells
247
+ * look-alike). Only `cospec` supports "sampled together". `cospecCount` tells
242
248
  * you how much of the rail is real order evidence.
243
249
  */
244
250
  pairings(variantId: VariantId, options?: PairingsOptions, signal?: AbortSignal): Promise<PairingsResponse>;
251
+ /** Find bounded, exact-spec substitutes for one opaque variant id. */
252
+ findSubstitutes(variantId: VariantId, options?: FindSubstitutesOptions, signal?: AbortSignal): Promise<FindSubstitutesResponse>;
245
253
  /** "What finishes does the manufacturer declare for THIS product?" — {@link declaredFinishes}. */
246
254
  associatedFinishes(variantId: VariantId, options?: AssociatedOptions, signal?: AbortSignal): Promise<import("./association-types.js").DeclaredAssociationsResponse>;
247
255
  /** "What products does the manufacturer declare THIS finish for?" — {@link declaredProducts}. */
@@ -277,58 +285,19 @@ export declare class MaterialGraphClient extends CatalogueClient {
277
285
  view?: "tile";
278
286
  idKind?: MaterialsBatchGetOptions["idKind"];
279
287
  }, signal?: AbortSignal): Promise<MaterialsBatchTileResponse>;
280
- /**
281
- * THE QUESTION: "what colour WORDS may I use?" — family, mood and undertone
282
- * with live counts. Vocabulary, not values: instead use `colours.profiles()`
283
- * for a category's palette, {@link MaterialGraphClient.byColour} to search by a
284
- * colour, {@link MaterialGraphClient.resolveColour} to turn a NAME into a hex.
285
- */
288
+ /** Vocabulary families and counts; use `colours.profiles()` for a material palette. */
286
289
  colourFacets(signal?: AbortSignal): Promise<ColourFacetsResponse>;
287
- /**
288
- * THE QUESTION: "what hex is 'Hague Blue'?" — the step before
289
- * {@link MaterialGraphClient.byColour} when you hold a name rather than a hex.
290
- * A `null` match means unrecognised, not "no such colour".
291
- */
290
+ /** Resolve a colour name to its canonical hex when recognised. */
292
291
  resolveColour(name: string, signal?: AbortSignal): Promise<ResolveColourResponse>;
293
292
  /** Ranked colour-name typeahead (GET `/api/v1/search/colours/suggest`). */
294
293
  suggestColour(q: string, options?: {
295
294
  limit?: number;
296
295
  }, signal?: AbortSignal): Promise<SuggestColourResponse>;
297
- /**
298
- * THE QUESTION: "what is the user starting to type?" It ranks NAMES, not
299
- * materials — instead use {@link MaterialGraphClient.search} once they commit,
300
- * {@link MaterialGraphClient.suggestColour} for colour names, and
301
- * {@link MaterialGraphClient.searchVocabulary} for attribute/value tokens.
302
- *
303
- * Entity typeahead across products, brands and categories
304
- * (GET `/api/v1/search/suggest`). Built for per-keystroke use: one indexed
305
- * lookup, no embedding call and no model. Every suggestion carries the
306
- * `refId` it resolves to — a product id, a brand slug, or a product-type key
307
- * — so selecting one should navigate to that entity rather than re-running
308
- * `label` as a search.
309
- *
310
- * @example
311
- * const { suggestions } = await client.suggest("carr", { kind: "product" });
312
- */
296
+ /** Entity typeahead. Navigate using the selected `refId`; use `search()` for materials. */
313
297
  suggest(q: string, options?: SuggestOptions, signal?: AbortSignal): Promise<SuggestResponse>;
314
- /**
315
- * THE QUESTION: "the user said 'fire rating' — which canonical attribute is
316
- * that?" Free text in, canonical `attributeId`s out; pair with
317
- * {@link MaterialGraphClient.resolveAttributeValue} for the VALUE, then spend
318
- * the pair on {@link MaterialGraphClient.bySpec} or `search({ filters })`.
319
- * Instead use {@link MaterialGraphClient.specificationFacets} to browse rather
320
- * than resolve.
321
- */
298
+ /** Resolve free text to a canonical attribute id. */
322
299
  resolveAttribute(q: string, options?: ResolveAttributeOptions, signal?: AbortSignal): Promise<ResolveAttributeResponse>;
323
- /**
324
- * THE QUESTION: "the user said 'class A' — what canonical term is that, under
325
- * THIS attribute?" The value half of the pair
326
- * {@link MaterialGraphClient.resolveAttribute} starts. Read
327
- * `resolution.recommendedAction`, not just `best`: `ambiguous` means ask.
328
- *
329
- * @param attributeId Canonical vocabulary, not an opaque id — discover it, do
330
- * not invent it.
331
- */
300
+ /** Resolve a value under a canonical attribute id; inspect `recommendedAction` for ambiguity. */
332
301
  resolveAttributeValue(attributeId: string, query: string, options?: ResolveAttributeValueOptions, signal?: AbortSignal): Promise<ResolveAttributeValueResponse>;
333
302
  /** "Is this phrase an attribute or a value?" — see {@link searchVocabularyRequest}. */
334
303
  searchVocabulary(query: string, options?: VocabularySearchOptions, signal?: AbortSignal): Promise<import("./catalog-discovery-types.js").VocabularySearchResponse>;
@@ -364,6 +333,12 @@ export declare class MaterialGraphClient extends CatalogueClient {
364
333
  * {@link MaterialGraphClient.applicableSpecs}). Discover, never hand-write.
365
334
  */
366
335
  taxonomy(signal?: AbortSignal): Promise<TaxonomyResponse>;
336
+ /**
337
+ * Exact current primary-type status counts by retained source category path.
338
+ * `comparisonThreshold` is a reporting cutoff only: it never promotes a
339
+ * proposal into an accepted category.
340
+ */
341
+ productTypeCoverage(options?: ProductTypeCoverageOptions, signal?: AbortSignal): Promise<ProductTypeStatusCoverage>;
367
342
  /**
368
343
  * THE QUESTION: "what is this key allowed to do?" Check `scopes` before
369
344
  * offering a capability: the write surfaces need `mg:ingest` / `mg:compose`,
@@ -535,6 +510,8 @@ export declare class MaterialGraphClient extends CatalogueClient {
535
510
  * `GET /api/v1/runs/{runId}/schedule.xlsx` with the same bearer key.
536
511
  */
537
512
  runSchedule(runId: RunId, options?: GetRunScheduleOptions): Promise<FinishScheduleResponse>;
513
+ /** Follow a verdict cell's citation handle to its canonical claim source. */
514
+ citation(citationId: string, signal?: AbortSignal): Promise<ResolvedVerdictCitation>;
538
515
  /**
539
516
  * Resume a suspended Run (POST `/api/v1/runs/{runId}/resume`).
540
517
  *