@instruments/materialgraph 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/by-spec-types.d.ts +45 -0
- package/catalog-discovery-types.d.ts +30 -14
- package/client.d.ts +4 -1
- package/client.js +7 -2
- package/package.json +1 -1
- package/types.d.ts +37 -0
package/by-spec-types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ValueResolution } from "./catalog-discovery-types.js";
|
|
1
2
|
import type { VariantId } from "./identifiers.js";
|
|
2
3
|
/**
|
|
3
4
|
* One criterion a match satisfied, with the trust behind it.
|
|
@@ -107,6 +108,32 @@ export interface BySpecMatch {
|
|
|
107
108
|
minConfidence: number | null;
|
|
108
109
|
verdict: BySpecVerdict;
|
|
109
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* One criterion the server could not resolve to canonical vocabulary, with the
|
|
113
|
+
* resolver's ranked suggestions for it.
|
|
114
|
+
*
|
|
115
|
+
* `attributeId` and `value` echo the parsed criterion, both of them, so a failed
|
|
116
|
+
* query can be restated without losing either half. (The HTTP route trims the
|
|
117
|
+
* attribute and value around the first `:` before validation.) Which HALF failed
|
|
118
|
+
* is read off `resolution.query`, the token actually resolved:
|
|
119
|
+
*
|
|
120
|
+
* - `resolution.query === attributeId` — the attribute id is unknown, and
|
|
121
|
+
* `resolution.candidates` are ATTRIBUTE ids.
|
|
122
|
+
* - `resolution.query === value` — the attribute is known but its value is no
|
|
123
|
+
* canonical term, and `resolution.candidates` are TERM ids, each carrying the
|
|
124
|
+
* `dictionaryId` it came from.
|
|
125
|
+
*
|
|
126
|
+
* EVERY miss is reported, not just the first, so one round trip is enough to fix
|
|
127
|
+
* a whole spec.
|
|
128
|
+
*/
|
|
129
|
+
export interface BySpecUnresolvedCriterion {
|
|
130
|
+
/** The parsed attribute id, after the route's surrounding-whitespace trim. */
|
|
131
|
+
attributeId: string;
|
|
132
|
+
/** The parsed value — never overwritten by the attribute id when that id is unknown. */
|
|
133
|
+
value: string;
|
|
134
|
+
/** Ranked candidates for whichever half failed. See {@link ValueResolution}. */
|
|
135
|
+
resolution: ValueResolution;
|
|
136
|
+
}
|
|
110
137
|
/**
|
|
111
138
|
* The find-by-spec envelope — A PAGE, AND NOTHING BUT A PAGE.
|
|
112
139
|
*
|
|
@@ -116,6 +143,9 @@ export interface BySpecMatch {
|
|
|
116
143
|
* states NO corpus total, so "N materials meet this specification" is not a
|
|
117
144
|
* claim you can make from one response. Raise `limit`, or say "at least N".
|
|
118
145
|
* `brandsSpanned` is likewise the brand count OF THIS SAMPLE.
|
|
146
|
+
*
|
|
147
|
+
* And check `unresolvedCriteria` BEFORE reading any of that: when it is present
|
|
148
|
+
* the numbers beside it describe a query that never ran.
|
|
119
149
|
*/
|
|
120
150
|
export interface BySpecResponse {
|
|
121
151
|
/** The criteria as parsed — check them before trusting a surprising result. */
|
|
@@ -129,4 +159,19 @@ export interface BySpecResponse {
|
|
|
129
159
|
brandsSpanned: number;
|
|
130
160
|
/** The sample, photo-first, capped by `limit`. */
|
|
131
161
|
matches: BySpecMatch[];
|
|
162
|
+
/**
|
|
163
|
+
* Present ONLY when a criterion failed exact canonical-vocabulary membership —
|
|
164
|
+
* and its presence means THE QUERY WAS NEVER RUN. A pre-flight gate short-circuits
|
|
165
|
+
* before the search, so the rest of the envelope is a placeholder rather than
|
|
166
|
+
* a finding: `matches` is `[]` and `totalMatches` is `0` because nothing was
|
|
167
|
+
* searched, not because nothing qualifies. Reporting that zero as "no material
|
|
168
|
+
* meets this specification" states a fact about the corpus on the strength of
|
|
169
|
+
* a question nobody asked it.
|
|
170
|
+
*
|
|
171
|
+
* Treat these criteria as UNAPPLIED and surface them: retry with a
|
|
172
|
+
* `resolution.candidates` id (subject to `recommendedAction` — `ambiguous`
|
|
173
|
+
* means ask, not pick), or say the value could not be resolved. Absent means
|
|
174
|
+
* every criterion resolved and the query did run.
|
|
175
|
+
*/
|
|
176
|
+
unresolvedCriteria?: BySpecUnresolvedCriterion[];
|
|
132
177
|
}
|
|
@@ -24,6 +24,34 @@ export interface ResolveValueCandidate {
|
|
|
24
24
|
/** Present only for a colour_family candidate resolved via the colorscope fallback. */
|
|
25
25
|
via?: OpenEnum<"colorscope">;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* The resolver's verdict on ONE free-text token — the single shape every
|
|
29
|
+
* resolving surface speaks, so a caller learns to read it once. Returned whole
|
|
30
|
+
* by {@link MaterialGraphClient.resolveAttributeValue}, and carried per bad
|
|
31
|
+
* criterion by `bySpec`'s `unresolvedCriteria`.
|
|
32
|
+
*
|
|
33
|
+
* READ `recommendedAction`, NOT JUST `best`. `ambiguous` with a populated
|
|
34
|
+
* `candidates` list means the phrase genuinely matched several terms — taking
|
|
35
|
+
* `best` silently there is how a query ends up answering a question nobody
|
|
36
|
+
* asked. `unresolved` means no candidate cleared the resolver's confidence
|
|
37
|
+
* threshold (and may still carry weak candidates); it says nothing about how
|
|
38
|
+
* many materials would match a corrected criterion.
|
|
39
|
+
*
|
|
40
|
+
* The resolver ranks, classifies and reports; it never substitutes the nearest
|
|
41
|
+
* token for the one you asked for. `best` is populated whenever ANY candidate
|
|
42
|
+
* exists — including under an `ambiguous` or `unresolved` status — so it is a
|
|
43
|
+
* leader, not a licence.
|
|
44
|
+
*
|
|
45
|
+
* `query` is the trimmed token that was actually resolved, which is how you tell
|
|
46
|
+
* WHICH half of a failed `attribute:value` pair was the problem.
|
|
47
|
+
*/
|
|
48
|
+
export interface ValueResolution {
|
|
49
|
+
status: OpenEnum<"resolved" | "ambiguous" | "unresolved">;
|
|
50
|
+
query: string;
|
|
51
|
+
best: ResolveValueCandidate | null;
|
|
52
|
+
candidates: ResolveValueCandidate[];
|
|
53
|
+
recommendedAction: OpenEnum<"use_best" | "choose_from_candidates" | "ask_user" | "none_found">;
|
|
54
|
+
}
|
|
27
55
|
/** Response from resolving a free-text value against one attribute's dictionary. */
|
|
28
56
|
export interface ResolveAttributeValueResponse {
|
|
29
57
|
attribute: {
|
|
@@ -31,20 +59,8 @@ export interface ResolveAttributeValueResponse {
|
|
|
31
59
|
name: string;
|
|
32
60
|
dictionaryId: string;
|
|
33
61
|
};
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
* `candidates` list means the phrase genuinely matched several terms — taking
|
|
37
|
-
* `best` silently there is how a query ends up answering a question nobody
|
|
38
|
-
* asked. `unresolved` means the vocabulary holds nothing like it, which is not
|
|
39
|
-
* the same as the corpus holding no such materials.
|
|
40
|
-
*/
|
|
41
|
-
resolution: {
|
|
42
|
-
status: OpenEnum<"resolved" | "ambiguous" | "unresolved">;
|
|
43
|
-
query: string;
|
|
44
|
-
best: ResolveValueCandidate | null;
|
|
45
|
-
candidates: ResolveValueCandidate[];
|
|
46
|
-
recommendedAction: OpenEnum<"use_best" | "choose_from_candidates" | "ask_user" | "none_found">;
|
|
47
|
-
};
|
|
62
|
+
/** The verdict on `q`. Read `recommendedAction` — see {@link ValueResolution}. */
|
|
63
|
+
resolution: ValueResolution;
|
|
48
64
|
}
|
|
49
65
|
/** Options for searching registry attributes and value-dictionary terms together. */
|
|
50
66
|
export interface VocabularySearchOptions {
|
package/client.d.ts
CHANGED
|
@@ -333,7 +333,10 @@ export declare class MaterialGraphClient {
|
|
|
333
333
|
* Instead use `search({ filters })` when the spec merely GATES a ranked
|
|
334
334
|
* question, `codes.advisory()` when the real question is what a space demands,
|
|
335
335
|
* and {@link MaterialGraphClient.specificationFacets} first if you do not know
|
|
336
|
-
* the canonical tokens
|
|
336
|
+
* the canonical tokens. Guessing one no longer returns a silently empty
|
|
337
|
+
* answer: an unresolvable criterion means the query NEVER RAN, and the
|
|
338
|
+
* response says so — read {@link BySpecResponse.unresolvedCriteria} before
|
|
339
|
+
* treating an empty `matches` as "nothing qualifies".
|
|
337
340
|
*
|
|
338
341
|
* A PAGE, NOT A CORPUS, unusually so: `totalMatches` is the size of the
|
|
339
342
|
* returned sample under `limit`, not a corpus count. See {@link BySpecResponse}.
|
package/client.js
CHANGED
|
@@ -294,7 +294,9 @@ export class MaterialGraphClient {
|
|
|
294
294
|
* you how much of the rail is real order evidence.
|
|
295
295
|
*/
|
|
296
296
|
pairings(variantId, options, signal) {
|
|
297
|
-
return this.#get("get_material_pairings", {
|
|
297
|
+
return this.#get("get_material_pairings", { ...options }, signal, {
|
|
298
|
+
variantId,
|
|
299
|
+
});
|
|
298
300
|
}
|
|
299
301
|
materials(ids, options, signal) {
|
|
300
302
|
if (ids.length > MAX_BATCH_IDS) {
|
|
@@ -396,7 +398,10 @@ export class MaterialGraphClient {
|
|
|
396
398
|
* Instead use `search({ filters })` when the spec merely GATES a ranked
|
|
397
399
|
* question, `codes.advisory()` when the real question is what a space demands,
|
|
398
400
|
* and {@link MaterialGraphClient.specificationFacets} first if you do not know
|
|
399
|
-
* the canonical tokens
|
|
401
|
+
* the canonical tokens. Guessing one no longer returns a silently empty
|
|
402
|
+
* answer: an unresolvable criterion means the query NEVER RAN, and the
|
|
403
|
+
* response says so — read {@link BySpecResponse.unresolvedCriteria} before
|
|
404
|
+
* treating an empty `matches` as "nothing qualifies".
|
|
400
405
|
*
|
|
401
406
|
* A PAGE, NOT A CORPUS, unusually so: `totalMatches` is the size of the
|
|
402
407
|
* returned sample under `limit`, not a corpus count. See {@link BySpecResponse}.
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -395,6 +395,8 @@ export interface CospecPairing {
|
|
|
395
395
|
liftLabel: string;
|
|
396
396
|
demand: CompanionDemand | null;
|
|
397
397
|
topProjectTypes: ProjectTypeShare[];
|
|
398
|
+
/** Graph-owned colour ranking facts, present only for an explicitly ordered rail. */
|
|
399
|
+
ranking?: PairingRanking;
|
|
398
400
|
}
|
|
399
401
|
/**
|
|
400
402
|
* A pairing item topped up from colour palette-similarity — a LOOK-ALIKE, not
|
|
@@ -405,6 +407,30 @@ export interface CospecPairing {
|
|
|
405
407
|
export interface ColourPairing extends MaterialTile {
|
|
406
408
|
source: "colour";
|
|
407
409
|
score: number;
|
|
410
|
+
/** Graph-owned colour ranking facts, present only for an explicitly ordered rail. */
|
|
411
|
+
ranking?: PairingRanking;
|
|
412
|
+
}
|
|
413
|
+
export type PairingOrderMode = "relevance" | "lightness_asc" | "lightness_desc";
|
|
414
|
+
export type PairingCorpus = "all" | "material_bank";
|
|
415
|
+
export interface PairingRanking {
|
|
416
|
+
anchorColourSimilarity: number | null;
|
|
417
|
+
lightness: number | null;
|
|
418
|
+
anchorColourSimilarityMeasurable: boolean;
|
|
419
|
+
lightnessMeasurable: boolean;
|
|
420
|
+
basis: OpenEnum<"dominant_colour_oklab">;
|
|
421
|
+
}
|
|
422
|
+
export interface PairingOrdering {
|
|
423
|
+
requested: OpenEnum<PairingOrderMode>;
|
|
424
|
+
applied: OpenEnum<PairingOrderMode>;
|
|
425
|
+
direction: OpenEnum<"ascending" | "descending">;
|
|
426
|
+
anchorColourBasis: OpenEnum<"one_minus_oklab_euclidean_distance">;
|
|
427
|
+
colourSpace: OpenEnum<"oklab">;
|
|
428
|
+
lightnessRange: {
|
|
429
|
+
min: 0;
|
|
430
|
+
max: 1;
|
|
431
|
+
};
|
|
432
|
+
missingValues: OpenEnum<"last">;
|
|
433
|
+
tieBreak: OpenEnum<"variantId_asc">;
|
|
408
434
|
}
|
|
409
435
|
/**
|
|
410
436
|
* One pairing, discriminated by `source` into three tiers of very different
|
|
@@ -422,6 +448,10 @@ export interface PairingsResponse {
|
|
|
422
448
|
* check it before presenting the rail as demand evidence.
|
|
423
449
|
*/
|
|
424
450
|
cospecCount: number;
|
|
451
|
+
/** Present only when `order` was requested. Evidence tiers remain independent. */
|
|
452
|
+
ordering?: PairingOrdering;
|
|
453
|
+
/** Opaque continuation bound to the seed, filters, corpus, and order. */
|
|
454
|
+
nextCursor?: Cursor;
|
|
425
455
|
}
|
|
426
456
|
export interface MaterialResponse {
|
|
427
457
|
material: MaterialDetail;
|
|
@@ -665,7 +695,14 @@ export interface MaterialsBatchOptions {
|
|
|
665
695
|
export interface PairingsOptions {
|
|
666
696
|
/** Comma-separated coarse category display names; filters both arms. */
|
|
667
697
|
categories?: string;
|
|
698
|
+
/** Page size, 1–24 inclusive (default 12). The server rejects (400), not clamps, values outside this range. */
|
|
668
699
|
limit?: number;
|
|
700
|
+
/** Graph-owned order applied within fixed cospec → considered → colour tiers. */
|
|
701
|
+
order?: PairingOrderMode;
|
|
702
|
+
/** Optional Material Bank/orderable gate; requires an explicit `order`. */
|
|
703
|
+
corpus?: PairingCorpus;
|
|
704
|
+
/** The previous response's `nextCursor`, passed back verbatim. */
|
|
705
|
+
cursor?: Cursor;
|
|
669
706
|
}
|
|
670
707
|
/** Options for `catalog/attributes/resolve`. */
|
|
671
708
|
export interface ResolveAttributeOptions {
|