@rudra-js/core 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -15
- package/dist/claim-screening.d.ts +33 -0
- package/dist/claim-screening.d.ts.map +1 -0
- package/dist/claim-screening.js +226 -0
- package/dist/claim-screening.js.map +1 -0
- package/dist/component-generator.d.ts.map +1 -1
- package/dist/component-generator.js +33 -98
- package/dist/component-generator.js.map +1 -1
- package/dist/component-spec.d.ts +2 -49
- package/dist/component-spec.d.ts.map +1 -1
- package/dist/component-spec.js +3 -17
- package/dist/component-spec.js.map +1 -1
- package/dist/fallback-component.d.ts +3 -0
- package/dist/fallback-component.d.ts.map +1 -1
- package/dist/fallback-component.js +3 -13
- package/dist/fallback-component.js.map +1 -1
- package/dist/fit-to-shopper.d.ts +5 -1
- package/dist/fit-to-shopper.d.ts.map +1 -1
- package/dist/fit-to-shopper.js +6 -4
- package/dist/fit-to-shopper.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/model-prompt.d.ts +13 -1
- package/dist/model-prompt.d.ts.map +1 -1
- package/dist/model-prompt.js +53 -21
- package/dist/model-prompt.js.map +1 -1
- package/dist/product-selection.d.ts +1 -9
- package/dist/product-selection.d.ts.map +1 -1
- package/dist/product-selection.js +1 -4
- package/dist/product-selection.js.map +1 -1
- package/dist/provider.d.ts +1 -8
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +1 -8
- package/dist/provider.js.map +1 -1
- package/dist/reconciliation.d.ts +15 -12
- package/dist/reconciliation.d.ts.map +1 -1
- package/dist/reconciliation.js +150 -340
- package/dist/reconciliation.js.map +1 -1
- package/dist/signal-digest.d.ts +10 -0
- package/dist/signal-digest.d.ts.map +1 -1
- package/dist/signal-digest.js +38 -28
- package/dist/signal-digest.js.map +1 -1
- package/dist/spec-cache.d.ts +14 -2
- package/dist/spec-cache.d.ts.map +1 -1
- package/dist/spec-cache.js +14 -24
- package/dist/spec-cache.js.map +1 -1
- package/dist/tracking-input.d.ts.map +1 -1
- package/dist/tracking-input.js +15 -13
- package/dist/tracking-input.js.map +1 -1
- package/package.json +4 -2
- package/src/claim-screening.ts +242 -0
- package/src/component-generator.ts +38 -123
- package/src/component-spec.ts +5 -18
- package/src/fallback-component.ts +3 -14
- package/src/fit-to-shopper.ts +11 -4
- package/src/index.ts +1 -0
- package/src/model-prompt.ts +58 -23
- package/src/product-selection.ts +2 -13
- package/src/provider.ts +1 -8
- package/src/reconciliation.ts +178 -359
- package/src/signal-digest.ts +41 -31
- package/src/spec-cache.ts +27 -24
- package/src/tracking-input.ts +16 -13
package/dist/model-prompt.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BANNER_TONES, EMPHASIS, RECOMMENDATION_BASES, TONES } from './component-spec.js';
|
|
2
|
+
import { FIELD_LIMITS } from './tracking-input.js';
|
|
2
3
|
/**
|
|
3
4
|
* What actually reaches the model.
|
|
4
5
|
*
|
|
@@ -126,31 +127,51 @@ on.`;
|
|
|
126
127
|
* text exactly the same way, and it missed U+0085, U+061C and U+00AD as well.
|
|
127
128
|
* Properties cover the ones nobody has thought of yet.
|
|
128
129
|
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* caught by Cn, and is invisible.
|
|
130
|
+
* The general categories alone do not, though. Half of what renders as nothing
|
|
131
|
+
* is a mark or a letter rather than a format character \u2014 the Mongolian free
|
|
132
|
+
* variation selectors, U+034F, the Hangul fillers, and the sixteen variation
|
|
133
|
+
* selectors at U+FE00 \u2014 so `Default_Ignorable_Code_Point` is in the class too.
|
|
134
|
+
* It is the property that means "takes up no room", which is the thing that
|
|
135
|
+
* makes a character able to carry text nobody sees.
|
|
136
136
|
*
|
|
137
|
-
* The zero-width joiner is
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
137
|
+
* Three are left out. The zero-width joiner is a format character, but it is
|
|
138
|
+
* also how a family emoji is spelled, and U+FE0E and U+FE0F are what make a
|
|
139
|
+
* character render as an emoji rather than as text. Escaping those mangles
|
|
140
|
+
* ordinary product titles. The other thirteen selectors at U+FE00 spell
|
|
141
|
+
* nothing and are escaped like the rest.
|
|
141
142
|
*/
|
|
142
|
-
const UNPRINTABLE = /(?!\
|
|
143
|
+
const UNPRINTABLE = /(?!\u{200D}|\u{FE0E}|\u{FE0F})[\p{Cc}\p{Cf}\p{Cn}\p{Co}\p{Zl}\p{Zp}\p{Default_Ignorable_Code_Point}]/gu;
|
|
143
144
|
/**
|
|
144
|
-
*
|
|
145
|
+
* How long one quoted value may be once escaped.
|
|
145
146
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* one
|
|
147
|
+
* The contract caps the string a host may send, and this caps what that string
|
|
148
|
+
* turns into. They are not the same number: an escape writes up to eight
|
|
149
|
+
* characters for one, so a field on its cap can still buy eight times the
|
|
150
|
+
* prompt \u2014 and the bill \u2014 that the cap implies. Ordinary text escapes nothing
|
|
151
|
+
* and never comes near this.
|
|
149
152
|
*/
|
|
150
|
-
const
|
|
153
|
+
const MAX_QUOTED = FIELD_LIMITS.shortText * 2;
|
|
154
|
+
const escapeUnprintable = (text) => text.replace(UNPRINTABLE, (character) => {
|
|
151
155
|
const codePoint = character.codePointAt(0);
|
|
152
156
|
return `\\u{${codePoint.toString(16).toUpperCase()}}`;
|
|
153
157
|
});
|
|
158
|
+
/** Host-supplied text, written so it cannot introduce structure of its own. */
|
|
159
|
+
const quote = (value) => {
|
|
160
|
+
const escaped = escapeUnprintable(JSON.stringify(value));
|
|
161
|
+
if (escaped.length <= MAX_QUOTED)
|
|
162
|
+
return escaped;
|
|
163
|
+
// Cut whole characters, so the result cannot end inside an escape sequence.
|
|
164
|
+
let length = 2;
|
|
165
|
+
let kept = '';
|
|
166
|
+
for (const character of value) {
|
|
167
|
+
const cost = escapeUnprintable(JSON.stringify(character)).length - 2;
|
|
168
|
+
if (length + cost > MAX_QUOTED)
|
|
169
|
+
break;
|
|
170
|
+
length += cost;
|
|
171
|
+
kept += character;
|
|
172
|
+
}
|
|
173
|
+
return escapeUnprintable(JSON.stringify(kept));
|
|
174
|
+
};
|
|
154
175
|
function section(heading, body) {
|
|
155
176
|
if (!body || body.length === 0)
|
|
156
177
|
return null;
|
|
@@ -179,7 +200,6 @@ function describeShopper(digest) {
|
|
|
179
200
|
];
|
|
180
201
|
return lines.filter((line) => line !== null).join('\n');
|
|
181
202
|
}
|
|
182
|
-
/** One candidate per line. Facts the model must not restate are left out. */
|
|
183
203
|
function describeCandidate(product) {
|
|
184
204
|
const parts = [quote(product.sku), quote(product.title), quote(product.category)];
|
|
185
205
|
if (product.rating !== undefined)
|
|
@@ -199,10 +219,22 @@ function describeCandidate(product) {
|
|
|
199
219
|
* first ones through are the ones it put first.
|
|
200
220
|
*/
|
|
201
221
|
const MAX_CANDIDATES = 60;
|
|
222
|
+
/**
|
|
223
|
+
* The candidates the model is actually shown.
|
|
224
|
+
*
|
|
225
|
+
* An out-of-stock product is dropped during reconciliation whatever the model
|
|
226
|
+
* does with it, so offering one only costs the shopper a slot.
|
|
227
|
+
*
|
|
228
|
+
* Exported because reconciliation checks the numerals the model writes against
|
|
229
|
+
* the strings on this list, and a candidate it was never shown cannot be where
|
|
230
|
+
* one came from. Two copies of "what the model saw" would drift, and the pair
|
|
231
|
+
* that drifted would be the prompt and the screen reading it back.
|
|
232
|
+
*/
|
|
233
|
+
export function offeredCandidates(input) {
|
|
234
|
+
return input.candidates.filter((product) => product.isInStock).slice(0, MAX_CANDIDATES);
|
|
235
|
+
}
|
|
202
236
|
export function buildPrompt(input, digest) {
|
|
203
|
-
|
|
204
|
-
// does with it, so offering one only costs the shopper a slot.
|
|
205
|
-
const offered = input.candidates.filter((product) => product.isInStock).slice(0, MAX_CANDIDATES);
|
|
237
|
+
const offered = offeredCandidates(input);
|
|
206
238
|
// The markers are OWASP's labelled-block recommendation. They are safe as
|
|
207
239
|
// boundaries because every value between them is quoted and stripped of
|
|
208
240
|
// anything that could end a line, so no shopper value can occupy a line by
|
package/dist/model-prompt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-prompt.js","sourceRoot":"","sources":["../src/model-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,oBAAoB,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"model-prompt.js","sourceRoot":"","sources":["../src/model-prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,19 +18,11 @@ export interface ProductPick {
|
|
|
18
18
|
product: Product;
|
|
19
19
|
/** Why this product, stated so reconciliation can check it. */
|
|
20
20
|
basis: RecommendationBasis;
|
|
21
|
-
/** How the basis reads to a shopper. */
|
|
21
|
+
/** How the basis reads to a shopper. The host's own sentence when it wrote one. */
|
|
22
22
|
reason: string;
|
|
23
|
-
/** True when `reason` is the host's own sentence from the candidate. */
|
|
24
|
-
reasonFromHost: boolean;
|
|
25
23
|
/** Unnormalised. Only the ordering is meaningful. */
|
|
26
24
|
score: number;
|
|
27
25
|
}
|
|
28
|
-
/**
|
|
29
|
-
* Scores every eligible candidate and returns them best first.
|
|
30
|
-
*
|
|
31
|
-
* Ties break on SKU so the order is total: two runs over the same payload
|
|
32
|
-
* produce the same list, which is what makes the control arm reproducible.
|
|
33
|
-
*/
|
|
34
26
|
/** How the picks are ordered once the unplaceable ones are gone. */
|
|
35
27
|
export type RankOrder = 'signals' | 'given';
|
|
36
28
|
export interface SelectOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-selection.d.ts","sourceRoot":"","sources":["../src/product-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAElE;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,KAAK,EAAE,mBAAmB,CAAC;IAC3B,
|
|
1
|
+
{"version":3,"file":"product-selection.d.ts","sourceRoot":"","sources":["../src/product-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAElE;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,KAAK,EAAE,mBAAmB,CAAC;IAC3B,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;CACf;AAuED,oEAAoE;AACpE,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,aAAkB,GAC1B,WAAW,EAAE,CAkDf"}
|
|
@@ -12,9 +12,7 @@ const SCORE_WEIGHTS = {
|
|
|
12
12
|
};
|
|
13
13
|
/** Beyond this many shared tags, more overlap says nothing new. */
|
|
14
14
|
const MAX_TAG_OVERLAP = 3;
|
|
15
|
-
/** Assumed rating for a product the catalog does not rate. */
|
|
16
15
|
const UNRATED = 3.5;
|
|
17
|
-
/** Tags on the products this shopper has actually engaged with. */
|
|
18
16
|
function engagedTags(input, digest) {
|
|
19
17
|
const engagedSkus = new Set([
|
|
20
18
|
...digest.likedSkus,
|
|
@@ -61,7 +59,7 @@ export function selectProducts(input, digest, options = {}) {
|
|
|
61
59
|
// same thing whether a shopper has two signals or two hundred.
|
|
62
60
|
const strongestAffinity = Math.max(1, ...affinityByCategory.values());
|
|
63
61
|
const tags = engagedTags(input, digest);
|
|
64
|
-
const excluded = neverRecommend(
|
|
62
|
+
const excluded = neverRecommend(input);
|
|
65
63
|
const viewsBySku = new Map(digest.topViewed.map((viewed) => [viewed.sku, viewed.views]));
|
|
66
64
|
const picks = [];
|
|
67
65
|
for (const product of input.candidates) {
|
|
@@ -90,7 +88,6 @@ export function selectProducts(input, digest, options = {}) {
|
|
|
90
88
|
product,
|
|
91
89
|
basis,
|
|
92
90
|
reason: product.reason ?? reason,
|
|
93
|
-
reasonFromHost: product.reason !== undefined,
|
|
94
91
|
score,
|
|
95
92
|
});
|
|
96
93
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-selection.js","sourceRoot":"","sources":["../src/product-selection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"product-selection.js","sourceRoot":"","sources":["../src/product-selection.ts"],"names":[],"mappings":"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"}
|
package/dist/provider.d.ts
CHANGED
|
@@ -68,13 +68,6 @@ export interface ComponentProvider {
|
|
|
68
68
|
readonly model: string;
|
|
69
69
|
generate(request: ProviderRequest): Promise<ProviderResult>;
|
|
70
70
|
}
|
|
71
|
-
/**
|
|
72
|
-
* A provider that returns a fixed spec and never touches the network.
|
|
73
|
-
*
|
|
74
|
-
* This is the benchmark's control: it isolates the cost of the framework from
|
|
75
|
-
* the latency of a model, which is the only way to report what server-side
|
|
76
|
-
* rendering itself costs. It is also what the generator's tests run against,
|
|
77
|
-
* since a test that needs an API key is a test nobody runs.
|
|
78
|
-
*/
|
|
71
|
+
/** A provider that returns a fixed spec and never touches the network. */
|
|
79
72
|
export declare function createFixedSpecProvider(spec: GeneratedSpec): ComponentProvider;
|
|
80
73
|
//# sourceMappingURL=provider.d.ts.map
|
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;GAOG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACjC,yEAAyE;IACzE,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC7D;AAED
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;GAOG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACjC,yEAAyE;IACzE,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC7D;AAED,0EAA0E;AAC1E,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,aAAa,GAAG,iBAAiB,CAa9E"}
|
package/dist/provider.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A provider that returns a fixed spec and never touches the network.
|
|
3
|
-
*
|
|
4
|
-
* This is the benchmark's control: it isolates the cost of the framework from
|
|
5
|
-
* the latency of a model, which is the only way to report what server-side
|
|
6
|
-
* rendering itself costs. It is also what the generator's tests run against,
|
|
7
|
-
* since a test that needs an API key is a test nobody runs.
|
|
8
|
-
*/
|
|
1
|
+
/** A provider that returns a fixed spec and never touches the network. */
|
|
9
2
|
export function createFixedSpecProvider(spec) {
|
|
10
3
|
return {
|
|
11
4
|
name: 'fixed',
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AA4EA
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AA4EA,0EAA0E;AAC1E,MAAM,UAAU,uBAAuB,CAAC,IAAmB;IACzD,OAAO;QACL,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,MAAM;QACb,QAAQ,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YAC7B,0EAA0E;YAC1E,yEAAyE;YACzE,8DAA8D;YAC9D,qEAAqE;YACrE,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/reconciliation.d.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import type { Block, GeneratedSpec } from './component-spec.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type SignalDigest } from './signal-digest.js';
|
|
3
3
|
import type { Bundle, TrackingInput } from './tracking-input.js';
|
|
4
|
-
/**
|
|
5
|
-
* More than this and the component stops being a component.
|
|
6
|
-
*
|
|
7
|
-
* Exported because the fill pass has to read the same blocks this module will:
|
|
8
|
-
* one past the cap never renders, so nothing is worth reserving for it.
|
|
9
|
-
*/
|
|
4
|
+
/** More than this and the component stops being a component. */
|
|
10
5
|
export declare const MAX_BLOCKS = 4;
|
|
6
|
+
/** The fill pass calls this too: one past the cap never renders, so nothing is worth reserving for it. */
|
|
7
|
+
export declare function capBlocks(blocks: Block[]): Block[];
|
|
11
8
|
export interface ReconcileResult {
|
|
12
9
|
spec: GeneratedSpec;
|
|
13
10
|
/** True when something survived that is worth rendering. */
|
|
@@ -18,12 +15,15 @@ export interface ReconcileResult {
|
|
|
18
15
|
/**
|
|
19
16
|
* SKUs that must never be recommended, whatever chose them.
|
|
20
17
|
*
|
|
18
|
+
* Everything above plus what the shopper already has, read from the payload for
|
|
19
|
+
* the same reason: a shopper with nine purchases must not be sold the ninth back.
|
|
20
|
+
*
|
|
21
21
|
* Exported because the deterministic selector applies the same rule when it
|
|
22
22
|
* picks. Two copies of "never recommend these" would drift, and the pair that
|
|
23
23
|
* drifted would be the model path and the fallback path — the two whose
|
|
24
24
|
* comparability the whole evaluation depends on.
|
|
25
25
|
*/
|
|
26
|
-
export declare function neverRecommend(
|
|
26
|
+
export declare function neverRecommend(input: TrackingInput): Set<string>;
|
|
27
27
|
/**
|
|
28
28
|
* The set this shopper should get, decided before anything is placed.
|
|
29
29
|
*
|
|
@@ -44,12 +44,15 @@ export declare function bundleForShopper(input: TrackingInput, digest: SignalDig
|
|
|
44
44
|
* One this shopper cannot see is dropped below and spends nothing, so it is not
|
|
45
45
|
* counted here either.
|
|
46
46
|
*/
|
|
47
|
-
export declare function placeableHeroSkus(blocks: readonly Block[], input: TrackingInput
|
|
47
|
+
export declare function placeableHeroSkus(blocks: readonly Block[], input: TrackingInput): string[];
|
|
48
48
|
export declare function reconcileSpec(generated: GeneratedSpec, input: TrackingInput, digest: SignalDigest,
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
50
|
+
* The reason this request wrote itself, by SKU: the host's own `reason` on a
|
|
51
|
+
* candidate, or the sentence the selector wrote when there was none. Neither is the
|
|
52
|
+
* model's words, and the deterministic component renders the same sentence unscreened.
|
|
53
|
+
*
|
|
54
|
+
* Only `fitToShopper` fills it, so in `per-shopper` mode it is empty and every
|
|
52
55
|
* reason is the model's, including one that happens to read the same.
|
|
53
56
|
*/
|
|
54
|
-
|
|
57
|
+
ourReasons?: ReadonlyMap<string, string>): ReconcileResult;
|
|
55
58
|
//# sourceMappingURL=reconciliation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconciliation.d.ts","sourceRoot":"","sources":["../src/reconciliation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reconciliation.d.ts","sourceRoot":"","sources":["../src/reconciliation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,KAAK,EACL,aAAa,EAGd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAW,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAuB1E,gEAAgE;AAChE,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,0GAA0G;AAC1G,wBAAgB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAElD;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,4DAA4D;IAC5D,QAAQ,EAAE,OAAO,CAAC;IAClB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AA2CD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC,CAShE;AA+QD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,MAAM,GAAG,SAAS,CAQpB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,EAAE,CAa1F;AA8ID,wBAAgB,aAAa,CAC3B,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,YAAY;AACpB;;;;;;;GAOG;AACH,UAAU,GAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAa,GAClD,eAAe,CAuCjB"}
|