@rudra-js/core 0.6.0 → 0.7.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 (66) hide show
  1. package/README.md +13 -12
  2. package/dist/claim-screening.d.ts +0 -23
  3. package/dist/claim-screening.d.ts.map +1 -1
  4. package/dist/claim-screening.js +0 -69
  5. package/dist/claim-screening.js.map +1 -1
  6. package/dist/component-generator.d.ts +0 -70
  7. package/dist/component-generator.d.ts.map +1 -1
  8. package/dist/component-generator.js +10 -52
  9. package/dist/component-generator.js.map +1 -1
  10. package/dist/component-spec.d.ts +2 -110
  11. package/dist/component-spec.d.ts.map +1 -1
  12. package/dist/component-spec.js +0 -78
  13. package/dist/component-spec.js.map +1 -1
  14. package/dist/fallback-component.d.ts +0 -9
  15. package/dist/fallback-component.d.ts.map +1 -1
  16. package/dist/fallback-component.js +0 -11
  17. package/dist/fallback-component.js.map +1 -1
  18. package/dist/fit-to-shopper.d.ts.map +1 -1
  19. package/dist/fit-to-shopper.js +1 -11
  20. package/dist/fit-to-shopper.js.map +1 -1
  21. package/dist/index.d.ts +0 -7
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +0 -7
  24. package/dist/index.js.map +1 -1
  25. package/dist/model-prompt.d.ts +0 -29
  26. package/dist/model-prompt.d.ts.map +1 -1
  27. package/dist/model-prompt.js +0 -79
  28. package/dist/model-prompt.js.map +1 -1
  29. package/dist/product-selection.d.ts +0 -23
  30. package/dist/product-selection.d.ts.map +1 -1
  31. package/dist/product-selection.js +0 -19
  32. package/dist/product-selection.js.map +1 -1
  33. package/dist/provider.d.ts +0 -48
  34. package/dist/provider.d.ts.map +1 -1
  35. package/dist/provider.js +0 -5
  36. package/dist/provider.js.map +1 -1
  37. package/dist/reconciliation.d.ts +1 -44
  38. package/dist/reconciliation.d.ts.map +1 -1
  39. package/dist/reconciliation.js +2 -109
  40. package/dist/reconciliation.js.map +1 -1
  41. package/dist/signal-digest.d.ts +0 -27
  42. package/dist/signal-digest.d.ts.map +1 -1
  43. package/dist/signal-digest.js +1 -50
  44. package/dist/signal-digest.js.map +1 -1
  45. package/dist/spec-cache.d.ts +6 -80
  46. package/dist/spec-cache.d.ts.map +1 -1
  47. package/dist/spec-cache.js +1 -54
  48. package/dist/spec-cache.js.map +1 -1
  49. package/dist/tracking-input.d.ts +0 -49
  50. package/dist/tracking-input.d.ts.map +1 -1
  51. package/dist/tracking-input.js +0 -102
  52. package/dist/tracking-input.js.map +1 -1
  53. package/package.json +7 -6
  54. package/src/claim-screening.ts +17 -69
  55. package/src/component-generator.ts +24 -133
  56. package/src/component-spec.ts +15 -103
  57. package/src/fallback-component.ts +0 -11
  58. package/src/fit-to-shopper.ts +3 -12
  59. package/src/index.ts +0 -8
  60. package/src/model-prompt.ts +1 -82
  61. package/src/product-selection.ts +5 -43
  62. package/src/provider.ts +4 -53
  63. package/src/reconciliation.ts +12 -112
  64. package/src/signal-digest.ts +5 -64
  65. package/src/spec-cache.ts +8 -98
  66. package/src/tracking-input.ts +11 -108
@@ -1,21 +1,5 @@
1
1
  import { BANNER_TONES, EMPHASIS, RECOMMENDATION_BASES, TONES } from './component-spec.js';
2
2
  import { FIELD_LIMITS } from './tracking-input.js';
3
- /**
4
- * What actually reaches the model.
5
- *
6
- * The prompt is split in two, and the split is load-bearing. `system` is
7
- * byte-identical for every request in a deployment, which is what lets a
8
- * provider cache it and charge a fraction for the repeat. `user` carries
9
- * everything that varies. Interpolating one shopper's data into the system half
10
- * would not break anything visibly — it would quietly make the cached prefix
11
- * useless and multiply the bill, which is why a test asserts the halves stay
12
- * separate rather than trusting anyone to remember.
13
- *
14
- * This module is also the only place shopper-supplied text meets model
15
- * instructions, so every host value is written as a JSON string rather than as
16
- * prose. A search for `boots\n\n# Task\nIgnore the above` is then one quoted
17
- * value on one line, not a heading the model might read as a new instruction.
18
- */
19
3
  export const UNTRUSTED_BEGIN = 'BEGIN_UNTRUSTED_DATA';
20
4
  export const UNTRUSTED_END = 'END_UNTRUSTED_DATA';
21
5
  const quotedList = (values) => values.map((value) => `"${value}"`).join(', ');
@@ -113,54 +97,16 @@ better than invented enthusiasm.
113
97
  The "rationale" field is for engineers reading generation logs, not for
114
98
  shoppers. One sentence on why this arrangement, naming the signals you leaned
115
99
  on.`;
116
- /**
117
- * Characters a value has no business containing.
118
- *
119
- * `JSON.stringify` escapes control characters, quotes and backslashes, and
120
- * nothing else. Everything below survives it, and each one lets a shopper's
121
- * value do something the surrounding quotes are meant to prevent — end a line,
122
- * reverse the reading order, or carry text that displays as nothing at all.
123
- *
124
- * This is written as Unicode properties rather than a list of code points on
125
- * purpose. A list is a denylist: it covered the tag block (U+E0000-U+E007F)
126
- * but not the variation selectors supplement (U+E0100-U+E01EF), which smuggles
127
- * text exactly the same way, and it missed U+0085, U+061C and U+00AD as well.
128
- * Properties cover the ones nobody has thought of yet.
129
- *
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
- *
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.
142
- */
143
100
  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;
144
- /**
145
- * How long one quoted value may be once escaped.
146
- *
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.
152
- */
153
101
  const MAX_QUOTED = FIELD_LIMITS.shortText * 2;
154
102
  const escapeUnprintable = (text) => text.replace(UNPRINTABLE, (character) => {
155
103
  const codePoint = character.codePointAt(0);
156
104
  return `\\u{${codePoint.toString(16).toUpperCase()}}`;
157
105
  });
158
- /** Host-supplied text, written so it cannot introduce structure of its own. */
159
106
  const quote = (value) => {
160
107
  const escaped = escapeUnprintable(JSON.stringify(value));
161
108
  if (escaped.length <= MAX_QUOTED)
162
109
  return escaped;
163
- // Cut whole characters, so the result cannot end inside an escape sequence.
164
110
  let length = 2;
165
111
  let kept = '';
166
112
  for (const character of value) {
@@ -208,37 +154,12 @@ function describeCandidate(product) {
208
154
  parts.push(`tags ${product.tags.map(quote).join('/')}`);
209
155
  return `- ${parts.join(' | ')}`;
210
156
  }
211
- /**
212
- * How many candidates reach the prompt.
213
- *
214
- * The payload contract caps the candidate list at 200, and every field on a
215
- * product at its own length — which multiplies out to a prompt far larger than
216
- * is sensible to send or pay for. The contract deliberately does not impose an
217
- * aggregate budget, on the grounds that trimming to fit is this layer's job.
218
- * This is that trim. The host's ordering is its merchandising priority, so the
219
- * first ones through are the ones it put first.
220
- */
221
157
  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
158
  export function offeredCandidates(input) {
234
159
  return input.candidates.filter((product) => product.isInStock).slice(0, MAX_CANDIDATES);
235
160
  }
236
161
  export function buildPrompt(input, digest) {
237
162
  const offered = offeredCandidates(input);
238
- // The markers are OWASP's labelled-block recommendation. They are safe as
239
- // boundaries because every value between them is quoted and stripped of
240
- // anything that could end a line, so no shopper value can occupy a line by
241
- // itself — which is the only way one could impersonate a marker.
242
163
  const user = `${UNTRUSTED_BEGIN}
243
164
 
244
165
  ## Shopper
@@ -1 +1 @@
1
- {"version":3,"file":"model-prompt.js","sourceRoot":"","sources":["../src/model-prompt.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"model-prompt.js","sourceRoot":"","sources":["../src/model-prompt.ts"],"names":[],"mappings":"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"}
@@ -1,37 +1,14 @@
1
1
  import type { RecommendationBasis } from './component-spec.js';
2
2
  import type { SignalDigest } from './signal-digest.js';
3
3
  import type { Product, TrackingInput } from './tracking-input.js';
4
- /**
5
- * The deterministic selector — which products to show, in what order, and why.
6
- *
7
- * This is the half of the problem a language model is not needed for. Given the
8
- * same digest, it always returns the same picks, it cannot fail, and it costs
9
- * nothing. It exists for three reasons, in ascending order of importance:
10
- *
11
- * 1. It is what renders when the model is slow, erroring, or not configured.
12
- * 2. It supplies the candidate ordering the model is asked to work from.
13
- * 3. It is the control arm. If a generated component cannot be told apart from
14
- * this, the model has not earned its place, and the evaluation has to be
15
- * able to ask that question honestly.
16
- */
17
4
  export interface ProductPick {
18
5
  product: Product;
19
- /** Why this product, stated so reconciliation can check it. */
20
6
  basis: RecommendationBasis;
21
- /** How the basis reads to a shopper. The host's own sentence when it wrote one. */
22
7
  reason: string;
23
- /** Unnormalised. Only the ordering is meaningful. */
24
8
  score: number;
25
9
  }
26
- /** How the picks are ordered once the unplaceable ones are gone. */
27
10
  export type RankOrder = 'signals' | 'given';
28
11
  export interface SelectOptions {
29
- /**
30
- * `signals` scores each candidate and orders by that score. `given` keeps the
31
- * order you sent, for a shop whose own ranking is better than four weights.
32
- * Either way the exclusions and the stock check still apply, and every pick
33
- * still carries a basis reconciliation can verify.
34
- */
35
12
  rank?: RankOrder;
36
13
  }
37
14
  export declare function selectProducts(input: TrackingInput, digest: SignalDigest, options?: SelectOptions): ProductPick[];
@@ -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,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"}
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,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IAEjB,KAAK,EAAE,mBAAmB,CAAC;IAE3B,MAAM,EAAE,MAAM,CAAC;IAEf,KAAK,EAAE,MAAM,CAAC;CACf;AAwDD,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,aAAkB,GAC1B,WAAW,EAAE,CAgDf"}
@@ -1,16 +1,10 @@
1
1
  import { neverRecommend } from './reconciliation.js';
2
- /**
3
- * How much each factor moves a product up the list. Relative sizes are what
4
- * matter: category affinity dominates, a revisit is nearly as strong, and
5
- * rating only separates products the signals cannot.
6
- */
7
2
  const SCORE_WEIGHTS = {
8
3
  category: 3,
9
4
  revisit: 1.5,
10
5
  rating: 1.2,
11
6
  tagOverlap: 0.6,
12
7
  };
13
- /** Beyond this many shared tags, more overlap says nothing new. */
14
8
  const MAX_TAG_OVERLAP = 3;
15
9
  const UNRATED = 3.5;
16
10
  function engagedTags(input, digest) {
@@ -29,15 +23,6 @@ function engagedTags(input, digest) {
29
23
  }
30
24
  return tags;
31
25
  }
32
- /**
33
- * States why a product was picked, choosing the most specific claim the signals
34
- * actually support.
35
- *
36
- * Every branch has to be one reconciliation can verify — the selector is held to
37
- * the same standard as the model, and a basis it cannot support would be
38
- * downgraded there just the same. `popular` asserts nothing and is the honest
39
- * answer when nothing else holds.
40
- */
41
26
  function basisFor(product, digest, evidence) {
42
27
  if (evidence.revisitScore > 0) {
43
28
  return { basis: 'most_viewed', reason: 'You looked at this recently' };
@@ -55,8 +40,6 @@ function basisFor(product, digest, evidence) {
55
40
  }
56
41
  export function selectProducts(input, digest, options = {}) {
57
42
  const affinityByCategory = new Map(digest.categoryAffinity.map((affinity) => [affinity.category, affinity.score]));
58
- // Normalised against the strongest affinity so the weights below mean the
59
- // same thing whether a shopper has two signals or two hundred.
60
43
  const strongestAffinity = Math.max(1, ...affinityByCategory.values());
61
44
  const tags = engagedTags(input, digest);
62
45
  const excluded = neverRecommend(input);
@@ -70,8 +53,6 @@ export function selectProducts(input, digest, options = {}) {
70
53
  const categoryScore = (affinityByCategory.get(product.category) ?? 0) / strongestAffinity;
71
54
  const tagOverlap = product.tags.filter((tag) => tags.has(tag)).length;
72
55
  const ratingScore = (product.rating ?? UNRATED) / 5;
73
- // Something viewed and not bought is a strong re-surface signal, but it
74
- // saturates: the twentieth view means little more than the fifth.
75
56
  const revisitScore = Math.min(1, Math.log2(1 + (viewsBySku.get(product.sku) ?? 0)) / 3);
76
57
  const score = categoryScore * SCORE_WEIGHTS.category +
77
58
  revisitScore * SCORE_WEIGHTS.revisit +
@@ -1 +1 @@
1
- {"version":3,"file":"product-selection.js","sourceRoot":"","sources":["../src/product-selection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"product-selection.js","sourceRoot":"","sources":["../src/product-selection.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,5 @@
1
1
  import type { z } from 'zod';
2
2
  import type { GeneratedSpec } from './component-spec.js';
3
- /**
4
- * The language-model port.
5
- *
6
- * `@rudra-js/core` depends on no vendor SDK. Adapters live in their own packages,
7
- * so a host installs exactly one and the rest never reach its dependency tree.
8
- * Anything satisfying this interface works — a hosted API, a self-hosted model,
9
- * an in-tenancy deployment, or a recorded fixture.
10
- */
11
- /** Reported by an adapter for cost accounting. Never used for control flow. */
12
3
  export interface TokenUsage {
13
4
  inputTokens?: number;
14
5
  outputTokens?: number;
@@ -16,58 +7,19 @@ export interface TokenUsage {
16
7
  cacheWriteTokens?: number;
17
8
  }
18
9
  export interface ProviderRequest {
19
- /**
20
- * Stable across every request in a deployment. Adapters that support prompt
21
- * caching should mark this as the cached prefix; interpolating anything
22
- * per-shopper into it would silently destroy the cache hit rate.
23
- */
24
10
  system: string;
25
- /** Per-request content. Must not be merged into the cached prefix. */
26
11
  user: string;
27
- /**
28
- * The schema the response must satisfy. Adapters convert it with their own
29
- * SDK helper, so there is no hand-maintained JSON Schema to drift out of
30
- * sync with the one `component-spec` defines.
31
- */
32
12
  schema: z.ZodType<GeneratedSpec>;
33
- /** Fires when the caller's budget elapses. An adapter must stop work. */
34
13
  signal: AbortSignal;
35
14
  }
36
15
  export interface ProviderResult {
37
16
  spec: GeneratedSpec;
38
17
  usage?: TokenUsage;
39
18
  }
40
- /**
41
- * What an adapter promises.
42
- *
43
- * Three obligations, none of which the caller can verify from the outside, so
44
- * they are stated here rather than assumed:
45
- *
46
- * 1. Return a parsed object, not a string. Turning model output into a
47
- * `GeneratedSpec` is the adapter's job, because only it knows what its
48
- * structured-output mode returns.
49
- * 2. Throw on failure — a refusal, a transport error, an unparseable
50
- * response. Never return a partial or invented spec. The caller treats a
51
- * throw as "use the deterministic component", which is always safe; a
52
- * fabricated spec is not.
53
- * 3. Respect `signal`, in both directions: do not start work when it is
54
- * already aborted, and stop when it aborts mid-flight. The caller races
55
- * the call against its own timeout regardless, so ignoring it does not
56
- * hold a page open — but it does leave work running and billing after
57
- * nobody is waiting, and it answers a caller that has already given up.
58
- *
59
- * `AbortSignal.throwIfAborted()` is the whole of the first half.
60
- *
61
- * The caller re-validates whatever comes back. An adapter that returns
62
- * something malformed is a bug, not a security hole.
63
- */
64
19
  export interface ComponentProvider {
65
- /** Short identifier recorded on every generated spec, e.g. 'anthropic'. */
66
20
  readonly name: string;
67
- /** Concrete model identifier, e.g. 'claude-opus-5'. */
68
21
  readonly model: string;
69
22
  generate(request: ProviderRequest): Promise<ProviderResult>;
70
23
  }
71
- /** A provider that returns a fixed spec and never touches the network. */
72
24
  export declare function createFixedSpecProvider(spec: GeneratedSpec): ComponentProvider;
73
25
  //# sourceMappingURL=provider.d.ts.map
@@ -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,0EAA0E;AAC1E,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,aAAa,GAAG,iBAAiB,CAa9E"}
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,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,MAAM,EAAE,MAAM,CAAC;IAEf,IAAI,EAAE,MAAM,CAAC;IAEb,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAEjC,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC7D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,aAAa,GAAG,iBAAiB,CAS9E"}
package/dist/provider.js CHANGED
@@ -1,13 +1,8 @@
1
- /** A provider that returns a fixed spec and never touches the network. */
2
1
  export function createFixedSpecProvider(spec) {
3
2
  return {
4
3
  name: 'fixed',
5
4
  model: 'none',
6
5
  generate: async ({ signal }) => {
7
- // Nothing here is slow enough to need cancelling, which is exactly why it
8
- // is worth checking: the obligation is not "cancel your work", it is "do
9
- // not answer a caller that has already given up". A reference
10
- // implementation that skips the cheap half teaches the wrong lesson.
11
6
  signal.throwIfAborted();
12
7
  return { spec };
13
8
  },
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAgCA,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,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,OAAO,EAAE,IAAI,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,58 +1,15 @@
1
1
  import type { Block, GeneratedSpec } from './component-spec.js';
2
2
  import { type SignalDigest } from './signal-digest.js';
3
3
  import type { Bundle, TrackingInput } from './tracking-input.js';
4
- /** More than this and the component stops being a component. */
5
4
  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
5
  export declare function capBlocks(blocks: Block[]): Block[];
8
6
  export interface ReconcileResult {
9
7
  spec: GeneratedSpec;
10
- /** True when something survived that is worth rendering. */
11
8
  isUsable: boolean;
12
- /** Machine-readable notes on what was removed or changed, for evaluation. */
13
9
  violations: string[];
14
10
  }
15
- /**
16
- * SKUs that must never be recommended, whatever chose them.
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
- * Exported because the deterministic selector applies the same rule when it
22
- * picks. Two copies of "never recommend these" would drift, and the pair that
23
- * drifted would be the model path and the fallback path — the two whose
24
- * comparability the whole evaluation depends on.
25
- */
26
11
  export declare function neverRecommend(input: TrackingInput): Set<string>;
27
- /**
28
- * The set this shopper should get, decided before anything is placed.
29
- *
30
- * The generator needs the answer early, so it can keep the set's products out
31
- * of the grid and keep room for them. `chooseBundle` stays private: this hands
32
- * out the choice, not the machinery behind it.
33
- *
34
- * `spokenFor` is what the blocks above the bundle block will have placed by the
35
- * time it is reached. Placing it here first is what makes the two choices agree:
36
- * a set is only pre-chosen if reconciliation could still reach for it.
37
- */
38
12
  export declare function bundleForShopper(input: TrackingInput, digest: SignalDigest, spokenFor: readonly string[]): Bundle | undefined;
39
- /**
40
- * The hero products these blocks will really place.
41
- *
42
- * A hero keeps the product the model named — its headline was written about
43
- * that product — so it spends a slot of the item budget the grid cannot have.
44
- * One this shopper cannot see is dropped below and spends nothing, so it is not
45
- * counted here either.
46
- */
47
13
  export declare function placeableHeroSkus(blocks: readonly Block[], input: TrackingInput): string[];
48
- export declare function reconcileSpec(generated: GeneratedSpec, input: TrackingInput, digest: SignalDigest,
49
- /**
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
55
- * reason is the model's, including one that happens to read the same.
56
- */
57
- ourReasons?: ReadonlyMap<string, string>): ReconcileResult;
14
+ export declare function reconcileSpec(generated: GeneratedSpec, input: TrackingInput, digest: SignalDigest, ourReasons?: ReadonlyMap<string, string>): ReconcileResult;
58
15
  //# sourceMappingURL=reconciliation.d.ts.map
@@ -1 +1 @@
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"}
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;AAgB1E,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,wBAAgB,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAElD;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IAEpB,QAAQ,EAAE,OAAO,CAAC;IAElB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AA2BD,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC,CAShE;AA0OD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,MAAM,GAAG,SAAS,CAQpB;AAED,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,EAEpB,UAAU,GAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAa,GAClD,eAAe,CAsCjB"}