@contentrain/decide 0.2.44 → 0.2.46

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 CHANGED
@@ -139,7 +139,11 @@ The key is read from `ANTHROPIC_API_KEY` at the moment of each request, on the
139
139
  same terms as Jev's token: never stored, logged or put in an error message.
140
140
  Requests go only to `https://api.anthropic.com/v1/messages`. Haiku gets the
141
141
  same shaped state and questions as Jev, as a prompt, and answers through one
142
- forced tool call, so the answer is a structured record, not parsed prose.
142
+ forced tool call at temperature 0, so the answer is a structured record, not
143
+ parsed prose. A Claude 4.7 or later model (`model` option) takes neither a
144
+ non-default temperature nor, on Opus and Sonnet 5.5, a forced tool call; it is
145
+ asked through structured outputs, with the same prompt and an equivalent JSON
146
+ schema.
143
147
  `punch_item` sends the prompt AO-9 measured, word for word; other kinds get a
144
148
  generic prompt built from their questions.
145
149
 
package/dist/index.d.mts CHANGED
@@ -393,7 +393,7 @@ interface AnthropicProviderOptions {
393
393
  fetch?: typeof globalThis.fetch;
394
394
  /** Per request. Default 60s. */
395
395
  timeoutMs?: number;
396
- /** Default `claude-haiku-4-5-20251001`, asked at temperature 0. */
396
+ /** Default `claude-haiku-4-5-20251001`, asked at temperature 0. A Claude 4.7 or later model is asked through structured outputs. */
397
397
  model?: string;
398
398
  }
399
399
  declare class AnthropicError extends Error {
@@ -412,8 +412,70 @@ declare function genericLlmPrompt({
412
412
  questions: Questions;
413
413
  count: number;
414
414
  }): string;
415
+ /**
416
+ * Whether a model takes the original request: `temperature: 0` and a forced tool call. Claude 4.7 and later models
417
+ * answer a non-default `temperature` with HTTP 400, and Opus and Sonnet 5.5 a forced tool call, so they are asked
418
+ * through structured outputs instead. An id this does not recognise is asked the current way.
419
+ */
420
+ declare function takesForcedTool(model: string): boolean;
415
421
  /** The Messages API body one batch sends. */
416
422
  declare function buildAnthropicRequest(spec: KindSpec<any, any>, shaped: readonly unknown[], model?: string): {
423
+ model: string;
424
+ max_tokens: number;
425
+ output_config: {
426
+ format: {
427
+ type: "json_schema";
428
+ schema: {
429
+ additionalProperties?: undefined;
430
+ type: string;
431
+ properties: {
432
+ items: {
433
+ type: string;
434
+ items: {
435
+ additionalProperties?: undefined;
436
+ type: string;
437
+ properties: Record<string, unknown>;
438
+ required: string[];
439
+ } | {
440
+ additionalProperties: boolean;
441
+ type: string;
442
+ properties: Record<string, unknown>;
443
+ required: string[];
444
+ };
445
+ };
446
+ };
447
+ required: string[];
448
+ } | {
449
+ additionalProperties: boolean;
450
+ type: string;
451
+ properties: {
452
+ items: {
453
+ type: string;
454
+ items: {
455
+ additionalProperties?: undefined;
456
+ type: string;
457
+ properties: Record<string, unknown>;
458
+ required: string[];
459
+ } | {
460
+ additionalProperties: boolean;
461
+ type: string;
462
+ properties: Record<string, unknown>;
463
+ required: string[];
464
+ };
465
+ };
466
+ };
467
+ required: string[];
468
+ };
469
+ };
470
+ };
471
+ messages: {
472
+ role: "user";
473
+ content: string;
474
+ }[];
475
+ temperature?: undefined;
476
+ tools?: undefined;
477
+ tool_choice?: undefined;
478
+ } | {
417
479
  model: string;
418
480
  max_tokens: number;
419
481
  temperature: number;
@@ -421,11 +483,38 @@ declare function buildAnthropicRequest(spec: KindSpec<any, any>, shaped: readonl
421
483
  name: string;
422
484
  description: string;
423
485
  input_schema: {
486
+ additionalProperties?: undefined;
424
487
  type: string;
425
488
  properties: {
426
489
  items: {
427
490
  type: string;
428
491
  items: {
492
+ additionalProperties?: undefined;
493
+ type: string;
494
+ properties: Record<string, unknown>;
495
+ required: string[];
496
+ } | {
497
+ additionalProperties: boolean;
498
+ type: string;
499
+ properties: Record<string, unknown>;
500
+ required: string[];
501
+ };
502
+ };
503
+ };
504
+ required: string[];
505
+ } | {
506
+ additionalProperties: boolean;
507
+ type: string;
508
+ properties: {
509
+ items: {
510
+ type: string;
511
+ items: {
512
+ additionalProperties?: undefined;
513
+ type: string;
514
+ properties: Record<string, unknown>;
515
+ required: string[];
516
+ } | {
517
+ additionalProperties: boolean;
429
518
  type: string;
430
519
  properties: Record<string, unknown>;
431
520
  required: string[];
@@ -436,13 +525,14 @@ declare function buildAnthropicRequest(spec: KindSpec<any, any>, shaped: readonl
436
525
  };
437
526
  }[];
438
527
  tool_choice: {
439
- type: string;
528
+ type: "tool";
440
529
  name: string;
441
530
  };
442
531
  messages: {
443
- role: string;
532
+ role: "user";
444
533
  content: string;
445
534
  }[];
535
+ output_config?: undefined;
446
536
  };
447
537
  /** Hash of the LLM request shape (model, prompt, tool), recorded by a calibration of this provider. */
448
538
  declare function anthropicRequestShapeHash(spec: KindSpec<any, any>, model?: string): string;
@@ -663,5 +753,5 @@ declare function stableChoices(runs: ReadonlyArray<readonly Decision[]>): {
663
753
  total: number;
664
754
  };
665
755
  //#endregion
666
- export { ANTHROPIC_ENDPOINT, ANTHROPIC_KEY_ENV, AnthropicError, type AnthropicProviderOptions, type AuditRecord, type AuditSink, BUILTIN_KINDS, type BatchLimits, type CachedDecision, CircuitBreaker, type CircuitBreakerOptions, DEFAULT_ANTHROPIC_MODEL, DEFAULT_BATCH, DEFAULT_JEV_MODEL, type DecideOptions, type Decider, type DeciderConfig, type Decision, type DecisionBudget, type DecisionCache, type DecisionProvider, type DecisionSource, ELIGIBILITY_CHOICES, type EligibilityBandInput, type EligibilityBandShaped, type EligibilityChoice, FIELD_TYPE_CHOICES, type FallbackReason, type FieldTypeChoice, type FieldTypeInput, type FieldTypeShaped, JEV_ENDPOINT, JEV_TOKEN_ENV, type JevAnswer, JevError, type JevProviderOptions, type JevQuestion, type JevSpec, JsonlAuditLog, JsonlDecisionCache, type KindSpec, MemoryAuditLog, MemoryDailyBudget, MemoryDecisionCache, NEEDS_HUMAN, type Outcome, PUNCH_CLASSES, PUNCH_CLASS_CRITERIA, PUNCH_SEVERITY_CRITERIA, type Pricing, type ProviderAnswer, type PunchCalibration, type PunchClass, type PunchItemInput, type PunchItemShaped, type PunchLabel, REGION_CHOICES, type RecordedCase, type RegionChoice, type RegionInput, type RegionShaped, type RuleVerdict, type TokenCost, UNMAPPED_CHOICES, type UnmappedChoice, type UnmappedInput, type UnmappedShaped, anthropicRequestShapeHash, buildAnthropicRequest, buildJevRequest, cacheKey, createAnthropicProvider, createDecider, createJevProvider, createReplayFetch, decide, eligibilityBand, eligibilityRule, estimateTokens, fieldType, fieldTypeRule, genericLlmPrompt, measurePunchCalibration, noopLlmProvider, planBatches, punchItem, punchItemRule, readAnthropicResponse, readJevResponse, regionName, regionRule, requestShapeHash, scrubSlug, scrubText, severityLevel, shapeEligibility, shapeFieldType, shapePunchItem, shapeRegion, shapeUnmapped, stableChoices, toAuditRecord, unmappedElement, unmappedRule };
756
+ export { ANTHROPIC_ENDPOINT, ANTHROPIC_KEY_ENV, AnthropicError, type AnthropicProviderOptions, type AuditRecord, type AuditSink, BUILTIN_KINDS, type BatchLimits, type CachedDecision, CircuitBreaker, type CircuitBreakerOptions, DEFAULT_ANTHROPIC_MODEL, DEFAULT_BATCH, DEFAULT_JEV_MODEL, type DecideOptions, type Decider, type DeciderConfig, type Decision, type DecisionBudget, type DecisionCache, type DecisionProvider, type DecisionSource, ELIGIBILITY_CHOICES, type EligibilityBandInput, type EligibilityBandShaped, type EligibilityChoice, FIELD_TYPE_CHOICES, type FallbackReason, type FieldTypeChoice, type FieldTypeInput, type FieldTypeShaped, JEV_ENDPOINT, JEV_TOKEN_ENV, type JevAnswer, JevError, type JevProviderOptions, type JevQuestion, type JevSpec, JsonlAuditLog, JsonlDecisionCache, type KindSpec, MemoryAuditLog, MemoryDailyBudget, MemoryDecisionCache, NEEDS_HUMAN, type Outcome, PUNCH_CLASSES, PUNCH_CLASS_CRITERIA, PUNCH_SEVERITY_CRITERIA, type Pricing, type ProviderAnswer, type PunchCalibration, type PunchClass, type PunchItemInput, type PunchItemShaped, type PunchLabel, REGION_CHOICES, type RecordedCase, type RegionChoice, type RegionInput, type RegionShaped, type RuleVerdict, type TokenCost, UNMAPPED_CHOICES, type UnmappedChoice, type UnmappedInput, type UnmappedShaped, anthropicRequestShapeHash, buildAnthropicRequest, buildJevRequest, cacheKey, createAnthropicProvider, createDecider, createJevProvider, createReplayFetch, decide, eligibilityBand, eligibilityRule, estimateTokens, fieldType, fieldTypeRule, genericLlmPrompt, measurePunchCalibration, noopLlmProvider, planBatches, punchItem, punchItemRule, readAnthropicResponse, readJevResponse, regionName, regionRule, requestShapeHash, scrubSlug, scrubText, severityLevel, shapeEligibility, shapeFieldType, shapePunchItem, shapeRegion, shapeUnmapped, stableChoices, takesForcedTool, toAuditRecord, unmappedElement, unmappedRule };
667
757
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/audit.ts","../src/batch.ts","../src/budget.ts","../src/cache.ts","../src/decide.ts","../src/jev.ts","../src/llm.ts","../src/anthropic.ts","../src/kinds/index.ts","../src/kinds/punch-item.ts","../src/kinds/eligibility-band.ts","../src/kinds/facts.ts","../src/kinds/shape.ts","../src/calibration.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/audit.ts","../src/batch.ts","../src/budget.ts","../src/cache.ts","../src/decide.ts","../src/jev.ts","../src/llm.ts","../src/anthropic.ts","../src/kinds/index.ts","../src/kinds/punch-item.ts","../src/kinds/eligibility-band.ts","../src/kinds/facts.ts","../src/kinds/shape.ts","../src/calibration.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1219,36 +1219,62 @@ function genericLlmPrompt({ state, questions, count }) {
1219
1219
  lines.push("", `Give all ${count} items through the ${TOOL_NAME} tool, one record per item.`);
1220
1220
  return lines.join("\n");
1221
1221
  }
1222
- /** The forced tool the model answers through: one record per item, one field per question. */
1223
- function answerTool(questions) {
1222
+ /**
1223
+ * Whether a model takes the original request: `temperature: 0` and a forced tool call. Claude 4.7 and later models
1224
+ * answer a non-default `temperature` with HTTP 400, and Opus and Sonnet 5.5 a forced tool call, so they are asked
1225
+ * through structured outputs instead. An id this does not recognise is asked the current way.
1226
+ */
1227
+ function takesForcedTool(model) {
1228
+ if (/^claude-\d-\d-/.test(model)) return true;
1229
+ const version = /^claude-(?:opus|sonnet|haiku)-(\d+)(?:-(\d{1,2}))?(?:-\d{8})?$/.exec(model);
1230
+ if (!version) return false;
1231
+ const [major, minor] = [Number(version[1]), Number(version[2] ?? 0)];
1232
+ return major < 4 || major === 4 && minor < 7;
1233
+ }
1234
+ /**
1235
+ * One record per item, one field per question. `bounds: false` leaves out the numeric bounds, which a structured-output
1236
+ * schema does not take; `readField` checks every value either way.
1237
+ */
1238
+ function answerSchema(questions, bounds = true) {
1224
1239
  const properties = { item: { type: "integer" } };
1225
1240
  for (const [suffix, question] of Object.entries(questions)) properties[suffix] = question.type === "choice" ? {
1226
1241
  type: "string",
1227
1242
  enum: Object.keys(question.criteria)
1228
1243
  } : question.type === "score" ? {
1229
1244
  type: "integer",
1230
- minimum: 0,
1231
- maximum: question.criteria.length - 1
1245
+ ...bounds ? {
1246
+ minimum: 0,
1247
+ maximum: question.criteria.length - 1
1248
+ } : {}
1232
1249
  } : {
1233
1250
  type: "number",
1234
- minimum: 0,
1235
- maximum: 1
1251
+ ...bounds ? {
1252
+ minimum: 0,
1253
+ maximum: 1
1254
+ } : {}
1236
1255
  };
1256
+ const strict = bounds ? {} : { additionalProperties: false };
1257
+ return {
1258
+ type: "object",
1259
+ properties: { items: {
1260
+ type: "array",
1261
+ items: {
1262
+ type: "object",
1263
+ properties,
1264
+ required: Object.keys(properties),
1265
+ ...strict
1266
+ }
1267
+ } },
1268
+ required: ["items"],
1269
+ ...strict
1270
+ };
1271
+ }
1272
+ /** The forced tool the model answers through. */
1273
+ function answerTool(questions) {
1237
1274
  return {
1238
1275
  name: TOOL_NAME,
1239
1276
  description: "Record the answers for every item.",
1240
- input_schema: {
1241
- type: "object",
1242
- properties: { items: {
1243
- type: "array",
1244
- items: {
1245
- type: "object",
1246
- properties,
1247
- required: Object.keys(properties)
1248
- }
1249
- } },
1250
- required: ["items"]
1251
- }
1277
+ input_schema: answerSchema(questions)
1252
1278
  };
1253
1279
  }
1254
1280
  /** The Messages API body one batch sends. */
@@ -1257,11 +1283,23 @@ function buildAnthropicRequest(spec, shaped, model = DEFAULT_ANTHROPIC_MODEL) {
1257
1283
  if (!jev) throw new TypeError(`kind ${spec.kind} has no prompt`);
1258
1284
  const { state } = buildJevRequest(spec, shaped);
1259
1285
  const questions = jev.questions("item1");
1260
- const prompt = (jev.llmPrompt ?? genericLlmPrompt)({
1261
- state,
1262
- questions,
1263
- count: shaped.length
1264
- });
1286
+ const messages = [{
1287
+ role: "user",
1288
+ content: (jev.llmPrompt ?? genericLlmPrompt)({
1289
+ state,
1290
+ questions,
1291
+ count: shaped.length
1292
+ })
1293
+ }];
1294
+ if (!takesForcedTool(model)) return {
1295
+ model,
1296
+ max_tokens: MAX_TOKENS,
1297
+ output_config: { format: {
1298
+ type: "json_schema",
1299
+ schema: answerSchema(questions, false)
1300
+ } },
1301
+ messages
1302
+ };
1265
1303
  return {
1266
1304
  model,
1267
1305
  max_tokens: MAX_TOKENS,
@@ -1271,10 +1309,7 @@ function buildAnthropicRequest(spec, shaped, model = DEFAULT_ANTHROPIC_MODEL) {
1271
1309
  type: "tool",
1272
1310
  name: TOOL_NAME
1273
1311
  },
1274
- messages: [{
1275
- role: "user",
1276
- content: prompt
1277
- }]
1312
+ messages
1278
1313
  };
1279
1314
  }
1280
1315
  /** Hash of the LLM request shape (model, prompt, tool), recorded by a calibration of this provider. */
@@ -1330,8 +1365,10 @@ function readAnthropicResponse(spec, count, body) {
1330
1365
  const jev = spec.jev;
1331
1366
  const questions = jev.questions("item1");
1332
1367
  const root = body && typeof body === "object" ? body : {};
1333
- const call = (Array.isArray(root.content) ? root.content : []).find((block) => block?.type === "tool_use" && block.name === TOOL_NAME);
1334
- const input = call?.input && typeof call.input === "object" ? call.input : {};
1368
+ const content = Array.isArray(root.content) ? root.content : [];
1369
+ const call = content.find((block) => block?.type === "tool_use" && block.name === TOOL_NAME);
1370
+ const given = call ? call.input : structuredAnswer(content);
1371
+ const input = given && typeof given === "object" ? given : {};
1335
1372
  const records = Array.isArray(input.items) ? input.items : [];
1336
1373
  const outcomes = [];
1337
1374
  for (let i = 1; i <= count; i++) {
@@ -1355,6 +1392,17 @@ function readAnthropicResponse(spec, count, body) {
1355
1392
  ...typeof root.model === "string" ? { model: root.model } : {}
1356
1393
  };
1357
1394
  }
1395
+ /** A structured-output answer: the JSON of the text block. Not JSON, or not an object: no answer. */
1396
+ function structuredAnswer(content) {
1397
+ const text = content.find((block) => block?.type === "text" && typeof block.text === "string")?.text;
1398
+ if (!text) return void 0;
1399
+ try {
1400
+ const value = JSON.parse(text);
1401
+ return value && typeof value === "object" ? value : void 0;
1402
+ } catch {
1403
+ return;
1404
+ }
1405
+ }
1358
1406
  function readField(question, value) {
1359
1407
  if (question.type === "choice") return typeof value === "string" && Object.hasOwn(question.criteria, value) ? {
1360
1408
  type: "choice",
@@ -1472,6 +1520,6 @@ function stableChoices(runs) {
1472
1520
  };
1473
1521
  }
1474
1522
  //#endregion
1475
- export { ANTHROPIC_ENDPOINT, ANTHROPIC_KEY_ENV, AnthropicError, BUILTIN_KINDS, CircuitBreaker, DEFAULT_ANTHROPIC_MODEL, DEFAULT_BATCH, DEFAULT_JEV_MODEL, ELIGIBILITY_CHOICES, FIELD_TYPE_CHOICES, JEV_ENDPOINT, JEV_TOKEN_ENV, JevError, JsonlAuditLog, JsonlDecisionCache, MemoryAuditLog, MemoryDailyBudget, MemoryDecisionCache, NEEDS_HUMAN, PUNCH_CLASSES, PUNCH_CLASS_CRITERIA, PUNCH_SEVERITY_CRITERIA, REGION_CHOICES, UNMAPPED_CHOICES, anthropicRequestShapeHash, buildAnthropicRequest, buildJevRequest, cacheKey, createAnthropicProvider, createDecider, createJevProvider, createReplayFetch, decide, eligibilityBand, eligibilityRule, estimateTokens, fieldType, fieldTypeRule, genericLlmPrompt, measurePunchCalibration, noopLlmProvider, planBatches, punchItem, punchItemRule, readAnthropicResponse, readJevResponse, regionName, regionRule, requestShapeHash, scrubSlug, scrubText, severityLevel, shapeEligibility, shapeFieldType, shapePunchItem, shapeRegion, shapeUnmapped, stableChoices, toAuditRecord, unmappedElement, unmappedRule };
1523
+ export { ANTHROPIC_ENDPOINT, ANTHROPIC_KEY_ENV, AnthropicError, BUILTIN_KINDS, CircuitBreaker, DEFAULT_ANTHROPIC_MODEL, DEFAULT_BATCH, DEFAULT_JEV_MODEL, ELIGIBILITY_CHOICES, FIELD_TYPE_CHOICES, JEV_ENDPOINT, JEV_TOKEN_ENV, JevError, JsonlAuditLog, JsonlDecisionCache, MemoryAuditLog, MemoryDailyBudget, MemoryDecisionCache, NEEDS_HUMAN, PUNCH_CLASSES, PUNCH_CLASS_CRITERIA, PUNCH_SEVERITY_CRITERIA, REGION_CHOICES, UNMAPPED_CHOICES, anthropicRequestShapeHash, buildAnthropicRequest, buildJevRequest, cacheKey, createAnthropicProvider, createDecider, createJevProvider, createReplayFetch, decide, eligibilityBand, eligibilityRule, estimateTokens, fieldType, fieldTypeRule, genericLlmPrompt, measurePunchCalibration, noopLlmProvider, planBatches, punchItem, punchItemRule, readAnthropicResponse, readJevResponse, regionName, regionRule, requestShapeHash, scrubSlug, scrubText, severityLevel, shapeEligibility, shapeFieldType, shapePunchItem, shapeRegion, shapeUnmapped, stableChoices, takesForcedTool, toAuditRecord, unmappedElement, unmappedRule };
1476
1524
 
1477
1525
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["redact","certain","tentative"],"sources":["../src/audit.ts","../src/batch.ts","../src/budget.ts","../src/cache.ts","../src/jev.ts","../src/kinds/shape.ts","../src/kinds/eligibility-band.ts","../src/kinds/facts.ts","../src/kinds/punch-item.ts","../src/kinds/index.ts","../src/llm.ts","../src/decide.ts","../src/anthropic.ts","../src/calibration.ts"],"sourcesContent":["// ─── Audit log ───\n//\n// One record per decision, whatever answered it: `decisions.jsonl`. It keeps\n// the input's hash and never the input, so the log can be kept and shared\n// without carrying what was decided about.\n\nimport { appendFile, mkdir } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport type { Decision, DecisionSource, FallbackReason } from './types.js'\n\nexport interface AuditRecord {\n /** ISO time the decision was made. */\n at: string\n tenant: string\n kind: string\n version: string\n /** The input hash — the same value as the cache key. */\n key: string\n /** The provider request shape the decision was keyed under. */\n shape: string\n choice?: string\n score?: number\n confidence: number\n source: DecisionSource\n proposed?: string\n unreviewed?: true\n fallback?: FallbackReason\n ms: number\n model?: string\n input_tokens?: number\n output_tokens?: number\n usd?: number\n}\n\nexport interface AuditSink {\n write: (records: readonly AuditRecord[]) => Promise<void>\n}\n\nexport function toAuditRecord(decision: Decision, at: string, tenant: string): AuditRecord {\n const record: AuditRecord = {\n at,\n tenant,\n kind: decision.kind,\n version: decision.version,\n key: decision.key,\n shape: decision.shape,\n confidence: decision.confidence,\n source: decision.source,\n ms: decision.ms,\n }\n if (decision.choice !== undefined) record.choice = decision.choice\n if (decision.score !== undefined) record.score = decision.score\n if (decision.proposed !== undefined) record.proposed = decision.proposed\n if (decision.unreviewed) record.unreviewed = true\n if (decision.fallback) record.fallback = decision.fallback\n if (decision.model) record.model = decision.model\n if (decision.cost) {\n record.input_tokens = decision.cost.input_tokens\n record.output_tokens = decision.cost.output_tokens\n if (decision.cost.usd !== undefined) record.usd = decision.cost.usd\n }\n return record\n}\n\nexport class MemoryAuditLog implements AuditSink {\n readonly records: AuditRecord[] = []\n\n async write(records: readonly AuditRecord[]): Promise<void> {\n this.records.push(...records)\n }\n}\n\n/** Appends to a JSONL file (conventionally `decisions.jsonl`), one line per decision. */\nexport class JsonlAuditLog implements AuditSink {\n constructor(readonly path: string) {}\n\n async write(records: readonly AuditRecord[]): Promise<void> {\n if (!records.length) return\n await mkdir(dirname(this.path), { recursive: true })\n await appendFile(this.path, records.map(record => `${JSON.stringify(record)}\\n`).join(''))\n }\n}\n","// ─── Batching ───\n//\n// Items of one kind share a request: the PoC measured 1.39x fewer input\n// tokens and ~4x less wall time than one request per item. A batch holds at\n// most `maxItems` items (default 32, inside the 20–40 band) and stays under\n// `maxTokens` (default 32k) by a conservative estimate — three characters a\n// token, which over-counts English and roughly matches Turkish.\n\nexport interface BatchLimits {\n maxItems?: number\n maxTokens?: number\n}\n\nexport const DEFAULT_BATCH: Required<BatchLimits> = { maxItems: 32, maxTokens: 32_000 }\n\nexport const estimateTokens = (text: string): number => Math.ceil(text.length / 3)\n\n/**\n * Split item costs into consecutive batches. `fixed` is what every request\n * pays once (the preamble); `costs[i]` what item i adds (its line and its\n * questions). An item too large for any batch goes alone.\n */\nexport function planBatches(costs: readonly number[], fixed: number, limits: BatchLimits = {}): number[][] {\n const maxItems = limits.maxItems ?? DEFAULT_BATCH.maxItems\n const maxTokens = limits.maxTokens ?? DEFAULT_BATCH.maxTokens\n if (!Number.isInteger(maxItems) || maxItems < 1) throw new RangeError(`maxItems must be a positive integer, got ${maxItems}`)\n const batches: number[][] = []\n let current: number[] = []\n let tokens = fixed\n costs.forEach((cost, i) => {\n if (current.length && (current.length >= maxItems || tokens + cost > maxTokens)) {\n batches.push(current)\n current = []\n tokens = fixed\n }\n current.push(i)\n tokens += cost\n })\n if (current.length) batches.push(current)\n return batches\n}\n","// ─── Budget cap and circuit breaker ───\n//\n// Neither ever fails a decision. Over the cap, or with the breaker open, the\n// decider answers from the rule and marks the decision `unreviewed`.\n\n/** How many provider decisions a tenant may spend. */\nexport interface DecisionBudget {\n /** Reserve up to `count` decisions for `tenant` at `now`; returns how many were granted. */\n take: (tenant: string, count: number, now: Date) => Promise<number>\n}\n\n/** A per-tenant cap on provider decisions per UTC day, held in memory. */\nexport class MemoryDailyBudget implements DecisionBudget {\n private readonly spent = new Map<string, number>()\n\n constructor(readonly perDay: number) {\n if (!Number.isInteger(perDay) || perDay < 0) throw new RangeError(`perDay must be a non-negative integer, got ${perDay}`)\n }\n\n async take(tenant: string, count: number, now: Date): Promise<number> {\n const slot = `${tenant}\\n${now.toISOString().slice(0, 10)}`\n const used = this.spent.get(slot) ?? 0\n const granted = Math.max(0, Math.min(count, this.perDay - used))\n this.spent.set(slot, used + granted)\n return granted\n }\n\n used(tenant: string, now: Date): number {\n return this.spent.get(`${tenant}\\n${now.toISOString().slice(0, 10)}`) ?? 0\n }\n}\n\nexport interface CircuitBreakerOptions {\n /** Consecutive failed requests that open the circuit. Default 3. */\n failures?: number\n /** How long it stays open before one request is let through. Default 60s. */\n cooldownMs?: number\n now?: () => number\n}\n\n/**\n * Closed → open after `failures` consecutive failed requests; open → half-open\n * after `cooldownMs`, where the next request decides: success closes it, a\n * failure opens it for another cooldown.\n */\nexport class CircuitBreaker {\n private consecutive = 0\n private openedAt: number | undefined\n private readonly limit: number\n private readonly cooldownMs: number\n private readonly now: () => number\n\n constructor(options: CircuitBreakerOptions = {}) {\n this.limit = options.failures ?? 3\n this.cooldownMs = options.cooldownMs ?? 60_000\n this.now = options.now ?? Date.now\n }\n\n get state(): 'closed' | 'open' | 'half_open' {\n if (this.openedAt === undefined) return 'closed'\n return this.now() - this.openedAt >= this.cooldownMs ? 'half_open' : 'open'\n }\n\n /** Whether a request may go out now. */\n allows(): boolean {\n return this.state !== 'open'\n }\n\n success(): void {\n this.consecutive = 0\n this.openedAt = undefined\n }\n\n failure(): void {\n this.consecutive++\n if (this.openedAt !== undefined || this.consecutive >= this.limit) this.openedAt = this.now()\n }\n}\n","// ─── Decision cache ───\n//\n// A provider is asked about the same input once. The key is\n// sha256(kind, schema version, request shape, canonical shaped input): the same\n// shaped input under the same schema and the same provider request always maps\n// to the same entry, and a schema bump or a changed request shape\n// (`requestShapeHash`) retires every entry made under the old one. Only provider answers are\n// cached — a rule answer is free to recompute and a fallback is not a decision\n// anyone reviewed.\n//\n// The stores here are for a single process (memory) and for a run directory\n// (append-only JSONL). A database store is the host's: implement\n// `DecisionCache` over it.\n\nimport { createHash } from 'node:crypto'\nimport { appendFile, mkdir, readFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport { canonicalStringify } from '@contentrain/types'\nimport type { Decision } from './types.js'\n\n/** What a cache keeps of a decision: the answer, never the input. */\nexport type CachedDecision = Pick<Decision, 'kind' | 'version' | 'shape' | 'choice' | 'score' | 'confidence' | 'probabilities' | 'proposed' | 'model'> & {\n source: 'jev' | 'llm'\n /** ISO time the provider answered. */\n at: string\n}\n\nexport interface DecisionCache {\n get: (key: string) => Promise<CachedDecision | undefined>\n set: (key: string, value: CachedDecision) => Promise<void>\n}\n\nexport function cacheKey(kind: string, version: string, shape: string, shaped: unknown): string {\n return createHash('sha256').update(`${kind}\\n${version}\\n${shape}\\n${canonicalStringify(shaped)}`).digest('hex')\n}\n\nexport class MemoryDecisionCache implements DecisionCache {\n private readonly entries = new Map<string, CachedDecision>()\n\n get size(): number {\n return this.entries.size\n }\n\n async get(key: string): Promise<CachedDecision | undefined> {\n return this.entries.get(key)\n }\n\n async set(key: string, value: CachedDecision): Promise<void> {\n this.entries.set(key, value)\n }\n}\n\n/**\n * One `{\"key\",\"value\"}` line per answer, appended. Read once, on first use;\n * a later line for the same key wins. A torn last line (a crash mid-append) is\n * skipped rather than failing the run — the answer is asked for again.\n */\nexport class JsonlDecisionCache implements DecisionCache {\n private loaded: Promise<Map<string, CachedDecision>> | undefined\n\n constructor(readonly path: string) {}\n\n private load(): Promise<Map<string, CachedDecision>> {\n this.loaded ??= readFile(this.path, 'utf8').then(\n text => readCacheLines(text),\n (error: NodeJS.ErrnoException) => {\n if (error.code === 'ENOENT') return new Map<string, CachedDecision>()\n throw error\n },\n )\n return this.loaded\n }\n\n async get(key: string): Promise<CachedDecision | undefined> {\n return (await this.load()).get(key)\n }\n\n async set(key: string, value: CachedDecision): Promise<void> {\n const entries = await this.load()\n entries.set(key, value)\n await mkdir(dirname(this.path), { recursive: true })\n await appendFile(this.path, `${JSON.stringify({ key, value })}\\n`)\n }\n}\n\nfunction readCacheLines(text: string): Map<string, CachedDecision> {\n const entries = new Map<string, CachedDecision>()\n for (const line of text.split('\\n')) {\n if (!line.trim()) continue\n try {\n const { key, value } = JSON.parse(line) as { key?: unknown, value?: CachedDecision }\n if (typeof key === 'string' && value && typeof value === 'object') entries.set(key, value)\n }\n catch {\n // torn line — see the class comment\n }\n }\n return entries\n}\n","// ─── Jev provider (typesafe.ai systemone) ───\n//\n// The only network code in the package. Three rules hold here and nowhere\n// else needs to think about them:\n// - The bearer token comes from the environment, read at the moment of each\n// request and passed straight into the header. It is never stored on an\n// object, returned, logged or put in an error message.\n// - Requests go to one fixed endpoint. There is no base-URL option.\n// - The request carries only what the kind's shaper and renderer produced.\n\nimport { createHash } from 'node:crypto'\nimport { canonicalStringify } from '@contentrain/types'\nimport type { DecisionProvider, JevAnswer, JevQuestion, KindSpec, Outcome, ProviderAnswer } from './types.js'\n\nexport const JEV_ENDPOINT = 'https://api.typesafe.ai/v1/systemone'\nexport const JEV_TOKEN_ENV = 'CONTENTRAIN_JEW_API_TOKEN'\nexport const DEFAULT_JEV_MODEL = 'jev-latest'\n\nexport interface JevProviderOptions {\n /** Where the token is read from. Default `process.env`. */\n env?: Readonly<Record<string, string | undefined>>\n /** Injected for tests and recorded replays. The URL it is called with is always `JEV_ENDPOINT`. */\n fetch?: typeof globalThis.fetch\n /** Per request. Default 15s. */\n timeoutMs?: number\n /** Default `jev-latest`. Part of the request shape: a different model is a different cache. */\n model?: string\n}\n\nexport class JevError extends Error {\n constructor(message: string, readonly status: number | undefined, readonly timeout = false) {\n super(message)\n this.name = 'JevError'\n }\n}\n\n/**\n * The request one batch sends: the kind's header from the first item, then one\n * `Item <n>: ` line per item; every item's questions keyed `item<n>_<suffix>`.\n */\nexport function buildJevRequest(spec: KindSpec<any, any>, shaped: readonly unknown[]): { state: string, questions: Record<string, JevQuestion> } {\n const jev = spec.jev\n if (!jev) throw new TypeError(`kind ${spec.kind} has no Jev prompt`)\n const header = shaped.length && jev.header ? jev.header(shaped[0]) : ''\n const lines = shaped.map((item, i) => `Item ${i + 1}: ${jev.render(item)}`)\n const questions: Record<string, JevQuestion> = {}\n shaped.forEach((_, i) => {\n const prefix = `item${i + 1}`\n for (const [suffix, question] of Object.entries(jev.questions(prefix))) questions[`${prefix}_${suffix}`] = question\n })\n return { state: header + lines.join('\\n'), questions }\n}\n\n/**\n * Hash of everything that shapes a kind's provider request: the model, the\n * batch limits, whether items are grouped, and the request built from two\n * copies of the kind's probe (header, line format, questions, criteria). A\n * change to any of them changes the hash, and with it every cache key.\n */\nexport function requestShapeHash(spec: KindSpec<any, any>, model = DEFAULT_JEV_MODEL): string {\n const jev = spec.jev\n if (!jev) return 'none'\n const shape = {\n model,\n batch: jev.batch ?? null,\n grouped: Boolean(jev.group),\n request: buildJevRequest(spec, [jev.probe, jev.probe]),\n }\n return createHash('sha256').update(canonicalStringify(shape)).digest('hex').slice(0, 16)\n}\n\nexport function createJevProvider(options: JevProviderOptions = {}): DecisionProvider {\n const env = options.env ?? process.env\n const doFetch = options.fetch ?? globalThis.fetch\n const timeoutMs = options.timeoutMs ?? 15_000\n const model = options.model ?? DEFAULT_JEV_MODEL\n\n return {\n name: 'jev',\n model,\n available: () => Boolean(env[JEV_TOKEN_ENV]?.trim()),\n async ask(spec, shaped) {\n const token = env[JEV_TOKEN_ENV]?.trim()\n if (!token) throw new JevError(`${JEV_TOKEN_ENV} is not set`, undefined)\n const { state, questions } = buildJevRequest(spec, shaped)\n let response: Response\n try {\n response = await doFetch(JEV_ENDPOINT, {\n method: 'POST',\n headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({ state, model, questions }),\n signal: AbortSignal.timeout(timeoutMs),\n })\n }\n catch (error) {\n const name = (error as { name?: string }).name\n if (name === 'TimeoutError' || name === 'AbortError') throw new JevError(`Jev did not answer within ${timeoutMs}ms`, undefined, true)\n throw new JevError(`Jev request failed: ${redact(String((error as Error).message ?? error), token)}`, undefined)\n }\n const text = await response.text()\n if (!response.ok) throw new JevError(`Jev answered HTTP ${response.status}: ${redact(text.slice(0, 200), token)}`, response.status)\n let body: unknown\n try {\n body = JSON.parse(text)\n }\n catch {\n throw new JevError('Jev answered with a body that is not JSON', response.status)\n }\n return readJevResponse(spec, shaped.length, body)\n },\n }\n}\n\n/** Per-item outcomes from a systemone response. An item whose answers are missing or malformed gets `undefined`. */\nexport function readJevResponse(spec: KindSpec<any, any>, count: number, body: unknown): ProviderAnswer {\n const jev = spec.jev!\n const root = (body && typeof body === 'object' ? body : {}) as { answers?: unknown, usage?: unknown, model?: unknown }\n const answers = (root.answers && typeof root.answers === 'object' ? root.answers : {}) as Record<string, unknown>\n const outcomes: Array<Outcome | undefined> = []\n for (let i = 1; i <= count; i++) {\n const own: Record<string, JevAnswer> = {}\n let complete = true\n for (const suffix of Object.keys(jev.questions(`item${i}`))) {\n const answer = readAnswer(answers[`item${i}_${suffix}`])\n if (!answer) complete = false\n else own[suffix] = answer\n }\n outcomes.push(complete ? jev.read(own) : undefined)\n }\n const usage = root.usage as { input_tokens?: unknown, output_tokens?: unknown } | undefined\n return {\n outcomes,\n ...(usage && typeof usage.input_tokens === 'number' && typeof usage.output_tokens === 'number'\n ? { usage: { input_tokens: usage.input_tokens, output_tokens: usage.output_tokens } }\n : {}),\n ...(typeof root.model === 'string' ? { model: root.model } : {}),\n }\n}\n\nconst isUnit = (value: unknown): value is number => typeof value === 'number' && value >= 0 && value <= 1\n\nfunction readAnswer(value: unknown): JevAnswer | undefined {\n if (!value || typeof value !== 'object') return undefined\n const answer = value as Record<string, unknown>\n const probabilities = answer.probabilities && typeof answer.probabilities === 'object'\n ? { probabilities: answer.probabilities as Record<string, number> }\n : {}\n if (answer.type === 'choice' && typeof answer.choice === 'string' && isUnit(answer.confidence))\n return { type: 'choice', choice: answer.choice, confidence: answer.confidence, ...probabilities }\n if (answer.type === 'score' && typeof answer.score === 'number' && Number.isFinite(answer.score) && isUnit(answer.confidence))\n return { type: 'score', score: answer.score, confidence: answer.confidence, ...probabilities }\n if (answer.type === 'noul' && isUnit(answer.noul)) return { type: 'noul', noul: answer.noul }\n return undefined\n}\n\nfunction redact(text: string, token: string): string {\n return text.split(token).join('[redacted]')\n}\n","// ─── Shaping helpers ───\n//\n// What a shaper does to free text before it may leave the process: URLs,\n// e-mail addresses and root-relative paths become placeholders, whitespace\n// collapses, and the text is cut to a length the decision can use.\n\nconst URL = /\\b(?:https?|ftp):\\/\\/\\S+|\\bwww\\.\\S+/gi\nconst EMAIL = /[\\w.+-]+@[\\w-]+(?:\\.[\\w-]+)+/g\n// A root-relative path: a slash at the start or after a space/bracket/quote, then a segment.\nconst PATH = /(^|[\\s(\"'=])\\/[\\w.~%-]+(?:\\/[\\w.~%-]*)*/g\n\nexport function scrubText(text: string, max: number): string {\n const clean = text\n .replace(URL, '<url>')\n .replace(EMAIL, '<email>')\n .replace(PATH, '$1<path>')\n .replace(/\\s+/g, ' ')\n .trim()\n return clean.length > max ? `${clean.slice(0, max - 1)}…` : clean\n}\n\n/** A slug-like identifier (post-type name, family name): lower-case word characters and dashes only. */\nexport function scrubSlug(value: string, max = 40): string {\n return value.toLowerCase().replace(/[^a-z0-9_-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, max)\n}\n\n/** A finite number, or undefined. */\nexport function finite(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n","// ─── eligibility_band: the undecided band of Migrate's eligibility verdict ───\n//\n// Migrate's `judgeEligibility` sorts a discovered site into eligible /\n// page_only / custom_type / access_blocked from public discovery counts. Most\n// sites are clear. Two bands are not, and those — only those — go to Jev:\n//\n// - posts and custom-type entries within a factor of two of each other: is\n// the content the posts, or the custom types?\n// - exactly one sampled post: a blog of one, or a brochure site with a stray\n// \"Hello world\"?\n//\n// The rule mirrors judgeEligibility's thresholds (MIN_POSTS = 2) so the clear\n// cases never reach a provider; a host with its own verdict function passes it\n// as `options.rule`. A Jev answer under 0.5 confidence becomes `needs_human`,\n// which is never offered to Jev as a choice.\n\nimport type { JevAnswer, JevQuestion, KindSpec, RuleVerdict } from '../types.js'\nimport { scrubSlug } from './shape.js'\n\nexport const ELIGIBILITY_CHOICES = ['eligible', 'access_blocked', 'page_only', 'custom_type'] as const\nexport type EligibilityChoice = typeof ELIGIBILITY_CHOICES[number]\nexport const NEEDS_HUMAN = 'needs_human'\n\n/** Migrate's `EligibilityInput`, as discovery produces it. */\nexport interface EligibilityBandInput {\n access: 'open' | 'bot_wall' | 'unreachable'\n rest: {\n reachable: boolean\n counts: { posts: number | null, pages: number | null }\n postTypes: Array<{ slug: string, count?: number | null }>\n /** Sampled records. Only how many there are is used — their content never leaves. */\n samples: { posts: unknown[], pages: unknown[] }\n }\n}\n\nexport interface EligibilityBandShaped {\n access: EligibilityBandInput['access']\n rest_reachable: boolean\n posts: number | null\n pages: number | null\n post_samples: number\n page_samples: number\n custom_types: Array<{ slug: string, count: number }>\n}\n\nconst MIN_POSTS = 2\n/** Posts and custom entries within this factor of each other are the band. */\nconst BAND_FACTOR = 2\n\nexport function shapeEligibility(input: EligibilityBandInput): EligibilityBandShaped {\n const rest = input.rest\n // Types whose slugs scrub to the same slug are summed. judgeEligibility does\n // not merge them, but it only ever uses the total, which is the same either way.\n const counts = new Map<string, number>()\n for (const type of rest.postTypes ?? []) {\n if (type.slug === 'post' || type.slug === 'page' || !((type.count ?? 0) > 0)) continue\n const slug = scrubSlug(type.slug)\n counts.set(slug, (counts.get(slug) ?? 0) + (type.count ?? 0))\n }\n return {\n access: input.access,\n rest_reachable: Boolean(rest.reachable),\n posts: rest.counts?.posts ?? null,\n pages: rest.counts?.pages ?? null,\n post_samples: rest.samples?.posts?.length ?? 0,\n page_samples: rest.samples?.pages?.length ?? 0,\n custom_types: [...counts].map(([slug, count]) => ({ slug, count })).toSorted((a, b) => a.slug.localeCompare(b.slug)),\n }\n}\n\nconst certain = (choice: EligibilityChoice): RuleVerdict => ({ choice, confidence: 1, final: true })\nconst tentative = (choice: EligibilityChoice): RuleVerdict => ({ choice, confidence: 0.5, final: false })\n\nexport function eligibilityRule(input: EligibilityBandInput): RuleVerdict {\n const site = shapeEligibility(input)\n if (site.access !== 'open' || !site.rest_reachable) return certain('access_blocked')\n const postCount = site.posts ?? site.post_samples\n const customCount = site.custom_types.reduce((sum, type) => sum + type.count, 0)\n const pages = site.page_samples || (site.pages ?? 0)\n\n if (site.post_samples >= MIN_POSTS) {\n const verdict: EligibilityChoice = customCount <= postCount ? 'eligible' : 'custom_type'\n const close = customCount > 0 && customCount * BAND_FACTOR >= postCount && postCount * BAND_FACTOR >= customCount\n return close ? tentative(verdict) : certain(verdict)\n }\n const verdict: EligibilityChoice = site.custom_types.length ? 'custom_type' : pages ? 'page_only' : 'access_blocked'\n return site.post_samples === 1 ? tentative(verdict) : certain(verdict)\n}\n\nfunction renderEligibility(site: EligibilityBandShaped): string {\n const custom = site.custom_types.length ? site.custom_types.map(type => `${type.slug}=${type.count}`).join(', ') : 'none'\n return [\n `access=${site.access}`,\n `rest=${site.rest_reachable ? 'reachable' : 'unreachable'}`,\n `posts=${site.posts ?? 'unknown'} (sampled ${site.post_samples})`,\n `pages=${site.pages ?? 'unknown'} (sampled ${site.page_samples})`,\n `custom post types: ${custom}`,\n ].join('; ')\n}\n\nfunction readEligibility(answers: Record<string, JevAnswer>) {\n const answer = answers.eligibility\n if (answer?.type !== 'choice') return undefined\n return { choice: answer.choice, confidence: answer.confidence, ...(answer.probabilities ? { probabilities: answer.probabilities } : {}) }\n}\n\nfunction eligibilityQuestions(prefix: string): Record<string, JevQuestion> {\n return {\n eligibility: {\n type: 'choice',\n instructions: `${prefix}: where does this site's content live, and can the engine move it?`,\n criteria: {\n eligible: 'Standard blog posts carry the site\\'s content; moving posts and pages moves what matters.',\n custom_type: 'The content lives mainly in custom post types (products, portfolio, members); moving posts and pages alone leaves it behind.',\n page_only: 'No real blog: a corporate or brochure site whose content is its pages.',\n access_blocked: 'What the scan could see is not the site\\'s real content; authorized access is needed to reach it.',\n },\n },\n }\n}\n\nexport const eligibilityBand: KindSpec<EligibilityBandInput, EligibilityBandShaped> = {\n kind: 'eligibility_band',\n version: '1',\n choices: ELIGIBILITY_CHOICES,\n shape: shapeEligibility,\n rule: eligibilityRule,\n jev: {\n header: () => 'WordPress sites considered for migration. Each item is what a public discovery scan counted on one site. The migration engine moves standard posts and pages only.\\n',\n render: renderEligibility,\n questions: eligibilityQuestions,\n read: readEligibility,\n probe: { access: 'open', rest_reachable: true, posts: 20, pages: 3, post_samples: 5, page_samples: 3, custom_types: [{ slug: 'product', count: 30 }] },\n },\n lowConfidence: { threshold: 0.5, choice: NEEDS_HUMAN },\n}\n","// ─── Migrate v3 fact-pack decisions: the narrow leftovers ───\n//\n// Migrate's fact pack settles most of a site deterministically: component\n// identity from builder trees and repeated subtrees, content vs. interface text\n// from cross-instance variance, field types from what the values say. Three\n// questions are left, each over a closed set, each with a rule that answers\n// the clear cases and a tentative answer for the rest:\n//\n// - field_type: a varying value whose type the value does not settle\n// (string or text, relation or url, select or string)\n// - region_name: what a top-level page section is (hero, card-grid, …)\n// - unmapped_element: which kit component a builder element no mapping rule\n// covers stands for, or `prose` / `site-specific`\n//\n// The fact pack already shapes these inputs (samples cut, e-mail addresses and\n// phone numbers masked); the shapers here scrub again, so nothing depends on\n// the producer being careful.\n\nimport type { JevAnswer, JevQuestion, KindSpec, RuleVerdict } from '../types.js'\nimport { scrubSlug, scrubText } from './shape.js'\n\nconst readChoice = (key: string) => (answers: Record<string, JevAnswer>) => {\n const answer = answers[key]\n if (answer?.type !== 'choice') return undefined\n return { choice: answer.choice, confidence: answer.confidence, ...(answer.probabilities ? { probabilities: answer.probabilities } : {}) }\n}\nconst certain = (choice: string, confidence = 1): RuleVerdict => ({ choice, confidence, final: true })\nconst tentative = (choice: string, confidence = 0.5): RuleVerdict => ({ choice, confidence, final: false })\n\n// ─── field_type ───────────────────────────────────────────────────────────────\n\n/** The field types a fact-pack field_type decision can be between. */\nexport const FIELD_TYPE_CHOICES = ['string', 'text', 'markdown', 'richtext', 'relation', 'url', 'select'] as const\nexport type FieldTypeChoice = typeof FIELD_TYPE_CHOICES[number]\n\nconst FIELD_TYPE_CRITERIA: Record<FieldTypeChoice, string> = {\n string: 'A short single-line value: a title, a label, a name.',\n text: 'Plain multi-sentence text without formatting: an excerpt, a description.',\n markdown: 'Formatted prose (emphasis, links inside the text) an editor writes as Markdown.',\n richtext: 'Formatted prose that needs HTML an editor cannot express in Markdown (tables, embeds).',\n relation: 'A link to another entry of the same site (a post, a page, a term): it should follow that entry when its address changes.',\n url: 'An address kept as written: external, or a fixed internal path that is not an entry.',\n select: 'One of a few fixed values repeated across instances (a category label, a status, a size).',\n}\n\nexport interface FieldTypeInput {\n tag: string\n prop: 'text' | 'href' | 'src' | 'alt' | 'datetime'\n inline?: boolean\n instances: number\n distinct: number\n maxLength: number\n samples: string[]\n /** The types this item may be answered with (a subset of FIELD_TYPE_CHOICES). */\n options: string[]\n}\n\nexport interface FieldTypeShaped {\n tag: string\n prop: FieldTypeInput['prop']\n inline: boolean\n instances: number\n distinct: number\n max_length: number\n samples: string[]\n options: FieldTypeChoice[]\n}\n\nexport function shapeFieldType(input: FieldTypeInput): FieldTypeShaped {\n const options = FIELD_TYPE_CHOICES.filter(choice => input.options.includes(choice))\n return {\n tag: scrubSlug(input.tag, 12),\n prop: input.prop,\n inline: Boolean(input.inline),\n instances: Math.max(0, Math.round(input.instances)),\n distinct: Math.max(0, Math.round(input.distinct)),\n max_length: Math.max(0, Math.round(input.maxLength)),\n samples: (input.samples ?? []).slice(0, 3).map(sample => scrubText(sample, 60)),\n options: options.length ? options : [...FIELD_TYPE_CHOICES],\n }\n}\n\nexport function fieldTypeRule(input: FieldTypeInput): RuleVerdict | undefined {\n const f = shapeFieldType(input)\n const has = (a: FieldTypeChoice, b: FieldTypeChoice) => f.options.length === 2 && f.options.includes(a) && f.options.includes(b)\n if (has('string', 'text')) {\n if (f.max_length <= 100) return certain('string')\n if (f.max_length >= 200) return certain('text')\n return tentative(f.max_length > 140 ? 'text' : 'string')\n }\n if (has('select', 'string')) {\n if (f.instances >= 8 && f.distinct <= 3) return certain('select')\n return tentative(f.distinct <= 3 ? 'select' : 'string')\n }\n if (has('relation', 'url')) return tentative('relation', 0.6)\n if (f.options.length === 1) return certain(f.options[0]!)\n return undefined\n}\n\nexport const fieldType: KindSpec<FieldTypeInput, FieldTypeShaped> = {\n kind: 'field_type',\n version: '1',\n choices: FIELD_TYPE_CHOICES,\n shape: shapeFieldType,\n rule: fieldTypeRule,\n jev: {\n // One request per option set, so the header can name the only valid answers.\n group: shaped => shaped.options.join('|'),\n header: shaped => `Values of repeated website components, migrated into a structured CMS. Each item is one value that differs between instances of the same component. Pick the field type that stores it. Valid types for every item in this request: ${shaped.options.join(', ')}.\\n`,\n render: f => `<${f.tag}> ${f.prop}; ${f.instances} instances, ${f.distinct} distinct, longest ${f.max_length} chars${f.inline ? ', has inline formatting' : ''}; samples: ${f.samples.map(s => JSON.stringify(s)).join(' | ') || 'none'}`,\n questions: (prefix): Record<string, JevQuestion> => ({\n type: { type: 'choice', instructions: `${prefix}: which field type stores this value?`, criteria: FIELD_TYPE_CRITERIA },\n }),\n read: readChoice('type'),\n probe: { tag: 'p', prop: 'text', inline: false, instances: 12, distinct: 12, max_length: 160, samples: ['A short excerpt of a post that runs a little longer than a title.'], options: ['string', 'text'] },\n },\n}\n\n// ─── region_name ──────────────────────────────────────────────────────────────\n\nexport const REGION_CHOICES = ['header', 'nav', 'hero', 'main', 'footer', 'sidebar', 'cta', 'card-grid', 'features', 'faq', 'pricing', 'testimonials', 'logos', 'gallery', 'contact', 'newsletter', 'content', 'other'] as const\nexport type RegionChoice = typeof REGION_CHOICES[number]\n\nconst REGION_CRITERIA: Record<RegionChoice, string> = {\n 'header': 'The site header: brand and primary navigation.',\n 'nav': 'A navigation block on its own.',\n 'hero': 'The large opening section of a page: headline, short text, often an image and a button.',\n 'main': 'The main content wrapper of the page.',\n 'footer': 'The site footer.',\n 'sidebar': 'A side column next to the main content.',\n 'cta': 'A call-to-action band: a short pitch and a button.',\n 'card-grid': 'A grid or list of similar cards (posts, services, team members).',\n 'features': 'A set of feature or benefit blocks, usually icon + title + text.',\n 'faq': 'Questions and answers, often collapsible.',\n 'pricing': 'Plans or packages with prices.',\n 'testimonials': 'Quotes from customers with names.',\n 'logos': 'A strip of client or partner logos.',\n 'gallery': 'A set of images shown as a gallery.',\n 'contact': 'Contact details or a contact form.',\n 'newsletter': 'A newsletter sign-up.',\n 'content': 'Ordinary page content: text, images, headings.',\n 'other': 'None of the above.',\n}\n\nexport interface RegionInput {\n tag: string\n classes?: string[]\n box?: [number, number, number, number]\n builder?: string | null\n children?: string[]\n images?: number\n links?: number\n headings?: number\n forms?: number\n text?: string\n}\n\nexport interface RegionShaped {\n tag: string\n classes: string[]\n top: number\n width: number\n height: number\n builder: string | null\n children: string[]\n images: number\n links: number\n headings: number\n forms: number\n text: string\n}\n\nexport function shapeRegion(input: RegionInput): RegionShaped {\n const [, y = 0, w = 0, h = 0] = input.box ?? []\n return {\n tag: scrubSlug(input.tag, 12),\n classes: (input.classes ?? []).slice(0, 6).map(c => scrubSlug(c)),\n // Rounded: layout scale is what matters, and exact pixels would split the cache.\n top: Math.round(y / 50) * 50,\n width: Math.round(w / 10) * 10,\n height: Math.round(h / 50) * 50,\n builder: input.builder ? scrubSlug(input.builder.replace('/', '-'), 40) : null,\n children: (input.children ?? []).slice(0, 12).map(c => scrubSlug(c.replace('/', '-'), 40)),\n images: input.images ?? 0,\n links: input.links ?? 0,\n headings: input.headings ?? 0,\n forms: input.forms ?? 0,\n text: scrubText(input.text ?? '', 120),\n }\n}\n\nconst REGION_CLASS_HINTS: [RegExp, RegionChoice][] = [\n [/faq|accordion|toggle|details/, 'faq'],\n [/testimonial|review|quote/, 'testimonials'],\n [/pricing|price|plan/, 'pricing'],\n [/newsletter|subscribe|mailchimp|optin/, 'newsletter'],\n [/logo|client|partner|brand/, 'logos'],\n [/gallery|portfolio/, 'gallery'],\n [/cta|call-to-action/, 'cta'],\n [/hero|banner|cover|masthead/, 'hero'],\n [/feature|benefit|service/, 'features'],\n]\n\nexport function regionRule(input: RegionInput): RuleVerdict | undefined {\n const r = shapeRegion(input)\n const words = `${r.classes.join(' ')} ${r.builder ?? ''} ${r.children.join(' ')}`\n for (const [re, choice] of REGION_CLASS_HINTS) if (re.test(words)) return tentative(choice, 0.7)\n if (r.forms > 0) return tentative(/subscri|newsletter|abone/i.test(r.text) ? 'newsletter' : 'contact', 0.6)\n const same = r.children.length >= 3 && r.children.every(c => c === r.children[0])\n if (same) return tentative('card-grid', 0.6)\n if (r.images >= 4 && r.headings <= 1 && r.text.length < 80) return tentative('gallery', 0.6)\n if (r.top <= 200 && r.headings >= 1 && r.height >= 300) return tentative('hero', 0.6)\n return tentative('content', 0.3)\n}\n\nexport const regionName: KindSpec<RegionInput, RegionShaped> = {\n kind: 'region_name',\n version: '1',\n choices: REGION_CHOICES,\n shape: shapeRegion,\n rule: regionRule,\n jev: {\n header: () => 'Top-level sections of a website page, rebuilt as components. Each item is one section: its tag, classes, position, the kinds of its children and a scrubbed sample of its text. Name what the section is.\\n',\n render: r => `<${r.tag}${r.classes.length ? ` class=\"${r.classes.join(' ')}\"` : ''}> at y≈${r.top}, ${r.width}×${r.height}; builder=${r.builder ?? 'none'}; children: ${r.children.join(', ') || 'none'}; ${r.headings} headings, ${r.images} images, ${r.links} links, ${r.forms} forms; text: ${JSON.stringify(r.text)}`,\n questions: (prefix): Record<string, JevQuestion> => ({\n region: { type: 'choice', instructions: `${prefix}: what is this page section?`, criteria: REGION_CRITERIA },\n }),\n read: readChoice('region'),\n probe: { tag: 'section', classes: ['wp-block-cover'], top: 100, width: 1280, height: 600, builder: 'core-cover', children: ['h1', 'p', 'core-buttons'], images: 1, links: 1, headings: 1, forms: 0, text: 'Welcome to our studio' },\n },\n}\n\n// ─── unmapped_element ─────────────────────────────────────────────────────────\n\n/** Kit component ids (astro-kit catalog, first fifteen) plus the two non-component answers. */\nexport const UNMAPPED_CHOICES = ['header', 'nav', 'footer', 'hero', 'card-grid', 'post-card', 'cta', 'faq', 'tabs', 'testimonial', 'gallery', 'slider', 'contact-form', 'pagination', 'breadcrumb', 'prose', 'site-specific'] as const\nexport type UnmappedChoice = typeof UNMAPPED_CHOICES[number]\n\nconst UNMAPPED_CRITERIA: Record<UnmappedChoice, string> = {\n 'header': 'Site header with brand and navigation.',\n 'nav': 'A navigation menu.',\n 'footer': 'Site footer.',\n 'hero': 'A large opening banner: headline, text, image, button.',\n 'card-grid': 'A grid of cards or feature boxes (icon/image + title + text).',\n 'post-card': 'One card for a blog post in a list.',\n 'cta': 'A call-to-action box with a button.',\n 'faq': 'Collapsible questions and answers (accordion, toggle).',\n 'tabs': 'Tabbed panels.',\n 'testimonial': 'A customer quote with a name.',\n 'gallery': 'An image gallery.',\n 'slider': 'A carousel or slider of slides.',\n 'contact-form': 'A form visitors submit.',\n 'pagination': 'Page navigation of a list.',\n 'breadcrumb': 'A breadcrumb trail.',\n 'prose': 'Plain content (text, a heading, an image, a spacer) that stays rich text, not a component.',\n 'site-specific': 'Something no kit component covers; it is written for this site.',\n}\n\nexport interface UnmappedInput {\n name: string\n builder: string\n count: number\n pages: number\n attrKeys?: string[]\n}\n\nexport interface UnmappedShaped {\n name: string\n builder: string\n count: number\n pages: number\n attr_keys: string[]\n}\n\nexport function shapeUnmapped(input: UnmappedInput): UnmappedShaped {\n return {\n name: scrubSlug(input.name.replace('/', '-'), 60),\n builder: scrubSlug(input.builder, 12),\n count: input.count,\n pages: input.pages,\n attr_keys: (input.attrKeys ?? []).slice(0, 20).map(k => scrubSlug(k, 40)),\n }\n}\n\nconst UNMAPPED_NAME_HINTS: [RegExp, UnmappedChoice][] = [\n [/(^|-)(heading|text|paragraph|text-editor|image|spacer|divider|separator|html|shortcode|video|audio|icon)$/, 'prose'],\n [/accordion|toggle|faq|details/, 'faq'],\n [/slider|carousel|slideshow/, 'slider'],\n [/gallery|lightbox/, 'gallery'],\n [/testimonial|review/, 'testimonial'],\n [/tabs?$/, 'tabs'],\n [/form|contact|signup/, 'contact-form'],\n [/call-to-action|cta|promo/, 'cta'],\n [/blurb|icon-box|info-box|image-box|feature|card|team-member|service/, 'card-grid'],\n [/breadcrumb/, 'breadcrumb'],\n [/pagination|pager/, 'pagination'],\n [/posts|blog|query|post-grid|loop/, 'card-grid'],\n [/fullwidth-header|hero|banner|cover/, 'hero'],\n [/menu|nav/, 'nav'],\n]\n\nexport function unmappedRule(input: UnmappedInput): RuleVerdict | undefined {\n const e = shapeUnmapped(input)\n for (const [re, choice] of UNMAPPED_NAME_HINTS) if (re.test(e.name)) return certain(choice, 0.9)\n return tentative('site-specific', 0.3)\n}\n\nexport const unmappedElement: KindSpec<UnmappedInput, UnmappedShaped> = {\n kind: 'unmapped_element',\n version: '1',\n choices: UNMAPPED_CHOICES,\n shape: shapeUnmapped,\n rule: unmappedRule,\n jev: {\n group: shaped => shaped.builder,\n header: shaped => `Page-builder elements (${shaped.builder}) found on a WordPress site that is rebuilt from a component kit. Each item is one element type: its name, how often it appears and the names of its settings. Say which kit component it becomes, \"prose\" when it is plain content, or \"site-specific\" when no kit component fits.\\n`,\n render: e => `${e.name}: ${e.count} uses on ${e.pages} pages; settings: ${e.attr_keys.join(', ') || 'none'}`,\n questions: (prefix): Record<string, JevQuestion> => ({\n component: { type: 'choice', instructions: `${prefix}: which kit component does this element become?`, criteria: UNMAPPED_CRITERIA },\n }),\n read: readChoice('component'),\n probe: { name: 'uagb-info-box', builder: 'gutenberg', count: 94, pages: 12, attr_keys: ['classes', 'settings'] },\n },\n lowConfidence: { threshold: 0.5, choice: 'site-specific' },\n}\n","// ─── punch_item: a migration run report's punch item → class + severity ───\n//\n// Migrate's run report lists what is left to finish on a migrated site. This\n// kind labels each item with its root cause (class) and how much it matters\n// (severity), as an advisory column beside the item — never as a gate.\n//\n// The request is PoC-1's, word for word, because that is the shape that was\n// measured: one request per site (at most 25 items), a three-line site header,\n// `Item <n>: etiket=…, link=…, neden=…` lines, and three questions per item —\n// class, severity and needs_human. needs_human is asked and not read: PoC-1\n// found it unreliable, but dropping the question changed the other two\n// answers. The one deliberate difference is privacy: the site's name, its URL\n// and item links are sent as placeholders.\n//\n// Any change here changes `requestShapeHash(punchItem)`. The test pins that\n// hash to the one in the latest `calibration/*.json`; a new shape needs a new\n// live calibration (`pnpm calibration:live`) before it can ship.\n\nimport { createHash } from 'node:crypto'\nimport type { JevAnswer, JevQuestion, KindSpec, RuleVerdict } from '../types.js'\nimport { finite, scrubText } from './shape.js'\n\nexport const PUNCH_CLASSES = ['product_defect', 'source_limit', 'cosmetic', 'measurement'] as const\nexport type PunchClass = typeof PUNCH_CLASSES[number]\n\nexport const PUNCH_CLASS_CRITERIA: Record<PunchClass, string> = {\n product_defect: 'Migration engine\\'in ürettiği çıktıda bir kusur/hata — üretilen sayfada bir şey yanlış (ör. yanlış görsel tekrar ediyor, bağlantı kırık, içerik markup\\'ta eksik).',\n source_limit: 'Kaynak sitenin kendi yapısından gelen bir sınır — içerik zaten kaynakta veri olarak ayrıştırılamaz durumda (ör. tema markup\\'ına gömülü, API\\'de yok), migration engine bunu değiştiremez.',\n cosmetic: 'Teslimi engellemeyen küçük görsel fark — kullanıcı deneyimini gerçekten bozmayan, göz ardı edilebilir bir fark.',\n measurement: 'Ölçüm/araç belirsizliği — sorunun kendisi değil, ölçüm sürecinin (skor eşiği, örneklem, zaman aşımı) ne olduğunu net söyleyememesi.',\n}\n\n/** Severity rubric, levels 0–3 (Jev's score scale). Level n here is severity n+1 on a 1–4 scale. */\nexport const PUNCH_SEVERITY_CRITERIA = [\n 'Teslimi engellemez — göz ardı edilebilir.',\n 'Küçük, düşük öncelik — teslim edilebilir, sonra bakılabilir.',\n 'Teslimden önce ele alınmalı — müşteri fark edebilir ama kesin reddetmez.',\n 'Müşteri fark eder ve reddeder — teslim öncesi mutlaka çözülmeli.',\n] as const\n\nexport interface PunchItemInput {\n /** The item's label in the run report, e.g. `(aile: post)` or a page slug. */\n label: string\n /** Why it is on the list, as the run report words it. */\n reason: string\n /** A link to the page. Never sent: the request says only whether there is one. */\n link?: string\n /** The site the item belongs to. `name` and `url` only group items into one request and are never sent. */\n site?: { name?: string, url?: string, decision?: string, median?: number, mobile_median?: number }\n}\n\nexport interface PunchItemShaped {\n label: string\n reason: string\n /** Whether the item has a link; the link itself is not kept. */\n linked: boolean\n site: {\n /** Opaque: a hash of the site's name or URL, so one site's items share a request. Never sent. */\n group: string\n decision: string | null\n median: number | null\n mobile_median: number | null\n }\n}\n\nexport function shapePunchItem(input: PunchItemInput): PunchItemShaped {\n const site = input.site ?? {}\n const identity = site.name ?? site.url ?? ''\n return {\n label: scrubText(String(input.label ?? ''), 120),\n reason: scrubText(String(input.reason ?? ''), 500),\n linked: Boolean(input.link),\n site: {\n group: identity ? createHash('sha256').update(identity).digest('hex').slice(0, 16) : '',\n decision: typeof site.decision === 'string' ? scrubText(site.decision, 40) : null,\n median: finite(site.median) ?? null,\n mobile_median: finite(site.mobile_median) ?? null,\n },\n }\n}\n\n// Run-report phrasings whose class is not in doubt. Tentative only: a rule\n// cannot place severity, so these answer only when Jev does not.\nconst SIGNATURES: ReadonlyArray<readonly [RegExp, PunchClass]> = [\n [/ölçülemedi|genellik kanıtlanmadı/i, 'measurement'],\n [/gövde yuvası yok|tam sayfa klon/i, 'source_limit'],\n [/hero sızıntısı|medya kaybı|dinamik liste bağlanmadı/i, 'product_defect'],\n]\n\nexport function punchItemRule(input: PunchItemInput): RuleVerdict | undefined {\n const reason = String(input.reason ?? '')\n const hit = SIGNATURES.find(([pattern]) => pattern.test(reason))\n return hit ? { choice: hit[1], confidence: 1, final: false } : undefined\n}\n\n// PoC-1's `siteStateHeader`, with the site's name and URL as placeholders.\nfunction punchHeader(item: PunchItemShaped): string {\n return `Site: <site> (<url>)\\nGenel karar: ${item.site.decision}\\nMedyan kalite skoru: ${item.site.median}, mobil: ${item.site.mobile_median}\\n`\n}\n\n// PoC-1's `itemText`, after its `Item <n>: ` prefix.\nfunction renderPunchItem(item: PunchItemShaped): string {\n return `etiket=\"${item.label}\", link=\"${item.linked ? '<url>' : '(yok)'}\", neden=\"${item.reason}\"`\n}\n\n// PoC-1's `itemQuestions`.\nfunction punchQuestions(prefix: string): Record<string, JevQuestion> {\n return {\n class: { type: 'choice', instructions: `${prefix} için: bu kalemin kök nedeni nedir?`, criteria: PUNCH_CLASS_CRITERIA },\n severity: { type: 'score', instructions: `${prefix} için: bu kalem ne kadar ciddi?`, criteria: PUNCH_SEVERITY_CRITERIA },\n needs_human: { type: 'noul', instructions: `${prefix} kalemi, teslim öncesi bir insanın karar vermesini gerektiriyor (otomatik/açık bir düzeltme değil, yargı gerektiriyor).` },\n }\n}\n\nfunction readPunchItem(answers: Record<string, JevAnswer>) {\n const cls = answers.class\n const severity = answers.severity\n if (cls?.type !== 'choice' || severity?.type !== 'score') return undefined\n return {\n choice: cls.choice,\n score: severity.score,\n confidence: Math.min(cls.confidence, severity.confidence),\n ...(cls.probabilities ? { probabilities: cls.probabilities } : {}),\n }\n}\n\n// The prompt AO-9 measured Claude Haiku with, word for word: the same state\n// and questions, in PoC-1's language, answered through a forced tool call.\nfunction punchLlmPrompt({ state, questions, count }: { state: string, questions: Record<string, JevQuestion>, count: number }): string {\n const q = questions.class as Extract<JevQuestion, { type: 'choice' }>\n const s = questions.severity as Extract<JevQuestion, { type: 'score' }>\n const h = questions.needs_human!\n return [\n 'Aşağıdaki durum bir WordPress → Astro taşıma koşusunun bitirilecekler listesinden bir sitenin kalemlerini içeriyor.',\n '',\n '<state>',\n state,\n '</state>',\n '',\n 'Her kalem için üç soruyu yanıtla (itemN yerine kalem numarası):',\n `1) class — ${q.instructions.replace('item1', 'itemN')} Seçenekler:`,\n ...Object.entries(q.criteria).map(([k, v]) => ` - ${k}: ${v}`),\n `2) severity — ${s.instructions.replace('item1', 'itemN')} 0–3 arası tam sayı:`,\n ...s.criteria.map((c, n) => ` ${n}: ${c}`),\n `3) needs_human — önermenin doğru olma olasılığı (0–1): ${h.instructions.replace('item1', 'itemN')}`,\n '',\n `Tüm ${count} kalemi record_answers aracıyla, her kalem için bir kayıt olarak ver.`,\n ].join('\\n')\n}\n\n/** Jev's 0–3 severity score as a 1–4 level (PoC-1's hand-label scale). */\nexport const severityLevel = (score: number): number => Math.min(4, Math.max(1, Math.round(score) + 1))\n\nexport const punchItem: KindSpec<PunchItemInput, PunchItemShaped> = {\n kind: 'punch_item',\n version: '2',\n choices: PUNCH_CLASSES,\n scoreRange: [0, 3],\n shape: shapePunchItem,\n rule: punchItemRule,\n jev: {\n header: punchHeader,\n group: item => item.site.group,\n render: renderPunchItem,\n questions: punchQuestions,\n read: readPunchItem,\n llmPrompt: punchLlmPrompt,\n // PoC-1's MAX_ITEMS_PER_CHUNK.\n batch: { maxItems: 25 },\n probe: {\n label: '(aile: post)',\n reason: 'en kötü sayfa 56.4 < 80 (5 sayfa ölçüldü)',\n linked: false,\n site: { group: 'probe', decision: 'KABUL + PUNCH LIST', median: 94.7, mobile_median: 83.9 },\n },\n },\n}\n","import type { KindSpec } from '../types.js'\nimport { eligibilityBand } from './eligibility-band.js'\nimport { fieldType, regionName, unmappedElement } from './facts.js'\nimport { punchItem } from './punch-item.js'\n\nexport const BUILTIN_KINDS: ReadonlyArray<KindSpec<any, any>> = [punchItem, eligibilityBand, fieldType, regionName, unmappedElement]\n","// ─── LLM provider (the last link) ───\n//\n// The link asked for what Jev does not answer. `createAnthropicProvider()`\n// (anthropic.ts) wires Claude Haiku; a host can wire its own model to the\n// kind's closed decision list instead. The default is a provider that is never\n// available, so no model is called unless the host opts in.\n\nimport type { DecisionProvider } from './types.js'\n\nexport const noopLlmProvider: DecisionProvider = {\n name: 'llm',\n available: () => false,\n ask: async () => {\n throw new Error('no LLM provider is configured')\n },\n}\n","// ─── The decider ───\n//\n// rule → cache → jev → llm → the rule's tentative answer.\n//\n// A final rule answer ends the chain before any lookup. Anything else is looked\n// up in the cache, then asked of each available provider in turn, in batches.\n// A provider that is off, over budget, behind an open circuit, slow or broken\n// never fails the call: its items move on down the chain and, at the end, take\n// the rule's tentative answer marked `unreviewed`.\n\nimport { type AuditSink, toAuditRecord } from './audit.js'\nimport { type BatchLimits, estimateTokens, planBatches } from './batch.js'\nimport type { DecisionBudget } from './budget.js'\nimport { CircuitBreaker } from './budget.js'\nimport { type CachedDecision, type DecisionCache, MemoryDecisionCache, cacheKey } from './cache.js'\nimport { DEFAULT_JEV_MODEL, buildJevRequest, createJevProvider, requestShapeHash } from './jev.js'\nimport { BUILTIN_KINDS } from './kinds/index.js'\nimport { noopLlmProvider } from './llm.js'\nimport type { Decision, DecisionProvider, FallbackReason, KindSpec, Outcome, RuleVerdict } from './types.js'\n\nexport interface Pricing {\n /** USD per million input tokens. */\n inputPerMTok: number\n /** USD per million output tokens. */\n outputPerMTok: number\n}\n\nexport interface DeciderConfig {\n /** Kinds this decider answers. Default: the built-in kinds. */\n kinds?: ReadonlyArray<KindSpec<any, any>>\n /** Default: Jev over `process.env`; `false` turns it off. */\n jev?: DecisionProvider | false\n /** Asked for what Jev does not answer. Default: `noopLlmProvider`; `createAnthropicProvider()` wires Claude Haiku. */\n llm?: DecisionProvider\n /** Default: an in-memory cache for this decider's lifetime. */\n cache?: DecisionCache\n audit?: AuditSink\n /** Absent: no cap. */\n budget?: DecisionBudget\n /** One per provider. Default: 3 failures, 60s cooldown. */\n breakers?: Partial<Record<'jev' | 'llm', CircuitBreaker>>\n batch?: BatchLimits\n /** Price per provider. Without one, that provider's `cost.usd` is left out; Jev's vendor publishes no price. */\n pricing?: Partial<Record<'jev' | 'llm', Pricing>>\n now?: () => Date\n}\n\nexport interface DecideOptions<I = unknown> {\n /** Budget and audit tenant. Default `default`. */\n tenant?: string\n /** Replace the kind's rule, e.g. with the host's own verdict function. `null` asks no rule. */\n rule?: ((input: I) => RuleVerdict | undefined) | null\n /** Skip the cache lookup and do not store the answer. */\n noCache?: boolean\n /**\n * Ask a repeated input once (default). `false` asks every input as its own\n * item, in the caller's order — what reproducing a calibrated request needs,\n * since folding renumbers the items a request carries.\n */\n fold?: boolean\n}\n\nexport interface Decider {\n decide: <I>(kind: string, input: I, options?: DecideOptions<I>) => Promise<Decision>\n decideMany: <I>(kind: string, inputs: readonly I[], options?: DecideOptions<I>) => Promise<Decision[]>\n kinds: () => string[]\n}\n\ninterface Pending {\n /** Positions in the caller's input list this item answers. */\n at: number[]\n /** Unique within one call: the cache key, or the key and position when not folding. */\n id: string\n key: string\n shaped: unknown\n rule: RuleVerdict | undefined\n}\n\nfunction validOutcome(spec: KindSpec<any, any>, outcome: Outcome | undefined): outcome is Outcome {\n if (!outcome) return false\n if (outcome.choice !== undefined && spec.choices && !spec.choices.includes(outcome.choice)) return false\n if (outcome.score !== undefined && spec.scoreRange && (outcome.score < spec.scoreRange[0] || outcome.score > spec.scoreRange[1])) return false\n return Number.isFinite(outcome.confidence)\n}\n\nfunction fromOutcome(spec: KindSpec<any, any>, key: string, shape: string, outcome: Outcome, source: Decision['source'], ms: number): Decision {\n const decision: Decision = { kind: spec.kind, version: spec.version, key, shape, confidence: outcome.confidence, source, ms }\n if (outcome.choice !== undefined) decision.choice = outcome.choice\n if (outcome.score !== undefined) decision.score = outcome.score\n if (outcome.probabilities) decision.probabilities = outcome.probabilities\n return decision\n}\n\n/** A provider answer under the kind's confidence floor becomes the kind's human-review choice. */\nfunction applyFloor(spec: KindSpec<any, any>, decision: Decision): Decision {\n const floor = spec.lowConfidence\n if (!floor || decision.choice === undefined || decision.confidence >= floor.threshold) return decision\n return { ...decision, proposed: decision.choice, choice: floor.choice }\n}\n\nfunction fallback(spec: KindSpec<any, any>, item: Pending, shape: string, reason: FallbackReason, ms: number): Decision {\n const base = item.rule\n ? fromOutcome(spec, item.key, shape, item.rule, 'rule', ms)\n : { kind: spec.kind, version: spec.version, key: item.key, shape, confidence: 0, source: 'rule' as const, ms }\n return { ...base, unreviewed: true, fallback: reason }\n}\n\nfunction fromCache(cached: CachedDecision, key: string, ms: number): Decision {\n const { at: _at, source: _source, ...rest } = cached\n return { ...rest, key, source: 'cache', ms }\n}\n\nfunction toCached(decision: Decision, source: 'jev' | 'llm', at: string): CachedDecision {\n const cached: CachedDecision = { kind: decision.kind, version: decision.version, shape: decision.shape, confidence: decision.confidence, source, at }\n for (const field of ['choice', 'score', 'probabilities', 'proposed', 'model'] as const) {\n if (decision[field] !== undefined) Object.assign(cached, { [field]: decision[field] })\n }\n return cached\n}\n\n/** Split `total` into `parts` integers that sum to it. */\nfunction share(total: number, parts: number, index: number): number {\n const base = Math.floor(total / parts)\n return base + (index < total - base * parts ? 1 : 0)\n}\n\nexport function createDecider(config: DeciderConfig = {}): Decider {\n const kinds = new Map((config.kinds ?? BUILTIN_KINDS).map(spec => [spec.kind, spec]))\n const cache = config.cache ?? new MemoryDecisionCache()\n const now = config.now ?? (() => new Date())\n const providers: DecisionProvider[] = []\n if (config.jev !== false) providers.push(config.jev ?? createJevProvider())\n providers.push(config.llm ?? noopLlmProvider)\n const breakers = new Map<string, CircuitBreaker>(providers.map(p => [p.name, config.breakers?.[p.name] ?? new CircuitBreaker()]))\n // The request shape a kind's answers are keyed under: the Jev prompt as the configured Jev provider would send it.\n const jevModel = providers.find(p => p.name === 'jev')?.model ?? DEFAULT_JEV_MODEL\n const shapes = new Map<string, string>()\n const shapeOf = (spec: KindSpec<any, any>): string => {\n let shape = shapes.get(spec.kind)\n if (shape === undefined) shapes.set(spec.kind, shape = requestShapeHash(spec, jevModel))\n return shape\n }\n\n function cost(provider: 'jev' | 'llm', usage: { input_tokens: number, output_tokens: number } | undefined, parts: number, index: number): Decision['cost'] {\n if (!usage) return undefined\n const input_tokens = share(usage.input_tokens, parts, index)\n const output_tokens = share(usage.output_tokens, parts, index)\n const price = config.pricing?.[provider]\n const usd = price\n ? (input_tokens * price.inputPerMTok + output_tokens * price.outputPerMTok) / 1e6\n : undefined\n return usd === undefined ? { input_tokens, output_tokens } : { input_tokens, output_tokens, usd }\n }\n\n /** Ask one provider about `items`; answered items are returned by key, the rest keep their reason to fall back. */\n async function ask(provider: DecisionProvider, spec: KindSpec<any, any>, shape: string, items: Pending[], tenant: string): Promise<{ answered: Map<string, Decision>, reasons: Map<string, FallbackReason> }> {\n const answered = new Map<string, Decision>()\n const reasons = new Map<string, FallbackReason>()\n const breaker = breakers.get(provider.name)!\n if (!provider.available() || (provider.name === 'jev' && !spec.jev)) {\n for (const item of items) reasons.set(item.id, 'no_provider')\n return { answered, reasons }\n }\n // Items of different groups never share a request; within a group, the\n // kind's calibrated batch limits win over the decider's.\n const groups = new Map<string, Pending[]>()\n for (const item of items) {\n const group = spec.jev?.group?.(item.shaped) ?? ''\n groups.set(group, [...(groups.get(group) ?? []), item])\n }\n const batches: Pending[][] = []\n for (const members of groups.values()) {\n const fixed = spec.jev?.header ? estimateTokens(spec.jev.header(members[0]!.shaped)) : 0\n const costs = members.map(item => Math.max(1, estimateTokens(JSON.stringify(buildJevRequestFor(spec, item.shaped))) - fixed))\n for (const batch of planBatches(costs, fixed, spec.jev?.batch ?? config.batch)) batches.push(batch.map(i => members[i]!))\n }\n for (const batch of batches) {\n // The breaker first: a request that never goes out spends no budget,\n // so an outage upstream does not drain the cap the next provider needs.\n if (!breaker.allows()) {\n for (const item of batch) reasons.set(item.id, 'circuit_open')\n continue\n }\n let members = batch\n if (config.budget) {\n const granted = await config.budget.take(tenant, batch.length, now())\n members = batch.slice(0, granted)\n for (const item of batch.slice(granted)) reasons.set(item.id, 'budget')\n }\n if (!members.length) continue\n const started = performance.now()\n try {\n const answer = await provider.ask(spec, members.map(item => item.shaped))\n breaker.success()\n const ms = Math.round(performance.now() - started)\n members.forEach((item, i) => {\n const outcome = answer.outcomes[i]\n if (!validOutcome(spec, outcome)) {\n reasons.set(item.id, 'no_answer')\n return\n }\n const decision = fromOutcome(spec, item.key, shape, outcome, provider.name, ms)\n const spent = cost(provider.name, answer.usage, members.length, i)\n if (spent) decision.cost = spent\n if (answer.model) decision.model = answer.model\n answered.set(item.id, applyFloor(spec, decision))\n })\n }\n catch (error) {\n breaker.failure()\n const reason: FallbackReason = (error as { timeout?: unknown } | null)?.timeout === true ? 'timeout' : 'error'\n for (const item of members) reasons.set(item.id, reason)\n }\n }\n return { answered, reasons }\n }\n\n async function decideMany<I>(kind: string, inputs: readonly I[], options: DecideOptions<I> = {}): Promise<Decision[]> {\n const spec = kinds.get(kind) as KindSpec<I, unknown> | undefined\n if (!spec) throw new TypeError(`unknown decision kind: ${kind} (known: ${[...kinds.keys()].join(', ')})`)\n const tenant = options.tenant ?? 'default'\n const shape = shapeOf(spec)\n const fold = options.fold ?? true\n const rule = options.rule === null ? undefined : (options.rule ?? spec.rule)\n const results: Decision[] = Array.from({ length: inputs.length })\n\n // Shape, rule, and fold duplicate inputs into one pending item.\n const pending = new Map<string, Pending>()\n inputs.forEach((input, i) => {\n const started = performance.now()\n const shaped = spec.shape(input)\n const key = cacheKey(spec.kind, spec.version, shape, shaped)\n const verdict = rule?.(input)\n const valid = verdict && validOutcome(spec, verdict) ? verdict : undefined\n if (valid?.final) {\n results[i] = fromOutcome(spec, key, shape, valid, 'rule', Math.round(performance.now() - started))\n return\n }\n const id = fold ? key : `${key}#${i}`\n const existing = pending.get(id)\n if (existing) existing.at.push(i)\n else pending.set(id, { at: [i], id, key, shaped, rule: valid })\n })\n\n let open = [...pending.values()]\n if (!options.noCache) {\n const started = performance.now()\n const hits = await Promise.all(open.map(item => cache.get(item.key)))\n const ms = Math.round(performance.now() - started)\n open = open.filter((item, i) => {\n const hit = hits[i]\n if (hit?.kind !== spec.kind || hit.version !== spec.version || hit.shape !== shape) return true\n for (const at of item.at) results[at] = fromCache(hit, item.key, ms)\n return false\n })\n }\n\n const lastReason = new Map<string, FallbackReason>()\n for (const provider of providers) {\n if (!open.length) break\n const { answered, reasons } = await ask(provider, spec, shape, open, tenant)\n for (const [id, decision] of answered) {\n const item = pending.get(id)!\n for (const at of item.at) results[at] = decision\n if (!options.noCache) await cache.set(item.key, toCached(decision, provider.name, now().toISOString()))\n }\n // A reason from a provider that was actually tried beats \"not configured\" from one after it.\n for (const [id, reason] of reasons) {\n if (reason !== 'no_provider' || !lastReason.has(id)) lastReason.set(id, reason)\n }\n open = open.filter(item => !answered.has(item.id))\n }\n for (const item of open) {\n const decision = fallback(spec, item, shape, lastReason.get(item.id) ?? 'no_provider', 0)\n for (const at of item.at) results[at] = decision\n }\n\n if (config.audit) {\n const at = now().toISOString()\n await config.audit.write(results.map(decision => toAuditRecord(decision, at, tenant)))\n }\n return results\n }\n\n return {\n decideMany,\n decide: async (kind, input, options) => (await decideMany(kind, [input], options))[0]!,\n kinds: () => [...kinds.keys()],\n }\n}\n\nfunction buildJevRequestFor(spec: KindSpec<any, any>, shaped: unknown): unknown {\n return spec.jev ? buildJevRequest(spec, [shaped]) : shaped\n}\n\nlet defaultDecider: Decider | undefined\n\n/**\n * Decide with the default decider: built-in kinds, Jev when\n * `CONTENTRAIN_JEW_API_TOKEN` is set, an in-memory cache, no budget, no audit\n * log. Build your own with `createDecider` for anything else.\n */\nexport function decide<I>(kind: string, input: I, options?: DecideOptions<I>): Promise<Decision> {\n defaultDecider ??= createDecider()\n return defaultDecider.decide(kind, input, options)\n}\n","// ─── Anthropic provider (Claude Haiku, the LLM link of the chain) ───\n//\n// Asked when Jev does not answer: Jev off, its circuit open, a timeout, an\n// error. The same rules hold here as in jev.ts:\n// - The API key comes from the environment, read at the moment of each\n// request and passed straight into the header. It is never stored on an\n// object, returned, logged or put in an error message.\n// - Requests go to one fixed endpoint. There is no base-URL option.\n// - The request carries only what the kind's shaper and renderer produced:\n// the state and questions Jev gets, as a prompt, answered through one\n// forced tool call so the answer is structured, not parsed from prose.\n//\n// A model reports no confidence of its own. Its answers carry confidence 0,\n// meaning \"not measured\": a kind with a confidence floor (eligibility_band)\n// keeps the model's pick as `proposed` and asks a human.\n\nimport { createHash } from 'node:crypto'\nimport { canonicalStringify } from '@contentrain/types'\nimport { buildJevRequest } from './jev.js'\nimport type { DecisionProvider, JevAnswer, JevQuestion, KindSpec, Outcome, ProviderAnswer } from './types.js'\n\nexport const ANTHROPIC_ENDPOINT = 'https://api.anthropic.com/v1/messages'\nexport const ANTHROPIC_KEY_ENV = 'ANTHROPIC_API_KEY'\nexport const DEFAULT_ANTHROPIC_MODEL = 'claude-haiku-4-5-20251001'\nconst ANTHROPIC_VERSION = '2023-06-01'\nconst MAX_TOKENS = 4096\nconst TOOL_NAME = 'record_answers'\n\nexport interface AnthropicProviderOptions {\n /** Where the key is read from. Default `process.env`. */\n env?: Readonly<Record<string, string | undefined>>\n /** Injected for tests. The URL it is called with is always `ANTHROPIC_ENDPOINT`. */\n fetch?: typeof globalThis.fetch\n /** Per request. Default 60s. */\n timeoutMs?: number\n /** Default `claude-haiku-4-5-20251001`, asked at temperature 0. */\n model?: string\n}\n\nexport class AnthropicError extends Error {\n constructor(message: string, readonly status: number | undefined, readonly timeout = false) {\n super(message)\n this.name = 'AnthropicError'\n }\n}\n\ntype Questions = Record<string, JevQuestion>\n\nconst itemN = (text: string) => text.replace(/\\bitem1\\b/g, 'itemN')\n\n/** The prompt for a kind without its own `llmPrompt`: the state, then every question with its options or rubric. */\nexport function genericLlmPrompt({ state, questions, count }: { state: string, questions: Questions, count: number }): string {\n const lines = ['<state>', state, '</state>', '', 'Answer these questions for every item (itemN stands for the item\\'s number):']\n Object.entries(questions).forEach(([suffix, question], n) => {\n if (question.type === 'choice') {\n lines.push(`${n + 1}) ${suffix} — ${itemN(question.instructions)} Options:`)\n for (const [choice, meaning] of Object.entries(question.criteria)) lines.push(` - ${choice}: ${meaning}`)\n }\n else if (question.type === 'score') {\n lines.push(`${n + 1}) ${suffix} — ${itemN(question.instructions)} An integer from 0 to ${question.criteria.length - 1}:`)\n question.criteria.forEach((meaning, level) => lines.push(` ${level}: ${meaning}`))\n }\n else {\n lines.push(`${n + 1}) ${suffix} — the probability (0–1) that this statement is true: ${itemN(question.instructions)}`)\n }\n })\n lines.push('', `Give all ${count} items through the ${TOOL_NAME} tool, one record per item.`)\n return lines.join('\\n')\n}\n\n/** The forced tool the model answers through: one record per item, one field per question. */\nfunction answerTool(questions: Questions) {\n const properties: Record<string, unknown> = { item: { type: 'integer' } }\n for (const [suffix, question] of Object.entries(questions)) {\n properties[suffix] = question.type === 'choice'\n ? { type: 'string', enum: Object.keys(question.criteria) }\n : question.type === 'score'\n ? { type: 'integer', minimum: 0, maximum: question.criteria.length - 1 }\n : { type: 'number', minimum: 0, maximum: 1 }\n }\n return {\n name: TOOL_NAME,\n description: 'Record the answers for every item.',\n input_schema: {\n type: 'object',\n properties: {\n items: { type: 'array', items: { type: 'object', properties, required: Object.keys(properties) } },\n },\n required: ['items'],\n },\n }\n}\n\n/** The Messages API body one batch sends. */\nexport function buildAnthropicRequest(spec: KindSpec<any, any>, shaped: readonly unknown[], model = DEFAULT_ANTHROPIC_MODEL) {\n const jev = spec.jev\n if (!jev) throw new TypeError(`kind ${spec.kind} has no prompt`)\n const { state } = buildJevRequest(spec, shaped)\n const questions = jev.questions('item1')\n const prompt = (jev.llmPrompt ?? genericLlmPrompt)({ state, questions, count: shaped.length })\n return {\n model,\n max_tokens: MAX_TOKENS,\n temperature: 0,\n tools: [answerTool(questions)],\n tool_choice: { type: 'tool', name: TOOL_NAME },\n messages: [{ role: 'user', content: prompt }],\n }\n}\n\n/** Hash of the LLM request shape (model, prompt, tool), recorded by a calibration of this provider. */\nexport function anthropicRequestShapeHash(spec: KindSpec<any, any>, model = DEFAULT_ANTHROPIC_MODEL): string {\n if (!spec.jev) return 'none'\n const request = buildAnthropicRequest(spec, [spec.jev.probe, spec.jev.probe], model)\n return createHash('sha256').update(canonicalStringify(request)).digest('hex').slice(0, 16)\n}\n\nexport function createAnthropicProvider(options: AnthropicProviderOptions = {}): DecisionProvider {\n const env = options.env ?? process.env\n const doFetch = options.fetch ?? globalThis.fetch\n const timeoutMs = options.timeoutMs ?? 60_000\n const model = options.model ?? DEFAULT_ANTHROPIC_MODEL\n\n return {\n name: 'llm',\n model,\n available: () => Boolean(env[ANTHROPIC_KEY_ENV]?.trim()),\n async ask(spec, shaped) {\n const key = env[ANTHROPIC_KEY_ENV]?.trim()\n if (!key) throw new AnthropicError(`${ANTHROPIC_KEY_ENV} is not set`, undefined)\n const request = buildAnthropicRequest(spec, shaped, model)\n let response: Response\n try {\n response = await doFetch(ANTHROPIC_ENDPOINT, {\n method: 'POST',\n headers: { 'x-api-key': key, 'anthropic-version': ANTHROPIC_VERSION, 'content-type': 'application/json' },\n body: JSON.stringify(request),\n signal: AbortSignal.timeout(timeoutMs),\n })\n }\n catch (error) {\n const name = (error as { name?: string }).name\n if (name === 'TimeoutError' || name === 'AbortError') throw new AnthropicError(`Anthropic did not answer within ${timeoutMs}ms`, undefined, true)\n throw new AnthropicError(`Anthropic request failed: ${redact(String((error as Error).message ?? error), key)}`, undefined)\n }\n const text = await response.text()\n if (!response.ok) throw new AnthropicError(`Anthropic answered HTTP ${response.status}: ${redact(text.slice(0, 200), key)}`, response.status)\n let body: unknown\n try {\n body = JSON.parse(text)\n }\n catch {\n throw new AnthropicError('Anthropic answered with a body that is not JSON', response.status)\n }\n return readAnthropicResponse(spec, shaped.length, body)\n },\n }\n}\n\n/** Per-item outcomes from a Messages API response. An item whose record is missing or malformed gets `undefined`. */\nexport function readAnthropicResponse(spec: KindSpec<any, any>, count: number, body: unknown): ProviderAnswer {\n const jev = spec.jev!\n const questions = jev.questions('item1')\n const root = (body && typeof body === 'object' ? body : {}) as { content?: unknown, usage?: unknown, model?: unknown }\n const content = Array.isArray(root.content) ? root.content as Array<Record<string, unknown>> : []\n const call = content.find(block => block?.type === 'tool_use' && block.name === TOOL_NAME)\n const input = (call?.input && typeof call.input === 'object' ? call.input : {}) as { items?: unknown }\n const records = Array.isArray(input.items) ? input.items as Array<Record<string, unknown>> : []\n\n const outcomes: Array<Outcome | undefined> = []\n for (let i = 1; i <= count; i++) {\n const record = records.find(r => r && typeof r === 'object' && r.item === i)\n const own: Record<string, JevAnswer> = {}\n let complete = Boolean(record)\n for (const [suffix, question] of Object.entries(questions)) {\n const answer = record ? readField(question, record[suffix]) : undefined\n if (!answer) complete = false\n else own[suffix] = answer\n }\n outcomes.push(complete ? jev.read(own) : undefined)\n }\n const usage = root.usage as { input_tokens?: unknown, output_tokens?: unknown } | undefined\n return {\n outcomes,\n ...(usage && typeof usage.input_tokens === 'number' && typeof usage.output_tokens === 'number'\n ? { usage: { input_tokens: usage.input_tokens, output_tokens: usage.output_tokens } }\n : {}),\n ...(typeof root.model === 'string' ? { model: root.model } : {}),\n }\n}\n\nfunction readField(question: JevQuestion, value: unknown): JevAnswer | undefined {\n if (question.type === 'choice')\n return typeof value === 'string' && Object.hasOwn(question.criteria, value) ? { type: 'choice', choice: value, confidence: 0 } : undefined\n if (question.type === 'score')\n return Number.isInteger(value) && (value as number) >= 0 && (value as number) < question.criteria.length ? { type: 'score', score: value as number, confidence: 0 } : undefined\n return typeof value === 'number' && value >= 0 && value <= 1 ? { type: 'noul', noul: value } : undefined\n}\n\nfunction redact(text: string, key: string): string {\n return text.split(key).join('[redacted]')\n}\n","// ─── Calibration ───\n//\n// A kind is trusted only as far as a live run has measured it against hand\n// labels. The measurement is `pnpm calibration:live`, which writes\n// `calibration/<date>.json` with the model and the request-shape hash it\n// measured; the numbers in the docs are that file's. Two tools here:\n// - `measurePunchCalibration` scores punch_item decisions against labels\n// the way PoC-1 did: exact class, severity within one level.\n// - `createReplayFetch` answers requests from recorded answers — a smoke\n// test of the code path, not a measurement.\n\nimport { buildJevRequest } from './jev.js'\nimport { severityLevel } from './kinds/punch-item.js'\nimport type { Decision, JevAnswer, KindSpec } from './types.js'\n\nexport interface RecordedCase<I> {\n input: I\n /** The item's answers, keyed by the kind's question suffixes. */\n answers: Record<string, JevAnswer>\n}\n\n/** A request's header and one item line, as a replay key. */\nfunction replayKey(state: string, line: string): string {\n const first = state.search(/^Item 1: /m)\n return `${first > 0 ? state.slice(0, first) : ''}\\u0000${line}`\n}\n\n/**\n * A `fetch` that answers systemone requests for `spec` from recorded answers,\n * matching each item by its request header and its rendered line. An item\n * with no recording gets no answers, which the decider treats as `no_answer`.\n * `calls` counts requests.\n *\n * A replay re-reads the answers a model gave once. It checks the code path —\n * shaping, grouping, batching, reading — and says nothing about how the model\n * answers today; only a live run does.\n */\nexport function createReplayFetch<I>(spec: KindSpec<I, any>, cases: ReadonlyArray<RecordedCase<I>>, model = 'replay'): typeof globalThis.fetch & { calls: number } {\n const byKey = new Map<string, Record<string, JevAnswer>>()\n for (const recorded of cases) {\n const { state } = buildJevRequest(spec, [spec.shape(recorded.input)])\n const line = /^Item 1: (.*)$/m.exec(state)![1]!\n byKey.set(replayKey(state, line), recorded.answers)\n }\n const replay = async (_url: string | URL | Request, init?: RequestInit): Promise<Response> => {\n replay.calls++\n const { state } = JSON.parse(String(init?.body)) as { state: string }\n const answers: Record<string, JevAnswer> = {}\n for (const line of state.split('\\n')) {\n const match = /^Item (\\d+): (.*)$/.exec(line)\n const recorded = match ? byKey.get(replayKey(state, match[2]!)) : undefined\n if (!recorded) continue\n for (const [suffix, answer] of Object.entries(recorded)) answers[`item${match![1]}_${suffix}`] = answer\n }\n return new Response(JSON.stringify({ model, answers }), { status: 200, headers: { 'Content-Type': 'application/json' } })\n }\n replay.calls = 0\n return replay as typeof globalThis.fetch & { calls: number }\n}\n\nexport interface PunchLabel {\n class: string\n /** 1–4. */\n severity: number\n}\n\nexport interface PunchCalibration {\n total: number\n answered: number\n classMatch: number\n severityWithin1: number\n classRate: number\n severityRate: number\n misses: Array<{ index: number, expected: PunchLabel, choice?: string, level?: number }>\n}\n\n/** Exact class and severity within one level, over every label (an unanswered item counts as a miss). */\nexport function measurePunchCalibration(labels: readonly PunchLabel[], decisions: readonly Decision[]): PunchCalibration {\n let answered = 0\n let classMatch = 0\n let severityWithin1 = 0\n const misses: PunchCalibration['misses'] = []\n labels.forEach((expected, index) => {\n const decision = decisions[index]\n if (decision?.choice === undefined || decision.score === undefined || decision.unreviewed) {\n misses.push({ index, expected })\n return\n }\n answered++\n const level = severityLevel(decision.score)\n const classOk = decision.choice === expected.class\n const severityOk = Math.abs(level - expected.severity) <= 1\n if (classOk) classMatch++\n if (severityOk) severityWithin1++\n if (!classOk || !severityOk) misses.push({ index, expected, choice: decision.choice, level })\n })\n const total = labels.length\n return {\n total,\n answered,\n classMatch,\n severityWithin1,\n classRate: total ? classMatch / total : 0,\n severityRate: total ? severityWithin1 / total : 0,\n misses,\n }\n}\n\n/** Whether repeated runs over the same inputs chose the same class for every item. */\nexport function stableChoices(runs: ReadonlyArray<readonly Decision[]>): { stable: number, total: number } {\n const total = runs[0]?.length ?? 0\n let stable = 0\n for (let i = 0; i < total; i++) {\n const choices = new Set(runs.map(run => run[i]?.choice))\n if (choices.size === 1 && !choices.has(undefined)) stable++\n }\n return { stable, total }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["redact","certain","tentative"],"sources":["../src/audit.ts","../src/batch.ts","../src/budget.ts","../src/cache.ts","../src/jev.ts","../src/kinds/shape.ts","../src/kinds/eligibility-band.ts","../src/kinds/facts.ts","../src/kinds/punch-item.ts","../src/kinds/index.ts","../src/llm.ts","../src/decide.ts","../src/anthropic.ts","../src/calibration.ts"],"sourcesContent":["// ─── Audit log ───\n//\n// One record per decision, whatever answered it: `decisions.jsonl`. It keeps\n// the input's hash and never the input, so the log can be kept and shared\n// without carrying what was decided about.\n\nimport { appendFile, mkdir } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport type { Decision, DecisionSource, FallbackReason } from './types.js'\n\nexport interface AuditRecord {\n /** ISO time the decision was made. */\n at: string\n tenant: string\n kind: string\n version: string\n /** The input hash — the same value as the cache key. */\n key: string\n /** The provider request shape the decision was keyed under. */\n shape: string\n choice?: string\n score?: number\n confidence: number\n source: DecisionSource\n proposed?: string\n unreviewed?: true\n fallback?: FallbackReason\n ms: number\n model?: string\n input_tokens?: number\n output_tokens?: number\n usd?: number\n}\n\nexport interface AuditSink {\n write: (records: readonly AuditRecord[]) => Promise<void>\n}\n\nexport function toAuditRecord(decision: Decision, at: string, tenant: string): AuditRecord {\n const record: AuditRecord = {\n at,\n tenant,\n kind: decision.kind,\n version: decision.version,\n key: decision.key,\n shape: decision.shape,\n confidence: decision.confidence,\n source: decision.source,\n ms: decision.ms,\n }\n if (decision.choice !== undefined) record.choice = decision.choice\n if (decision.score !== undefined) record.score = decision.score\n if (decision.proposed !== undefined) record.proposed = decision.proposed\n if (decision.unreviewed) record.unreviewed = true\n if (decision.fallback) record.fallback = decision.fallback\n if (decision.model) record.model = decision.model\n if (decision.cost) {\n record.input_tokens = decision.cost.input_tokens\n record.output_tokens = decision.cost.output_tokens\n if (decision.cost.usd !== undefined) record.usd = decision.cost.usd\n }\n return record\n}\n\nexport class MemoryAuditLog implements AuditSink {\n readonly records: AuditRecord[] = []\n\n async write(records: readonly AuditRecord[]): Promise<void> {\n this.records.push(...records)\n }\n}\n\n/** Appends to a JSONL file (conventionally `decisions.jsonl`), one line per decision. */\nexport class JsonlAuditLog implements AuditSink {\n constructor(readonly path: string) {}\n\n async write(records: readonly AuditRecord[]): Promise<void> {\n if (!records.length) return\n await mkdir(dirname(this.path), { recursive: true })\n await appendFile(this.path, records.map(record => `${JSON.stringify(record)}\\n`).join(''))\n }\n}\n","// ─── Batching ───\n//\n// Items of one kind share a request: the PoC measured 1.39x fewer input\n// tokens and ~4x less wall time than one request per item. A batch holds at\n// most `maxItems` items (default 32, inside the 20–40 band) and stays under\n// `maxTokens` (default 32k) by a conservative estimate — three characters a\n// token, which over-counts English and roughly matches Turkish.\n\nexport interface BatchLimits {\n maxItems?: number\n maxTokens?: number\n}\n\nexport const DEFAULT_BATCH: Required<BatchLimits> = { maxItems: 32, maxTokens: 32_000 }\n\nexport const estimateTokens = (text: string): number => Math.ceil(text.length / 3)\n\n/**\n * Split item costs into consecutive batches. `fixed` is what every request\n * pays once (the preamble); `costs[i]` what item i adds (its line and its\n * questions). An item too large for any batch goes alone.\n */\nexport function planBatches(costs: readonly number[], fixed: number, limits: BatchLimits = {}): number[][] {\n const maxItems = limits.maxItems ?? DEFAULT_BATCH.maxItems\n const maxTokens = limits.maxTokens ?? DEFAULT_BATCH.maxTokens\n if (!Number.isInteger(maxItems) || maxItems < 1) throw new RangeError(`maxItems must be a positive integer, got ${maxItems}`)\n const batches: number[][] = []\n let current: number[] = []\n let tokens = fixed\n costs.forEach((cost, i) => {\n if (current.length && (current.length >= maxItems || tokens + cost > maxTokens)) {\n batches.push(current)\n current = []\n tokens = fixed\n }\n current.push(i)\n tokens += cost\n })\n if (current.length) batches.push(current)\n return batches\n}\n","// ─── Budget cap and circuit breaker ───\n//\n// Neither ever fails a decision. Over the cap, or with the breaker open, the\n// decider answers from the rule and marks the decision `unreviewed`.\n\n/** How many provider decisions a tenant may spend. */\nexport interface DecisionBudget {\n /** Reserve up to `count` decisions for `tenant` at `now`; returns how many were granted. */\n take: (tenant: string, count: number, now: Date) => Promise<number>\n}\n\n/** A per-tenant cap on provider decisions per UTC day, held in memory. */\nexport class MemoryDailyBudget implements DecisionBudget {\n private readonly spent = new Map<string, number>()\n\n constructor(readonly perDay: number) {\n if (!Number.isInteger(perDay) || perDay < 0) throw new RangeError(`perDay must be a non-negative integer, got ${perDay}`)\n }\n\n async take(tenant: string, count: number, now: Date): Promise<number> {\n const slot = `${tenant}\\n${now.toISOString().slice(0, 10)}`\n const used = this.spent.get(slot) ?? 0\n const granted = Math.max(0, Math.min(count, this.perDay - used))\n this.spent.set(slot, used + granted)\n return granted\n }\n\n used(tenant: string, now: Date): number {\n return this.spent.get(`${tenant}\\n${now.toISOString().slice(0, 10)}`) ?? 0\n }\n}\n\nexport interface CircuitBreakerOptions {\n /** Consecutive failed requests that open the circuit. Default 3. */\n failures?: number\n /** How long it stays open before one request is let through. Default 60s. */\n cooldownMs?: number\n now?: () => number\n}\n\n/**\n * Closed → open after `failures` consecutive failed requests; open → half-open\n * after `cooldownMs`, where the next request decides: success closes it, a\n * failure opens it for another cooldown.\n */\nexport class CircuitBreaker {\n private consecutive = 0\n private openedAt: number | undefined\n private readonly limit: number\n private readonly cooldownMs: number\n private readonly now: () => number\n\n constructor(options: CircuitBreakerOptions = {}) {\n this.limit = options.failures ?? 3\n this.cooldownMs = options.cooldownMs ?? 60_000\n this.now = options.now ?? Date.now\n }\n\n get state(): 'closed' | 'open' | 'half_open' {\n if (this.openedAt === undefined) return 'closed'\n return this.now() - this.openedAt >= this.cooldownMs ? 'half_open' : 'open'\n }\n\n /** Whether a request may go out now. */\n allows(): boolean {\n return this.state !== 'open'\n }\n\n success(): void {\n this.consecutive = 0\n this.openedAt = undefined\n }\n\n failure(): void {\n this.consecutive++\n if (this.openedAt !== undefined || this.consecutive >= this.limit) this.openedAt = this.now()\n }\n}\n","// ─── Decision cache ───\n//\n// A provider is asked about the same input once. The key is\n// sha256(kind, schema version, request shape, canonical shaped input): the same\n// shaped input under the same schema and the same provider request always maps\n// to the same entry, and a schema bump or a changed request shape\n// (`requestShapeHash`) retires every entry made under the old one. Only provider answers are\n// cached — a rule answer is free to recompute and a fallback is not a decision\n// anyone reviewed.\n//\n// The stores here are for a single process (memory) and for a run directory\n// (append-only JSONL). A database store is the host's: implement\n// `DecisionCache` over it.\n\nimport { createHash } from 'node:crypto'\nimport { appendFile, mkdir, readFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport { canonicalStringify } from '@contentrain/types'\nimport type { Decision } from './types.js'\n\n/** What a cache keeps of a decision: the answer, never the input. */\nexport type CachedDecision = Pick<Decision, 'kind' | 'version' | 'shape' | 'choice' | 'score' | 'confidence' | 'probabilities' | 'proposed' | 'model'> & {\n source: 'jev' | 'llm'\n /** ISO time the provider answered. */\n at: string\n}\n\nexport interface DecisionCache {\n get: (key: string) => Promise<CachedDecision | undefined>\n set: (key: string, value: CachedDecision) => Promise<void>\n}\n\nexport function cacheKey(kind: string, version: string, shape: string, shaped: unknown): string {\n return createHash('sha256').update(`${kind}\\n${version}\\n${shape}\\n${canonicalStringify(shaped)}`).digest('hex')\n}\n\nexport class MemoryDecisionCache implements DecisionCache {\n private readonly entries = new Map<string, CachedDecision>()\n\n get size(): number {\n return this.entries.size\n }\n\n async get(key: string): Promise<CachedDecision | undefined> {\n return this.entries.get(key)\n }\n\n async set(key: string, value: CachedDecision): Promise<void> {\n this.entries.set(key, value)\n }\n}\n\n/**\n * One `{\"key\",\"value\"}` line per answer, appended. Read once, on first use;\n * a later line for the same key wins. A torn last line (a crash mid-append) is\n * skipped rather than failing the run — the answer is asked for again.\n */\nexport class JsonlDecisionCache implements DecisionCache {\n private loaded: Promise<Map<string, CachedDecision>> | undefined\n\n constructor(readonly path: string) {}\n\n private load(): Promise<Map<string, CachedDecision>> {\n this.loaded ??= readFile(this.path, 'utf8').then(\n text => readCacheLines(text),\n (error: NodeJS.ErrnoException) => {\n if (error.code === 'ENOENT') return new Map<string, CachedDecision>()\n throw error\n },\n )\n return this.loaded\n }\n\n async get(key: string): Promise<CachedDecision | undefined> {\n return (await this.load()).get(key)\n }\n\n async set(key: string, value: CachedDecision): Promise<void> {\n const entries = await this.load()\n entries.set(key, value)\n await mkdir(dirname(this.path), { recursive: true })\n await appendFile(this.path, `${JSON.stringify({ key, value })}\\n`)\n }\n}\n\nfunction readCacheLines(text: string): Map<string, CachedDecision> {\n const entries = new Map<string, CachedDecision>()\n for (const line of text.split('\\n')) {\n if (!line.trim()) continue\n try {\n const { key, value } = JSON.parse(line) as { key?: unknown, value?: CachedDecision }\n if (typeof key === 'string' && value && typeof value === 'object') entries.set(key, value)\n }\n catch {\n // torn line — see the class comment\n }\n }\n return entries\n}\n","// ─── Jev provider (typesafe.ai systemone) ───\n//\n// The only network code in the package. Three rules hold here and nowhere\n// else needs to think about them:\n// - The bearer token comes from the environment, read at the moment of each\n// request and passed straight into the header. It is never stored on an\n// object, returned, logged or put in an error message.\n// - Requests go to one fixed endpoint. There is no base-URL option.\n// - The request carries only what the kind's shaper and renderer produced.\n\nimport { createHash } from 'node:crypto'\nimport { canonicalStringify } from '@contentrain/types'\nimport type { DecisionProvider, JevAnswer, JevQuestion, KindSpec, Outcome, ProviderAnswer } from './types.js'\n\nexport const JEV_ENDPOINT = 'https://api.typesafe.ai/v1/systemone'\nexport const JEV_TOKEN_ENV = 'CONTENTRAIN_JEW_API_TOKEN'\nexport const DEFAULT_JEV_MODEL = 'jev-latest'\n\nexport interface JevProviderOptions {\n /** Where the token is read from. Default `process.env`. */\n env?: Readonly<Record<string, string | undefined>>\n /** Injected for tests and recorded replays. The URL it is called with is always `JEV_ENDPOINT`. */\n fetch?: typeof globalThis.fetch\n /** Per request. Default 15s. */\n timeoutMs?: number\n /** Default `jev-latest`. Part of the request shape: a different model is a different cache. */\n model?: string\n}\n\nexport class JevError extends Error {\n constructor(message: string, readonly status: number | undefined, readonly timeout = false) {\n super(message)\n this.name = 'JevError'\n }\n}\n\n/**\n * The request one batch sends: the kind's header from the first item, then one\n * `Item <n>: ` line per item; every item's questions keyed `item<n>_<suffix>`.\n */\nexport function buildJevRequest(spec: KindSpec<any, any>, shaped: readonly unknown[]): { state: string, questions: Record<string, JevQuestion> } {\n const jev = spec.jev\n if (!jev) throw new TypeError(`kind ${spec.kind} has no Jev prompt`)\n const header = shaped.length && jev.header ? jev.header(shaped[0]) : ''\n const lines = shaped.map((item, i) => `Item ${i + 1}: ${jev.render(item)}`)\n const questions: Record<string, JevQuestion> = {}\n shaped.forEach((_, i) => {\n const prefix = `item${i + 1}`\n for (const [suffix, question] of Object.entries(jev.questions(prefix))) questions[`${prefix}_${suffix}`] = question\n })\n return { state: header + lines.join('\\n'), questions }\n}\n\n/**\n * Hash of everything that shapes a kind's provider request: the model, the\n * batch limits, whether items are grouped, and the request built from two\n * copies of the kind's probe (header, line format, questions, criteria). A\n * change to any of them changes the hash, and with it every cache key.\n */\nexport function requestShapeHash(spec: KindSpec<any, any>, model = DEFAULT_JEV_MODEL): string {\n const jev = spec.jev\n if (!jev) return 'none'\n const shape = {\n model,\n batch: jev.batch ?? null,\n grouped: Boolean(jev.group),\n request: buildJevRequest(spec, [jev.probe, jev.probe]),\n }\n return createHash('sha256').update(canonicalStringify(shape)).digest('hex').slice(0, 16)\n}\n\nexport function createJevProvider(options: JevProviderOptions = {}): DecisionProvider {\n const env = options.env ?? process.env\n const doFetch = options.fetch ?? globalThis.fetch\n const timeoutMs = options.timeoutMs ?? 15_000\n const model = options.model ?? DEFAULT_JEV_MODEL\n\n return {\n name: 'jev',\n model,\n available: () => Boolean(env[JEV_TOKEN_ENV]?.trim()),\n async ask(spec, shaped) {\n const token = env[JEV_TOKEN_ENV]?.trim()\n if (!token) throw new JevError(`${JEV_TOKEN_ENV} is not set`, undefined)\n const { state, questions } = buildJevRequest(spec, shaped)\n let response: Response\n try {\n response = await doFetch(JEV_ENDPOINT, {\n method: 'POST',\n headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },\n body: JSON.stringify({ state, model, questions }),\n signal: AbortSignal.timeout(timeoutMs),\n })\n }\n catch (error) {\n const name = (error as { name?: string }).name\n if (name === 'TimeoutError' || name === 'AbortError') throw new JevError(`Jev did not answer within ${timeoutMs}ms`, undefined, true)\n throw new JevError(`Jev request failed: ${redact(String((error as Error).message ?? error), token)}`, undefined)\n }\n const text = await response.text()\n if (!response.ok) throw new JevError(`Jev answered HTTP ${response.status}: ${redact(text.slice(0, 200), token)}`, response.status)\n let body: unknown\n try {\n body = JSON.parse(text)\n }\n catch {\n throw new JevError('Jev answered with a body that is not JSON', response.status)\n }\n return readJevResponse(spec, shaped.length, body)\n },\n }\n}\n\n/** Per-item outcomes from a systemone response. An item whose answers are missing or malformed gets `undefined`. */\nexport function readJevResponse(spec: KindSpec<any, any>, count: number, body: unknown): ProviderAnswer {\n const jev = spec.jev!\n const root = (body && typeof body === 'object' ? body : {}) as { answers?: unknown, usage?: unknown, model?: unknown }\n const answers = (root.answers && typeof root.answers === 'object' ? root.answers : {}) as Record<string, unknown>\n const outcomes: Array<Outcome | undefined> = []\n for (let i = 1; i <= count; i++) {\n const own: Record<string, JevAnswer> = {}\n let complete = true\n for (const suffix of Object.keys(jev.questions(`item${i}`))) {\n const answer = readAnswer(answers[`item${i}_${suffix}`])\n if (!answer) complete = false\n else own[suffix] = answer\n }\n outcomes.push(complete ? jev.read(own) : undefined)\n }\n const usage = root.usage as { input_tokens?: unknown, output_tokens?: unknown } | undefined\n return {\n outcomes,\n ...(usage && typeof usage.input_tokens === 'number' && typeof usage.output_tokens === 'number'\n ? { usage: { input_tokens: usage.input_tokens, output_tokens: usage.output_tokens } }\n : {}),\n ...(typeof root.model === 'string' ? { model: root.model } : {}),\n }\n}\n\nconst isUnit = (value: unknown): value is number => typeof value === 'number' && value >= 0 && value <= 1\n\nfunction readAnswer(value: unknown): JevAnswer | undefined {\n if (!value || typeof value !== 'object') return undefined\n const answer = value as Record<string, unknown>\n const probabilities = answer.probabilities && typeof answer.probabilities === 'object'\n ? { probabilities: answer.probabilities as Record<string, number> }\n : {}\n if (answer.type === 'choice' && typeof answer.choice === 'string' && isUnit(answer.confidence))\n return { type: 'choice', choice: answer.choice, confidence: answer.confidence, ...probabilities }\n if (answer.type === 'score' && typeof answer.score === 'number' && Number.isFinite(answer.score) && isUnit(answer.confidence))\n return { type: 'score', score: answer.score, confidence: answer.confidence, ...probabilities }\n if (answer.type === 'noul' && isUnit(answer.noul)) return { type: 'noul', noul: answer.noul }\n return undefined\n}\n\nfunction redact(text: string, token: string): string {\n return text.split(token).join('[redacted]')\n}\n","// ─── Shaping helpers ───\n//\n// What a shaper does to free text before it may leave the process: URLs,\n// e-mail addresses and root-relative paths become placeholders, whitespace\n// collapses, and the text is cut to a length the decision can use.\n\nconst URL = /\\b(?:https?|ftp):\\/\\/\\S+|\\bwww\\.\\S+/gi\nconst EMAIL = /[\\w.+-]+@[\\w-]+(?:\\.[\\w-]+)+/g\n// A root-relative path: a slash at the start or after a space/bracket/quote, then a segment.\nconst PATH = /(^|[\\s(\"'=])\\/[\\w.~%-]+(?:\\/[\\w.~%-]*)*/g\n\nexport function scrubText(text: string, max: number): string {\n const clean = text\n .replace(URL, '<url>')\n .replace(EMAIL, '<email>')\n .replace(PATH, '$1<path>')\n .replace(/\\s+/g, ' ')\n .trim()\n return clean.length > max ? `${clean.slice(0, max - 1)}…` : clean\n}\n\n/** A slug-like identifier (post-type name, family name): lower-case word characters and dashes only. */\nexport function scrubSlug(value: string, max = 40): string {\n return value.toLowerCase().replace(/[^a-z0-9_-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, max)\n}\n\n/** A finite number, or undefined. */\nexport function finite(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined\n}\n","// ─── eligibility_band: the undecided band of Migrate's eligibility verdict ───\n//\n// Migrate's `judgeEligibility` sorts a discovered site into eligible /\n// page_only / custom_type / access_blocked from public discovery counts. Most\n// sites are clear. Two bands are not, and those — only those — go to Jev:\n//\n// - posts and custom-type entries within a factor of two of each other: is\n// the content the posts, or the custom types?\n// - exactly one sampled post: a blog of one, or a brochure site with a stray\n// \"Hello world\"?\n//\n// The rule mirrors judgeEligibility's thresholds (MIN_POSTS = 2) so the clear\n// cases never reach a provider; a host with its own verdict function passes it\n// as `options.rule`. A Jev answer under 0.5 confidence becomes `needs_human`,\n// which is never offered to Jev as a choice.\n\nimport type { JevAnswer, JevQuestion, KindSpec, RuleVerdict } from '../types.js'\nimport { scrubSlug } from './shape.js'\n\nexport const ELIGIBILITY_CHOICES = ['eligible', 'access_blocked', 'page_only', 'custom_type'] as const\nexport type EligibilityChoice = typeof ELIGIBILITY_CHOICES[number]\nexport const NEEDS_HUMAN = 'needs_human'\n\n/** Migrate's `EligibilityInput`, as discovery produces it. */\nexport interface EligibilityBandInput {\n access: 'open' | 'bot_wall' | 'unreachable'\n rest: {\n reachable: boolean\n counts: { posts: number | null, pages: number | null }\n postTypes: Array<{ slug: string, count?: number | null }>\n /** Sampled records. Only how many there are is used — their content never leaves. */\n samples: { posts: unknown[], pages: unknown[] }\n }\n}\n\nexport interface EligibilityBandShaped {\n access: EligibilityBandInput['access']\n rest_reachable: boolean\n posts: number | null\n pages: number | null\n post_samples: number\n page_samples: number\n custom_types: Array<{ slug: string, count: number }>\n}\n\nconst MIN_POSTS = 2\n/** Posts and custom entries within this factor of each other are the band. */\nconst BAND_FACTOR = 2\n\nexport function shapeEligibility(input: EligibilityBandInput): EligibilityBandShaped {\n const rest = input.rest\n // Types whose slugs scrub to the same slug are summed. judgeEligibility does\n // not merge them, but it only ever uses the total, which is the same either way.\n const counts = new Map<string, number>()\n for (const type of rest.postTypes ?? []) {\n if (type.slug === 'post' || type.slug === 'page' || !((type.count ?? 0) > 0)) continue\n const slug = scrubSlug(type.slug)\n counts.set(slug, (counts.get(slug) ?? 0) + (type.count ?? 0))\n }\n return {\n access: input.access,\n rest_reachable: Boolean(rest.reachable),\n posts: rest.counts?.posts ?? null,\n pages: rest.counts?.pages ?? null,\n post_samples: rest.samples?.posts?.length ?? 0,\n page_samples: rest.samples?.pages?.length ?? 0,\n custom_types: [...counts].map(([slug, count]) => ({ slug, count })).toSorted((a, b) => a.slug.localeCompare(b.slug)),\n }\n}\n\nconst certain = (choice: EligibilityChoice): RuleVerdict => ({ choice, confidence: 1, final: true })\nconst tentative = (choice: EligibilityChoice): RuleVerdict => ({ choice, confidence: 0.5, final: false })\n\nexport function eligibilityRule(input: EligibilityBandInput): RuleVerdict {\n const site = shapeEligibility(input)\n if (site.access !== 'open' || !site.rest_reachable) return certain('access_blocked')\n const postCount = site.posts ?? site.post_samples\n const customCount = site.custom_types.reduce((sum, type) => sum + type.count, 0)\n const pages = site.page_samples || (site.pages ?? 0)\n\n if (site.post_samples >= MIN_POSTS) {\n const verdict: EligibilityChoice = customCount <= postCount ? 'eligible' : 'custom_type'\n const close = customCount > 0 && customCount * BAND_FACTOR >= postCount && postCount * BAND_FACTOR >= customCount\n return close ? tentative(verdict) : certain(verdict)\n }\n const verdict: EligibilityChoice = site.custom_types.length ? 'custom_type' : pages ? 'page_only' : 'access_blocked'\n return site.post_samples === 1 ? tentative(verdict) : certain(verdict)\n}\n\nfunction renderEligibility(site: EligibilityBandShaped): string {\n const custom = site.custom_types.length ? site.custom_types.map(type => `${type.slug}=${type.count}`).join(', ') : 'none'\n return [\n `access=${site.access}`,\n `rest=${site.rest_reachable ? 'reachable' : 'unreachable'}`,\n `posts=${site.posts ?? 'unknown'} (sampled ${site.post_samples})`,\n `pages=${site.pages ?? 'unknown'} (sampled ${site.page_samples})`,\n `custom post types: ${custom}`,\n ].join('; ')\n}\n\nfunction readEligibility(answers: Record<string, JevAnswer>) {\n const answer = answers.eligibility\n if (answer?.type !== 'choice') return undefined\n return { choice: answer.choice, confidence: answer.confidence, ...(answer.probabilities ? { probabilities: answer.probabilities } : {}) }\n}\n\nfunction eligibilityQuestions(prefix: string): Record<string, JevQuestion> {\n return {\n eligibility: {\n type: 'choice',\n instructions: `${prefix}: where does this site's content live, and can the engine move it?`,\n criteria: {\n eligible: 'Standard blog posts carry the site\\'s content; moving posts and pages moves what matters.',\n custom_type: 'The content lives mainly in custom post types (products, portfolio, members); moving posts and pages alone leaves it behind.',\n page_only: 'No real blog: a corporate or brochure site whose content is its pages.',\n access_blocked: 'What the scan could see is not the site\\'s real content; authorized access is needed to reach it.',\n },\n },\n }\n}\n\nexport const eligibilityBand: KindSpec<EligibilityBandInput, EligibilityBandShaped> = {\n kind: 'eligibility_band',\n version: '1',\n choices: ELIGIBILITY_CHOICES,\n shape: shapeEligibility,\n rule: eligibilityRule,\n jev: {\n header: () => 'WordPress sites considered for migration. Each item is what a public discovery scan counted on one site. The migration engine moves standard posts and pages only.\\n',\n render: renderEligibility,\n questions: eligibilityQuestions,\n read: readEligibility,\n probe: { access: 'open', rest_reachable: true, posts: 20, pages: 3, post_samples: 5, page_samples: 3, custom_types: [{ slug: 'product', count: 30 }] },\n },\n lowConfidence: { threshold: 0.5, choice: NEEDS_HUMAN },\n}\n","// ─── Migrate v3 fact-pack decisions: the narrow leftovers ───\n//\n// Migrate's fact pack settles most of a site deterministically: component\n// identity from builder trees and repeated subtrees, content vs. interface text\n// from cross-instance variance, field types from what the values say. Three\n// questions are left, each over a closed set, each with a rule that answers\n// the clear cases and a tentative answer for the rest:\n//\n// - field_type: a varying value whose type the value does not settle\n// (string or text, relation or url, select or string)\n// - region_name: what a top-level page section is (hero, card-grid, …)\n// - unmapped_element: which kit component a builder element no mapping rule\n// covers stands for, or `prose` / `site-specific`\n//\n// The fact pack already shapes these inputs (samples cut, e-mail addresses and\n// phone numbers masked); the shapers here scrub again, so nothing depends on\n// the producer being careful.\n\nimport type { JevAnswer, JevQuestion, KindSpec, RuleVerdict } from '../types.js'\nimport { scrubSlug, scrubText } from './shape.js'\n\nconst readChoice = (key: string) => (answers: Record<string, JevAnswer>) => {\n const answer = answers[key]\n if (answer?.type !== 'choice') return undefined\n return { choice: answer.choice, confidence: answer.confidence, ...(answer.probabilities ? { probabilities: answer.probabilities } : {}) }\n}\nconst certain = (choice: string, confidence = 1): RuleVerdict => ({ choice, confidence, final: true })\nconst tentative = (choice: string, confidence = 0.5): RuleVerdict => ({ choice, confidence, final: false })\n\n// ─── field_type ───────────────────────────────────────────────────────────────\n\n/** The field types a fact-pack field_type decision can be between. */\nexport const FIELD_TYPE_CHOICES = ['string', 'text', 'markdown', 'richtext', 'relation', 'url', 'select'] as const\nexport type FieldTypeChoice = typeof FIELD_TYPE_CHOICES[number]\n\nconst FIELD_TYPE_CRITERIA: Record<FieldTypeChoice, string> = {\n string: 'A short single-line value: a title, a label, a name.',\n text: 'Plain multi-sentence text without formatting: an excerpt, a description.',\n markdown: 'Formatted prose (emphasis, links inside the text) an editor writes as Markdown.',\n richtext: 'Formatted prose that needs HTML an editor cannot express in Markdown (tables, embeds).',\n relation: 'A link to another entry of the same site (a post, a page, a term): it should follow that entry when its address changes.',\n url: 'An address kept as written: external, or a fixed internal path that is not an entry.',\n select: 'One of a few fixed values repeated across instances (a category label, a status, a size).',\n}\n\nexport interface FieldTypeInput {\n tag: string\n prop: 'text' | 'href' | 'src' | 'alt' | 'datetime'\n inline?: boolean\n instances: number\n distinct: number\n maxLength: number\n samples: string[]\n /** The types this item may be answered with (a subset of FIELD_TYPE_CHOICES). */\n options: string[]\n}\n\nexport interface FieldTypeShaped {\n tag: string\n prop: FieldTypeInput['prop']\n inline: boolean\n instances: number\n distinct: number\n max_length: number\n samples: string[]\n options: FieldTypeChoice[]\n}\n\nexport function shapeFieldType(input: FieldTypeInput): FieldTypeShaped {\n const options = FIELD_TYPE_CHOICES.filter(choice => input.options.includes(choice))\n return {\n tag: scrubSlug(input.tag, 12),\n prop: input.prop,\n inline: Boolean(input.inline),\n instances: Math.max(0, Math.round(input.instances)),\n distinct: Math.max(0, Math.round(input.distinct)),\n max_length: Math.max(0, Math.round(input.maxLength)),\n samples: (input.samples ?? []).slice(0, 3).map(sample => scrubText(sample, 60)),\n options: options.length ? options : [...FIELD_TYPE_CHOICES],\n }\n}\n\nexport function fieldTypeRule(input: FieldTypeInput): RuleVerdict | undefined {\n const f = shapeFieldType(input)\n const has = (a: FieldTypeChoice, b: FieldTypeChoice) => f.options.length === 2 && f.options.includes(a) && f.options.includes(b)\n if (has('string', 'text')) {\n if (f.max_length <= 100) return certain('string')\n if (f.max_length >= 200) return certain('text')\n return tentative(f.max_length > 140 ? 'text' : 'string')\n }\n if (has('select', 'string')) {\n if (f.instances >= 8 && f.distinct <= 3) return certain('select')\n return tentative(f.distinct <= 3 ? 'select' : 'string')\n }\n if (has('relation', 'url')) return tentative('relation', 0.6)\n if (f.options.length === 1) return certain(f.options[0]!)\n return undefined\n}\n\nexport const fieldType: KindSpec<FieldTypeInput, FieldTypeShaped> = {\n kind: 'field_type',\n version: '1',\n choices: FIELD_TYPE_CHOICES,\n shape: shapeFieldType,\n rule: fieldTypeRule,\n jev: {\n // One request per option set, so the header can name the only valid answers.\n group: shaped => shaped.options.join('|'),\n header: shaped => `Values of repeated website components, migrated into a structured CMS. Each item is one value that differs between instances of the same component. Pick the field type that stores it. Valid types for every item in this request: ${shaped.options.join(', ')}.\\n`,\n render: f => `<${f.tag}> ${f.prop}; ${f.instances} instances, ${f.distinct} distinct, longest ${f.max_length} chars${f.inline ? ', has inline formatting' : ''}; samples: ${f.samples.map(s => JSON.stringify(s)).join(' | ') || 'none'}`,\n questions: (prefix): Record<string, JevQuestion> => ({\n type: { type: 'choice', instructions: `${prefix}: which field type stores this value?`, criteria: FIELD_TYPE_CRITERIA },\n }),\n read: readChoice('type'),\n probe: { tag: 'p', prop: 'text', inline: false, instances: 12, distinct: 12, max_length: 160, samples: ['A short excerpt of a post that runs a little longer than a title.'], options: ['string', 'text'] },\n },\n}\n\n// ─── region_name ──────────────────────────────────────────────────────────────\n\nexport const REGION_CHOICES = ['header', 'nav', 'hero', 'main', 'footer', 'sidebar', 'cta', 'card-grid', 'features', 'faq', 'pricing', 'testimonials', 'logos', 'gallery', 'contact', 'newsletter', 'content', 'other'] as const\nexport type RegionChoice = typeof REGION_CHOICES[number]\n\nconst REGION_CRITERIA: Record<RegionChoice, string> = {\n 'header': 'The site header: brand and primary navigation.',\n 'nav': 'A navigation block on its own.',\n 'hero': 'The large opening section of a page: headline, short text, often an image and a button.',\n 'main': 'The main content wrapper of the page.',\n 'footer': 'The site footer.',\n 'sidebar': 'A side column next to the main content.',\n 'cta': 'A call-to-action band: a short pitch and a button.',\n 'card-grid': 'A grid or list of similar cards (posts, services, team members).',\n 'features': 'A set of feature or benefit blocks, usually icon + title + text.',\n 'faq': 'Questions and answers, often collapsible.',\n 'pricing': 'Plans or packages with prices.',\n 'testimonials': 'Quotes from customers with names.',\n 'logos': 'A strip of client or partner logos.',\n 'gallery': 'A set of images shown as a gallery.',\n 'contact': 'Contact details or a contact form.',\n 'newsletter': 'A newsletter sign-up.',\n 'content': 'Ordinary page content: text, images, headings.',\n 'other': 'None of the above.',\n}\n\nexport interface RegionInput {\n tag: string\n classes?: string[]\n box?: [number, number, number, number]\n builder?: string | null\n children?: string[]\n images?: number\n links?: number\n headings?: number\n forms?: number\n text?: string\n}\n\nexport interface RegionShaped {\n tag: string\n classes: string[]\n top: number\n width: number\n height: number\n builder: string | null\n children: string[]\n images: number\n links: number\n headings: number\n forms: number\n text: string\n}\n\nexport function shapeRegion(input: RegionInput): RegionShaped {\n const [, y = 0, w = 0, h = 0] = input.box ?? []\n return {\n tag: scrubSlug(input.tag, 12),\n classes: (input.classes ?? []).slice(0, 6).map(c => scrubSlug(c)),\n // Rounded: layout scale is what matters, and exact pixels would split the cache.\n top: Math.round(y / 50) * 50,\n width: Math.round(w / 10) * 10,\n height: Math.round(h / 50) * 50,\n builder: input.builder ? scrubSlug(input.builder.replace('/', '-'), 40) : null,\n children: (input.children ?? []).slice(0, 12).map(c => scrubSlug(c.replace('/', '-'), 40)),\n images: input.images ?? 0,\n links: input.links ?? 0,\n headings: input.headings ?? 0,\n forms: input.forms ?? 0,\n text: scrubText(input.text ?? '', 120),\n }\n}\n\nconst REGION_CLASS_HINTS: [RegExp, RegionChoice][] = [\n [/faq|accordion|toggle|details/, 'faq'],\n [/testimonial|review|quote/, 'testimonials'],\n [/pricing|price|plan/, 'pricing'],\n [/newsletter|subscribe|mailchimp|optin/, 'newsletter'],\n [/logo|client|partner|brand/, 'logos'],\n [/gallery|portfolio/, 'gallery'],\n [/cta|call-to-action/, 'cta'],\n [/hero|banner|cover|masthead/, 'hero'],\n [/feature|benefit|service/, 'features'],\n]\n\nexport function regionRule(input: RegionInput): RuleVerdict | undefined {\n const r = shapeRegion(input)\n const words = `${r.classes.join(' ')} ${r.builder ?? ''} ${r.children.join(' ')}`\n for (const [re, choice] of REGION_CLASS_HINTS) if (re.test(words)) return tentative(choice, 0.7)\n if (r.forms > 0) return tentative(/subscri|newsletter|abone/i.test(r.text) ? 'newsletter' : 'contact', 0.6)\n const same = r.children.length >= 3 && r.children.every(c => c === r.children[0])\n if (same) return tentative('card-grid', 0.6)\n if (r.images >= 4 && r.headings <= 1 && r.text.length < 80) return tentative('gallery', 0.6)\n if (r.top <= 200 && r.headings >= 1 && r.height >= 300) return tentative('hero', 0.6)\n return tentative('content', 0.3)\n}\n\nexport const regionName: KindSpec<RegionInput, RegionShaped> = {\n kind: 'region_name',\n version: '1',\n choices: REGION_CHOICES,\n shape: shapeRegion,\n rule: regionRule,\n jev: {\n header: () => 'Top-level sections of a website page, rebuilt as components. Each item is one section: its tag, classes, position, the kinds of its children and a scrubbed sample of its text. Name what the section is.\\n',\n render: r => `<${r.tag}${r.classes.length ? ` class=\"${r.classes.join(' ')}\"` : ''}> at y≈${r.top}, ${r.width}×${r.height}; builder=${r.builder ?? 'none'}; children: ${r.children.join(', ') || 'none'}; ${r.headings} headings, ${r.images} images, ${r.links} links, ${r.forms} forms; text: ${JSON.stringify(r.text)}`,\n questions: (prefix): Record<string, JevQuestion> => ({\n region: { type: 'choice', instructions: `${prefix}: what is this page section?`, criteria: REGION_CRITERIA },\n }),\n read: readChoice('region'),\n probe: { tag: 'section', classes: ['wp-block-cover'], top: 100, width: 1280, height: 600, builder: 'core-cover', children: ['h1', 'p', 'core-buttons'], images: 1, links: 1, headings: 1, forms: 0, text: 'Welcome to our studio' },\n },\n}\n\n// ─── unmapped_element ─────────────────────────────────────────────────────────\n\n/** Kit component ids (astro-kit catalog, first fifteen) plus the two non-component answers. */\nexport const UNMAPPED_CHOICES = ['header', 'nav', 'footer', 'hero', 'card-grid', 'post-card', 'cta', 'faq', 'tabs', 'testimonial', 'gallery', 'slider', 'contact-form', 'pagination', 'breadcrumb', 'prose', 'site-specific'] as const\nexport type UnmappedChoice = typeof UNMAPPED_CHOICES[number]\n\nconst UNMAPPED_CRITERIA: Record<UnmappedChoice, string> = {\n 'header': 'Site header with brand and navigation.',\n 'nav': 'A navigation menu.',\n 'footer': 'Site footer.',\n 'hero': 'A large opening banner: headline, text, image, button.',\n 'card-grid': 'A grid of cards or feature boxes (icon/image + title + text).',\n 'post-card': 'One card for a blog post in a list.',\n 'cta': 'A call-to-action box with a button.',\n 'faq': 'Collapsible questions and answers (accordion, toggle).',\n 'tabs': 'Tabbed panels.',\n 'testimonial': 'A customer quote with a name.',\n 'gallery': 'An image gallery.',\n 'slider': 'A carousel or slider of slides.',\n 'contact-form': 'A form visitors submit.',\n 'pagination': 'Page navigation of a list.',\n 'breadcrumb': 'A breadcrumb trail.',\n 'prose': 'Plain content (text, a heading, an image, a spacer) that stays rich text, not a component.',\n 'site-specific': 'Something no kit component covers; it is written for this site.',\n}\n\nexport interface UnmappedInput {\n name: string\n builder: string\n count: number\n pages: number\n attrKeys?: string[]\n}\n\nexport interface UnmappedShaped {\n name: string\n builder: string\n count: number\n pages: number\n attr_keys: string[]\n}\n\nexport function shapeUnmapped(input: UnmappedInput): UnmappedShaped {\n return {\n name: scrubSlug(input.name.replace('/', '-'), 60),\n builder: scrubSlug(input.builder, 12),\n count: input.count,\n pages: input.pages,\n attr_keys: (input.attrKeys ?? []).slice(0, 20).map(k => scrubSlug(k, 40)),\n }\n}\n\nconst UNMAPPED_NAME_HINTS: [RegExp, UnmappedChoice][] = [\n [/(^|-)(heading|text|paragraph|text-editor|image|spacer|divider|separator|html|shortcode|video|audio|icon)$/, 'prose'],\n [/accordion|toggle|faq|details/, 'faq'],\n [/slider|carousel|slideshow/, 'slider'],\n [/gallery|lightbox/, 'gallery'],\n [/testimonial|review/, 'testimonial'],\n [/tabs?$/, 'tabs'],\n [/form|contact|signup/, 'contact-form'],\n [/call-to-action|cta|promo/, 'cta'],\n [/blurb|icon-box|info-box|image-box|feature|card|team-member|service/, 'card-grid'],\n [/breadcrumb/, 'breadcrumb'],\n [/pagination|pager/, 'pagination'],\n [/posts|blog|query|post-grid|loop/, 'card-grid'],\n [/fullwidth-header|hero|banner|cover/, 'hero'],\n [/menu|nav/, 'nav'],\n]\n\nexport function unmappedRule(input: UnmappedInput): RuleVerdict | undefined {\n const e = shapeUnmapped(input)\n for (const [re, choice] of UNMAPPED_NAME_HINTS) if (re.test(e.name)) return certain(choice, 0.9)\n return tentative('site-specific', 0.3)\n}\n\nexport const unmappedElement: KindSpec<UnmappedInput, UnmappedShaped> = {\n kind: 'unmapped_element',\n version: '1',\n choices: UNMAPPED_CHOICES,\n shape: shapeUnmapped,\n rule: unmappedRule,\n jev: {\n group: shaped => shaped.builder,\n header: shaped => `Page-builder elements (${shaped.builder}) found on a WordPress site that is rebuilt from a component kit. Each item is one element type: its name, how often it appears and the names of its settings. Say which kit component it becomes, \"prose\" when it is plain content, or \"site-specific\" when no kit component fits.\\n`,\n render: e => `${e.name}: ${e.count} uses on ${e.pages} pages; settings: ${e.attr_keys.join(', ') || 'none'}`,\n questions: (prefix): Record<string, JevQuestion> => ({\n component: { type: 'choice', instructions: `${prefix}: which kit component does this element become?`, criteria: UNMAPPED_CRITERIA },\n }),\n read: readChoice('component'),\n probe: { name: 'uagb-info-box', builder: 'gutenberg', count: 94, pages: 12, attr_keys: ['classes', 'settings'] },\n },\n lowConfidence: { threshold: 0.5, choice: 'site-specific' },\n}\n","// ─── punch_item: a migration run report's punch item → class + severity ───\n//\n// Migrate's run report lists what is left to finish on a migrated site. This\n// kind labels each item with its root cause (class) and how much it matters\n// (severity), as an advisory column beside the item — never as a gate.\n//\n// The request is PoC-1's, word for word, because that is the shape that was\n// measured: one request per site (at most 25 items), a three-line site header,\n// `Item <n>: etiket=…, link=…, neden=…` lines, and three questions per item —\n// class, severity and needs_human. needs_human is asked and not read: PoC-1\n// found it unreliable, but dropping the question changed the other two\n// answers. The one deliberate difference is privacy: the site's name, its URL\n// and item links are sent as placeholders.\n//\n// Any change here changes `requestShapeHash(punchItem)`. The test pins that\n// hash to the one in the latest `calibration/*.json`; a new shape needs a new\n// live calibration (`pnpm calibration:live`) before it can ship.\n\nimport { createHash } from 'node:crypto'\nimport type { JevAnswer, JevQuestion, KindSpec, RuleVerdict } from '../types.js'\nimport { finite, scrubText } from './shape.js'\n\nexport const PUNCH_CLASSES = ['product_defect', 'source_limit', 'cosmetic', 'measurement'] as const\nexport type PunchClass = typeof PUNCH_CLASSES[number]\n\nexport const PUNCH_CLASS_CRITERIA: Record<PunchClass, string> = {\n product_defect: 'Migration engine\\'in ürettiği çıktıda bir kusur/hata — üretilen sayfada bir şey yanlış (ör. yanlış görsel tekrar ediyor, bağlantı kırık, içerik markup\\'ta eksik).',\n source_limit: 'Kaynak sitenin kendi yapısından gelen bir sınır — içerik zaten kaynakta veri olarak ayrıştırılamaz durumda (ör. tema markup\\'ına gömülü, API\\'de yok), migration engine bunu değiştiremez.',\n cosmetic: 'Teslimi engellemeyen küçük görsel fark — kullanıcı deneyimini gerçekten bozmayan, göz ardı edilebilir bir fark.',\n measurement: 'Ölçüm/araç belirsizliği — sorunun kendisi değil, ölçüm sürecinin (skor eşiği, örneklem, zaman aşımı) ne olduğunu net söyleyememesi.',\n}\n\n/** Severity rubric, levels 0–3 (Jev's score scale). Level n here is severity n+1 on a 1–4 scale. */\nexport const PUNCH_SEVERITY_CRITERIA = [\n 'Teslimi engellemez — göz ardı edilebilir.',\n 'Küçük, düşük öncelik — teslim edilebilir, sonra bakılabilir.',\n 'Teslimden önce ele alınmalı — müşteri fark edebilir ama kesin reddetmez.',\n 'Müşteri fark eder ve reddeder — teslim öncesi mutlaka çözülmeli.',\n] as const\n\nexport interface PunchItemInput {\n /** The item's label in the run report, e.g. `(aile: post)` or a page slug. */\n label: string\n /** Why it is on the list, as the run report words it. */\n reason: string\n /** A link to the page. Never sent: the request says only whether there is one. */\n link?: string\n /** The site the item belongs to. `name` and `url` only group items into one request and are never sent. */\n site?: { name?: string, url?: string, decision?: string, median?: number, mobile_median?: number }\n}\n\nexport interface PunchItemShaped {\n label: string\n reason: string\n /** Whether the item has a link; the link itself is not kept. */\n linked: boolean\n site: {\n /** Opaque: a hash of the site's name or URL, so one site's items share a request. Never sent. */\n group: string\n decision: string | null\n median: number | null\n mobile_median: number | null\n }\n}\n\nexport function shapePunchItem(input: PunchItemInput): PunchItemShaped {\n const site = input.site ?? {}\n const identity = site.name ?? site.url ?? ''\n return {\n label: scrubText(String(input.label ?? ''), 120),\n reason: scrubText(String(input.reason ?? ''), 500),\n linked: Boolean(input.link),\n site: {\n group: identity ? createHash('sha256').update(identity).digest('hex').slice(0, 16) : '',\n decision: typeof site.decision === 'string' ? scrubText(site.decision, 40) : null,\n median: finite(site.median) ?? null,\n mobile_median: finite(site.mobile_median) ?? null,\n },\n }\n}\n\n// Run-report phrasings whose class is not in doubt. Tentative only: a rule\n// cannot place severity, so these answer only when Jev does not.\nconst SIGNATURES: ReadonlyArray<readonly [RegExp, PunchClass]> = [\n [/ölçülemedi|genellik kanıtlanmadı/i, 'measurement'],\n [/gövde yuvası yok|tam sayfa klon/i, 'source_limit'],\n [/hero sızıntısı|medya kaybı|dinamik liste bağlanmadı/i, 'product_defect'],\n]\n\nexport function punchItemRule(input: PunchItemInput): RuleVerdict | undefined {\n const reason = String(input.reason ?? '')\n const hit = SIGNATURES.find(([pattern]) => pattern.test(reason))\n return hit ? { choice: hit[1], confidence: 1, final: false } : undefined\n}\n\n// PoC-1's `siteStateHeader`, with the site's name and URL as placeholders.\nfunction punchHeader(item: PunchItemShaped): string {\n return `Site: <site> (<url>)\\nGenel karar: ${item.site.decision}\\nMedyan kalite skoru: ${item.site.median}, mobil: ${item.site.mobile_median}\\n`\n}\n\n// PoC-1's `itemText`, after its `Item <n>: ` prefix.\nfunction renderPunchItem(item: PunchItemShaped): string {\n return `etiket=\"${item.label}\", link=\"${item.linked ? '<url>' : '(yok)'}\", neden=\"${item.reason}\"`\n}\n\n// PoC-1's `itemQuestions`.\nfunction punchQuestions(prefix: string): Record<string, JevQuestion> {\n return {\n class: { type: 'choice', instructions: `${prefix} için: bu kalemin kök nedeni nedir?`, criteria: PUNCH_CLASS_CRITERIA },\n severity: { type: 'score', instructions: `${prefix} için: bu kalem ne kadar ciddi?`, criteria: PUNCH_SEVERITY_CRITERIA },\n needs_human: { type: 'noul', instructions: `${prefix} kalemi, teslim öncesi bir insanın karar vermesini gerektiriyor (otomatik/açık bir düzeltme değil, yargı gerektiriyor).` },\n }\n}\n\nfunction readPunchItem(answers: Record<string, JevAnswer>) {\n const cls = answers.class\n const severity = answers.severity\n if (cls?.type !== 'choice' || severity?.type !== 'score') return undefined\n return {\n choice: cls.choice,\n score: severity.score,\n confidence: Math.min(cls.confidence, severity.confidence),\n ...(cls.probabilities ? { probabilities: cls.probabilities } : {}),\n }\n}\n\n// The prompt AO-9 measured Claude Haiku with, word for word: the same state\n// and questions, in PoC-1's language, answered through a forced tool call.\nfunction punchLlmPrompt({ state, questions, count }: { state: string, questions: Record<string, JevQuestion>, count: number }): string {\n const q = questions.class as Extract<JevQuestion, { type: 'choice' }>\n const s = questions.severity as Extract<JevQuestion, { type: 'score' }>\n const h = questions.needs_human!\n return [\n 'Aşağıdaki durum bir WordPress → Astro taşıma koşusunun bitirilecekler listesinden bir sitenin kalemlerini içeriyor.',\n '',\n '<state>',\n state,\n '</state>',\n '',\n 'Her kalem için üç soruyu yanıtla (itemN yerine kalem numarası):',\n `1) class — ${q.instructions.replace('item1', 'itemN')} Seçenekler:`,\n ...Object.entries(q.criteria).map(([k, v]) => ` - ${k}: ${v}`),\n `2) severity — ${s.instructions.replace('item1', 'itemN')} 0–3 arası tam sayı:`,\n ...s.criteria.map((c, n) => ` ${n}: ${c}`),\n `3) needs_human — önermenin doğru olma olasılığı (0–1): ${h.instructions.replace('item1', 'itemN')}`,\n '',\n `Tüm ${count} kalemi record_answers aracıyla, her kalem için bir kayıt olarak ver.`,\n ].join('\\n')\n}\n\n/** Jev's 0–3 severity score as a 1–4 level (PoC-1's hand-label scale). */\nexport const severityLevel = (score: number): number => Math.min(4, Math.max(1, Math.round(score) + 1))\n\nexport const punchItem: KindSpec<PunchItemInput, PunchItemShaped> = {\n kind: 'punch_item',\n version: '2',\n choices: PUNCH_CLASSES,\n scoreRange: [0, 3],\n shape: shapePunchItem,\n rule: punchItemRule,\n jev: {\n header: punchHeader,\n group: item => item.site.group,\n render: renderPunchItem,\n questions: punchQuestions,\n read: readPunchItem,\n llmPrompt: punchLlmPrompt,\n // PoC-1's MAX_ITEMS_PER_CHUNK.\n batch: { maxItems: 25 },\n probe: {\n label: '(aile: post)',\n reason: 'en kötü sayfa 56.4 < 80 (5 sayfa ölçüldü)',\n linked: false,\n site: { group: 'probe', decision: 'KABUL + PUNCH LIST', median: 94.7, mobile_median: 83.9 },\n },\n },\n}\n","import type { KindSpec } from '../types.js'\nimport { eligibilityBand } from './eligibility-band.js'\nimport { fieldType, regionName, unmappedElement } from './facts.js'\nimport { punchItem } from './punch-item.js'\n\nexport const BUILTIN_KINDS: ReadonlyArray<KindSpec<any, any>> = [punchItem, eligibilityBand, fieldType, regionName, unmappedElement]\n","// ─── LLM provider (the last link) ───\n//\n// The link asked for what Jev does not answer. `createAnthropicProvider()`\n// (anthropic.ts) wires Claude Haiku; a host can wire its own model to the\n// kind's closed decision list instead. The default is a provider that is never\n// available, so no model is called unless the host opts in.\n\nimport type { DecisionProvider } from './types.js'\n\nexport const noopLlmProvider: DecisionProvider = {\n name: 'llm',\n available: () => false,\n ask: async () => {\n throw new Error('no LLM provider is configured')\n },\n}\n","// ─── The decider ───\n//\n// rule → cache → jev → llm → the rule's tentative answer.\n//\n// A final rule answer ends the chain before any lookup. Anything else is looked\n// up in the cache, then asked of each available provider in turn, in batches.\n// A provider that is off, over budget, behind an open circuit, slow or broken\n// never fails the call: its items move on down the chain and, at the end, take\n// the rule's tentative answer marked `unreviewed`.\n\nimport { type AuditSink, toAuditRecord } from './audit.js'\nimport { type BatchLimits, estimateTokens, planBatches } from './batch.js'\nimport type { DecisionBudget } from './budget.js'\nimport { CircuitBreaker } from './budget.js'\nimport { type CachedDecision, type DecisionCache, MemoryDecisionCache, cacheKey } from './cache.js'\nimport { DEFAULT_JEV_MODEL, buildJevRequest, createJevProvider, requestShapeHash } from './jev.js'\nimport { BUILTIN_KINDS } from './kinds/index.js'\nimport { noopLlmProvider } from './llm.js'\nimport type { Decision, DecisionProvider, FallbackReason, KindSpec, Outcome, RuleVerdict } from './types.js'\n\nexport interface Pricing {\n /** USD per million input tokens. */\n inputPerMTok: number\n /** USD per million output tokens. */\n outputPerMTok: number\n}\n\nexport interface DeciderConfig {\n /** Kinds this decider answers. Default: the built-in kinds. */\n kinds?: ReadonlyArray<KindSpec<any, any>>\n /** Default: Jev over `process.env`; `false` turns it off. */\n jev?: DecisionProvider | false\n /** Asked for what Jev does not answer. Default: `noopLlmProvider`; `createAnthropicProvider()` wires Claude Haiku. */\n llm?: DecisionProvider\n /** Default: an in-memory cache for this decider's lifetime. */\n cache?: DecisionCache\n audit?: AuditSink\n /** Absent: no cap. */\n budget?: DecisionBudget\n /** One per provider. Default: 3 failures, 60s cooldown. */\n breakers?: Partial<Record<'jev' | 'llm', CircuitBreaker>>\n batch?: BatchLimits\n /** Price per provider. Without one, that provider's `cost.usd` is left out; Jev's vendor publishes no price. */\n pricing?: Partial<Record<'jev' | 'llm', Pricing>>\n now?: () => Date\n}\n\nexport interface DecideOptions<I = unknown> {\n /** Budget and audit tenant. Default `default`. */\n tenant?: string\n /** Replace the kind's rule, e.g. with the host's own verdict function. `null` asks no rule. */\n rule?: ((input: I) => RuleVerdict | undefined) | null\n /** Skip the cache lookup and do not store the answer. */\n noCache?: boolean\n /**\n * Ask a repeated input once (default). `false` asks every input as its own\n * item, in the caller's order — what reproducing a calibrated request needs,\n * since folding renumbers the items a request carries.\n */\n fold?: boolean\n}\n\nexport interface Decider {\n decide: <I>(kind: string, input: I, options?: DecideOptions<I>) => Promise<Decision>\n decideMany: <I>(kind: string, inputs: readonly I[], options?: DecideOptions<I>) => Promise<Decision[]>\n kinds: () => string[]\n}\n\ninterface Pending {\n /** Positions in the caller's input list this item answers. */\n at: number[]\n /** Unique within one call: the cache key, or the key and position when not folding. */\n id: string\n key: string\n shaped: unknown\n rule: RuleVerdict | undefined\n}\n\nfunction validOutcome(spec: KindSpec<any, any>, outcome: Outcome | undefined): outcome is Outcome {\n if (!outcome) return false\n if (outcome.choice !== undefined && spec.choices && !spec.choices.includes(outcome.choice)) return false\n if (outcome.score !== undefined && spec.scoreRange && (outcome.score < spec.scoreRange[0] || outcome.score > spec.scoreRange[1])) return false\n return Number.isFinite(outcome.confidence)\n}\n\nfunction fromOutcome(spec: KindSpec<any, any>, key: string, shape: string, outcome: Outcome, source: Decision['source'], ms: number): Decision {\n const decision: Decision = { kind: spec.kind, version: spec.version, key, shape, confidence: outcome.confidence, source, ms }\n if (outcome.choice !== undefined) decision.choice = outcome.choice\n if (outcome.score !== undefined) decision.score = outcome.score\n if (outcome.probabilities) decision.probabilities = outcome.probabilities\n return decision\n}\n\n/** A provider answer under the kind's confidence floor becomes the kind's human-review choice. */\nfunction applyFloor(spec: KindSpec<any, any>, decision: Decision): Decision {\n const floor = spec.lowConfidence\n if (!floor || decision.choice === undefined || decision.confidence >= floor.threshold) return decision\n return { ...decision, proposed: decision.choice, choice: floor.choice }\n}\n\nfunction fallback(spec: KindSpec<any, any>, item: Pending, shape: string, reason: FallbackReason, ms: number): Decision {\n const base = item.rule\n ? fromOutcome(spec, item.key, shape, item.rule, 'rule', ms)\n : { kind: spec.kind, version: spec.version, key: item.key, shape, confidence: 0, source: 'rule' as const, ms }\n return { ...base, unreviewed: true, fallback: reason }\n}\n\nfunction fromCache(cached: CachedDecision, key: string, ms: number): Decision {\n const { at: _at, source: _source, ...rest } = cached\n return { ...rest, key, source: 'cache', ms }\n}\n\nfunction toCached(decision: Decision, source: 'jev' | 'llm', at: string): CachedDecision {\n const cached: CachedDecision = { kind: decision.kind, version: decision.version, shape: decision.shape, confidence: decision.confidence, source, at }\n for (const field of ['choice', 'score', 'probabilities', 'proposed', 'model'] as const) {\n if (decision[field] !== undefined) Object.assign(cached, { [field]: decision[field] })\n }\n return cached\n}\n\n/** Split `total` into `parts` integers that sum to it. */\nfunction share(total: number, parts: number, index: number): number {\n const base = Math.floor(total / parts)\n return base + (index < total - base * parts ? 1 : 0)\n}\n\nexport function createDecider(config: DeciderConfig = {}): Decider {\n const kinds = new Map((config.kinds ?? BUILTIN_KINDS).map(spec => [spec.kind, spec]))\n const cache = config.cache ?? new MemoryDecisionCache()\n const now = config.now ?? (() => new Date())\n const providers: DecisionProvider[] = []\n if (config.jev !== false) providers.push(config.jev ?? createJevProvider())\n providers.push(config.llm ?? noopLlmProvider)\n const breakers = new Map<string, CircuitBreaker>(providers.map(p => [p.name, config.breakers?.[p.name] ?? new CircuitBreaker()]))\n // The request shape a kind's answers are keyed under: the Jev prompt as the configured Jev provider would send it.\n const jevModel = providers.find(p => p.name === 'jev')?.model ?? DEFAULT_JEV_MODEL\n const shapes = new Map<string, string>()\n const shapeOf = (spec: KindSpec<any, any>): string => {\n let shape = shapes.get(spec.kind)\n if (shape === undefined) shapes.set(spec.kind, shape = requestShapeHash(spec, jevModel))\n return shape\n }\n\n function cost(provider: 'jev' | 'llm', usage: { input_tokens: number, output_tokens: number } | undefined, parts: number, index: number): Decision['cost'] {\n if (!usage) return undefined\n const input_tokens = share(usage.input_tokens, parts, index)\n const output_tokens = share(usage.output_tokens, parts, index)\n const price = config.pricing?.[provider]\n const usd = price\n ? (input_tokens * price.inputPerMTok + output_tokens * price.outputPerMTok) / 1e6\n : undefined\n return usd === undefined ? { input_tokens, output_tokens } : { input_tokens, output_tokens, usd }\n }\n\n /** Ask one provider about `items`; answered items are returned by key, the rest keep their reason to fall back. */\n async function ask(provider: DecisionProvider, spec: KindSpec<any, any>, shape: string, items: Pending[], tenant: string): Promise<{ answered: Map<string, Decision>, reasons: Map<string, FallbackReason> }> {\n const answered = new Map<string, Decision>()\n const reasons = new Map<string, FallbackReason>()\n const breaker = breakers.get(provider.name)!\n if (!provider.available() || (provider.name === 'jev' && !spec.jev)) {\n for (const item of items) reasons.set(item.id, 'no_provider')\n return { answered, reasons }\n }\n // Items of different groups never share a request; within a group, the\n // kind's calibrated batch limits win over the decider's.\n const groups = new Map<string, Pending[]>()\n for (const item of items) {\n const group = spec.jev?.group?.(item.shaped) ?? ''\n groups.set(group, [...(groups.get(group) ?? []), item])\n }\n const batches: Pending[][] = []\n for (const members of groups.values()) {\n const fixed = spec.jev?.header ? estimateTokens(spec.jev.header(members[0]!.shaped)) : 0\n const costs = members.map(item => Math.max(1, estimateTokens(JSON.stringify(buildJevRequestFor(spec, item.shaped))) - fixed))\n for (const batch of planBatches(costs, fixed, spec.jev?.batch ?? config.batch)) batches.push(batch.map(i => members[i]!))\n }\n for (const batch of batches) {\n // The breaker first: a request that never goes out spends no budget,\n // so an outage upstream does not drain the cap the next provider needs.\n if (!breaker.allows()) {\n for (const item of batch) reasons.set(item.id, 'circuit_open')\n continue\n }\n let members = batch\n if (config.budget) {\n const granted = await config.budget.take(tenant, batch.length, now())\n members = batch.slice(0, granted)\n for (const item of batch.slice(granted)) reasons.set(item.id, 'budget')\n }\n if (!members.length) continue\n const started = performance.now()\n try {\n const answer = await provider.ask(spec, members.map(item => item.shaped))\n breaker.success()\n const ms = Math.round(performance.now() - started)\n members.forEach((item, i) => {\n const outcome = answer.outcomes[i]\n if (!validOutcome(spec, outcome)) {\n reasons.set(item.id, 'no_answer')\n return\n }\n const decision = fromOutcome(spec, item.key, shape, outcome, provider.name, ms)\n const spent = cost(provider.name, answer.usage, members.length, i)\n if (spent) decision.cost = spent\n if (answer.model) decision.model = answer.model\n answered.set(item.id, applyFloor(spec, decision))\n })\n }\n catch (error) {\n breaker.failure()\n const reason: FallbackReason = (error as { timeout?: unknown } | null)?.timeout === true ? 'timeout' : 'error'\n for (const item of members) reasons.set(item.id, reason)\n }\n }\n return { answered, reasons }\n }\n\n async function decideMany<I>(kind: string, inputs: readonly I[], options: DecideOptions<I> = {}): Promise<Decision[]> {\n const spec = kinds.get(kind) as KindSpec<I, unknown> | undefined\n if (!spec) throw new TypeError(`unknown decision kind: ${kind} (known: ${[...kinds.keys()].join(', ')})`)\n const tenant = options.tenant ?? 'default'\n const shape = shapeOf(spec)\n const fold = options.fold ?? true\n const rule = options.rule === null ? undefined : (options.rule ?? spec.rule)\n const results: Decision[] = Array.from({ length: inputs.length })\n\n // Shape, rule, and fold duplicate inputs into one pending item.\n const pending = new Map<string, Pending>()\n inputs.forEach((input, i) => {\n const started = performance.now()\n const shaped = spec.shape(input)\n const key = cacheKey(spec.kind, spec.version, shape, shaped)\n const verdict = rule?.(input)\n const valid = verdict && validOutcome(spec, verdict) ? verdict : undefined\n if (valid?.final) {\n results[i] = fromOutcome(spec, key, shape, valid, 'rule', Math.round(performance.now() - started))\n return\n }\n const id = fold ? key : `${key}#${i}`\n const existing = pending.get(id)\n if (existing) existing.at.push(i)\n else pending.set(id, { at: [i], id, key, shaped, rule: valid })\n })\n\n let open = [...pending.values()]\n if (!options.noCache) {\n const started = performance.now()\n const hits = await Promise.all(open.map(item => cache.get(item.key)))\n const ms = Math.round(performance.now() - started)\n open = open.filter((item, i) => {\n const hit = hits[i]\n if (hit?.kind !== spec.kind || hit.version !== spec.version || hit.shape !== shape) return true\n for (const at of item.at) results[at] = fromCache(hit, item.key, ms)\n return false\n })\n }\n\n const lastReason = new Map<string, FallbackReason>()\n for (const provider of providers) {\n if (!open.length) break\n const { answered, reasons } = await ask(provider, spec, shape, open, tenant)\n for (const [id, decision] of answered) {\n const item = pending.get(id)!\n for (const at of item.at) results[at] = decision\n if (!options.noCache) await cache.set(item.key, toCached(decision, provider.name, now().toISOString()))\n }\n // A reason from a provider that was actually tried beats \"not configured\" from one after it.\n for (const [id, reason] of reasons) {\n if (reason !== 'no_provider' || !lastReason.has(id)) lastReason.set(id, reason)\n }\n open = open.filter(item => !answered.has(item.id))\n }\n for (const item of open) {\n const decision = fallback(spec, item, shape, lastReason.get(item.id) ?? 'no_provider', 0)\n for (const at of item.at) results[at] = decision\n }\n\n if (config.audit) {\n const at = now().toISOString()\n await config.audit.write(results.map(decision => toAuditRecord(decision, at, tenant)))\n }\n return results\n }\n\n return {\n decideMany,\n decide: async (kind, input, options) => (await decideMany(kind, [input], options))[0]!,\n kinds: () => [...kinds.keys()],\n }\n}\n\nfunction buildJevRequestFor(spec: KindSpec<any, any>, shaped: unknown): unknown {\n return spec.jev ? buildJevRequest(spec, [shaped]) : shaped\n}\n\nlet defaultDecider: Decider | undefined\n\n/**\n * Decide with the default decider: built-in kinds, Jev when\n * `CONTENTRAIN_JEW_API_TOKEN` is set, an in-memory cache, no budget, no audit\n * log. Build your own with `createDecider` for anything else.\n */\nexport function decide<I>(kind: string, input: I, options?: DecideOptions<I>): Promise<Decision> {\n defaultDecider ??= createDecider()\n return defaultDecider.decide(kind, input, options)\n}\n","// ─── Anthropic provider (Claude Haiku, the LLM link of the chain) ───\n//\n// Asked when Jev does not answer: Jev off, its circuit open, a timeout, an\n// error. The same rules hold here as in jev.ts:\n// - The API key comes from the environment, read at the moment of each\n// request and passed straight into the header. It is never stored on an\n// object, returned, logged or put in an error message.\n// - Requests go to one fixed endpoint. There is no base-URL option.\n// - The request carries only what the kind's shaper and renderer produced:\n// the state and questions Jev gets, as a prompt. The answer is structured,\n// not parsed from prose: one forced tool call at temperature 0 on models\n// that take them, structured outputs (a JSON schema) on the rest.\n//\n// A model reports no confidence of its own. Its answers carry confidence 0,\n// meaning \"not measured\": a kind with a confidence floor (eligibility_band)\n// keeps the model's pick as `proposed` and asks a human.\n\nimport { createHash } from 'node:crypto'\nimport { canonicalStringify } from '@contentrain/types'\nimport { buildJevRequest } from './jev.js'\nimport type { DecisionProvider, JevAnswer, JevQuestion, KindSpec, Outcome, ProviderAnswer } from './types.js'\n\nexport const ANTHROPIC_ENDPOINT = 'https://api.anthropic.com/v1/messages'\nexport const ANTHROPIC_KEY_ENV = 'ANTHROPIC_API_KEY'\nexport const DEFAULT_ANTHROPIC_MODEL = 'claude-haiku-4-5-20251001'\nconst ANTHROPIC_VERSION = '2023-06-01'\nconst MAX_TOKENS = 4096\nconst TOOL_NAME = 'record_answers'\n\nexport interface AnthropicProviderOptions {\n /** Where the key is read from. Default `process.env`. */\n env?: Readonly<Record<string, string | undefined>>\n /** Injected for tests. The URL it is called with is always `ANTHROPIC_ENDPOINT`. */\n fetch?: typeof globalThis.fetch\n /** Per request. Default 60s. */\n timeoutMs?: number\n /** Default `claude-haiku-4-5-20251001`, asked at temperature 0. A Claude 4.7 or later model is asked through structured outputs. */\n model?: string\n}\n\nexport class AnthropicError extends Error {\n constructor(message: string, readonly status: number | undefined, readonly timeout = false) {\n super(message)\n this.name = 'AnthropicError'\n }\n}\n\ntype Questions = Record<string, JevQuestion>\n\nconst itemN = (text: string) => text.replace(/\\bitem1\\b/g, 'itemN')\n\n/** The prompt for a kind without its own `llmPrompt`: the state, then every question with its options or rubric. */\nexport function genericLlmPrompt({ state, questions, count }: { state: string, questions: Questions, count: number }): string {\n const lines = ['<state>', state, '</state>', '', 'Answer these questions for every item (itemN stands for the item\\'s number):']\n Object.entries(questions).forEach(([suffix, question], n) => {\n if (question.type === 'choice') {\n lines.push(`${n + 1}) ${suffix} — ${itemN(question.instructions)} Options:`)\n for (const [choice, meaning] of Object.entries(question.criteria)) lines.push(` - ${choice}: ${meaning}`)\n }\n else if (question.type === 'score') {\n lines.push(`${n + 1}) ${suffix} — ${itemN(question.instructions)} An integer from 0 to ${question.criteria.length - 1}:`)\n question.criteria.forEach((meaning, level) => lines.push(` ${level}: ${meaning}`))\n }\n else {\n lines.push(`${n + 1}) ${suffix} — the probability (0–1) that this statement is true: ${itemN(question.instructions)}`)\n }\n })\n lines.push('', `Give all ${count} items through the ${TOOL_NAME} tool, one record per item.`)\n return lines.join('\\n')\n}\n\n/**\n * Whether a model takes the original request: `temperature: 0` and a forced tool call. Claude 4.7 and later models\n * answer a non-default `temperature` with HTTP 400, and Opus and Sonnet 5.5 a forced tool call, so they are asked\n * through structured outputs instead. An id this does not recognise is asked the current way.\n */\nexport function takesForcedTool(model: string): boolean {\n if (/^claude-\\d-\\d-/.test(model)) return true\n const version = /^claude-(?:opus|sonnet|haiku)-(\\d+)(?:-(\\d{1,2}))?(?:-\\d{8})?$/.exec(model)\n if (!version) return false\n const [major, minor] = [Number(version[1]), Number(version[2] ?? 0)]\n return major < 4 || (major === 4 && minor < 7)\n}\n\n/**\n * One record per item, one field per question. `bounds: false` leaves out the numeric bounds, which a structured-output\n * schema does not take; `readField` checks every value either way.\n */\nfunction answerSchema(questions: Questions, bounds = true) {\n const properties: Record<string, unknown> = { item: { type: 'integer' } }\n for (const [suffix, question] of Object.entries(questions)) {\n properties[suffix] = question.type === 'choice'\n ? { type: 'string', enum: Object.keys(question.criteria) }\n : question.type === 'score'\n ? { type: 'integer', ...(bounds ? { minimum: 0, maximum: question.criteria.length - 1 } : {}) }\n : { type: 'number', ...(bounds ? { minimum: 0, maximum: 1 } : {}) }\n }\n const strict = bounds ? {} : { additionalProperties: false }\n return {\n type: 'object',\n properties: {\n items: { type: 'array', items: { type: 'object', properties, required: Object.keys(properties), ...strict } },\n },\n required: ['items'],\n ...strict,\n }\n}\n\n/** The forced tool the model answers through. */\nfunction answerTool(questions: Questions) {\n return { name: TOOL_NAME, description: 'Record the answers for every item.', input_schema: answerSchema(questions) }\n}\n\n/** The Messages API body one batch sends. */\nexport function buildAnthropicRequest(spec: KindSpec<any, any>, shaped: readonly unknown[], model = DEFAULT_ANTHROPIC_MODEL) {\n const jev = spec.jev\n if (!jev) throw new TypeError(`kind ${spec.kind} has no prompt`)\n const { state } = buildJevRequest(spec, shaped)\n const questions = jev.questions('item1')\n const prompt = (jev.llmPrompt ?? genericLlmPrompt)({ state, questions, count: shaped.length })\n const messages = [{ role: 'user' as const, content: prompt }]\n if (!takesForcedTool(model))\n return { model, max_tokens: MAX_TOKENS, output_config: { format: { type: 'json_schema' as const, schema: answerSchema(questions, false) } }, messages }\n return {\n model,\n max_tokens: MAX_TOKENS,\n temperature: 0,\n tools: [answerTool(questions)],\n tool_choice: { type: 'tool' as const, name: TOOL_NAME },\n messages,\n }\n}\n\n/** Hash of the LLM request shape (model, prompt, tool), recorded by a calibration of this provider. */\nexport function anthropicRequestShapeHash(spec: KindSpec<any, any>, model = DEFAULT_ANTHROPIC_MODEL): string {\n if (!spec.jev) return 'none'\n const request = buildAnthropicRequest(spec, [spec.jev.probe, spec.jev.probe], model)\n return createHash('sha256').update(canonicalStringify(request)).digest('hex').slice(0, 16)\n}\n\nexport function createAnthropicProvider(options: AnthropicProviderOptions = {}): DecisionProvider {\n const env = options.env ?? process.env\n const doFetch = options.fetch ?? globalThis.fetch\n const timeoutMs = options.timeoutMs ?? 60_000\n const model = options.model ?? DEFAULT_ANTHROPIC_MODEL\n\n return {\n name: 'llm',\n model,\n available: () => Boolean(env[ANTHROPIC_KEY_ENV]?.trim()),\n async ask(spec, shaped) {\n const key = env[ANTHROPIC_KEY_ENV]?.trim()\n if (!key) throw new AnthropicError(`${ANTHROPIC_KEY_ENV} is not set`, undefined)\n const request = buildAnthropicRequest(spec, shaped, model)\n let response: Response\n try {\n response = await doFetch(ANTHROPIC_ENDPOINT, {\n method: 'POST',\n headers: { 'x-api-key': key, 'anthropic-version': ANTHROPIC_VERSION, 'content-type': 'application/json' },\n body: JSON.stringify(request),\n signal: AbortSignal.timeout(timeoutMs),\n })\n }\n catch (error) {\n const name = (error as { name?: string }).name\n if (name === 'TimeoutError' || name === 'AbortError') throw new AnthropicError(`Anthropic did not answer within ${timeoutMs}ms`, undefined, true)\n throw new AnthropicError(`Anthropic request failed: ${redact(String((error as Error).message ?? error), key)}`, undefined)\n }\n const text = await response.text()\n if (!response.ok) throw new AnthropicError(`Anthropic answered HTTP ${response.status}: ${redact(text.slice(0, 200), key)}`, response.status)\n let body: unknown\n try {\n body = JSON.parse(text)\n }\n catch {\n throw new AnthropicError('Anthropic answered with a body that is not JSON', response.status)\n }\n return readAnthropicResponse(spec, shaped.length, body)\n },\n }\n}\n\n/** Per-item outcomes from a Messages API response. An item whose record is missing or malformed gets `undefined`. */\nexport function readAnthropicResponse(spec: KindSpec<any, any>, count: number, body: unknown): ProviderAnswer {\n const jev = spec.jev!\n const questions = jev.questions('item1')\n const root = (body && typeof body === 'object' ? body : {}) as { content?: unknown, usage?: unknown, model?: unknown }\n const content = Array.isArray(root.content) ? root.content as Array<Record<string, unknown>> : []\n const call = content.find(block => block?.type === 'tool_use' && block.name === TOOL_NAME)\n const given = call ? call.input : structuredAnswer(content)\n const input = (given && typeof given === 'object' ? given : {}) as { items?: unknown }\n const records = Array.isArray(input.items) ? input.items as Array<Record<string, unknown>> : []\n\n const outcomes: Array<Outcome | undefined> = []\n for (let i = 1; i <= count; i++) {\n const record = records.find(r => r && typeof r === 'object' && r.item === i)\n const own: Record<string, JevAnswer> = {}\n let complete = Boolean(record)\n for (const [suffix, question] of Object.entries(questions)) {\n const answer = record ? readField(question, record[suffix]) : undefined\n if (!answer) complete = false\n else own[suffix] = answer\n }\n outcomes.push(complete ? jev.read(own) : undefined)\n }\n const usage = root.usage as { input_tokens?: unknown, output_tokens?: unknown } | undefined\n return {\n outcomes,\n ...(usage && typeof usage.input_tokens === 'number' && typeof usage.output_tokens === 'number'\n ? { usage: { input_tokens: usage.input_tokens, output_tokens: usage.output_tokens } }\n : {}),\n ...(typeof root.model === 'string' ? { model: root.model } : {}),\n }\n}\n\n/** A structured-output answer: the JSON of the text block. Not JSON, or not an object: no answer. */\nfunction structuredAnswer(content: ReadonlyArray<Record<string, unknown>>): object | undefined {\n const text = content.find(block => block?.type === 'text' && typeof block.text === 'string')?.text as string | undefined\n if (!text) return undefined\n try {\n const value: unknown = JSON.parse(text)\n return value && typeof value === 'object' ? value : undefined\n }\n catch {\n return undefined\n }\n}\n\nfunction readField(question: JevQuestion, value: unknown): JevAnswer | undefined {\n if (question.type === 'choice')\n return typeof value === 'string' && Object.hasOwn(question.criteria, value) ? { type: 'choice', choice: value, confidence: 0 } : undefined\n if (question.type === 'score')\n return Number.isInteger(value) && (value as number) >= 0 && (value as number) < question.criteria.length ? { type: 'score', score: value as number, confidence: 0 } : undefined\n return typeof value === 'number' && value >= 0 && value <= 1 ? { type: 'noul', noul: value } : undefined\n}\n\nfunction redact(text: string, key: string): string {\n return text.split(key).join('[redacted]')\n}\n","// ─── Calibration ───\n//\n// A kind is trusted only as far as a live run has measured it against hand\n// labels. The measurement is `pnpm calibration:live`, which writes\n// `calibration/<date>.json` with the model and the request-shape hash it\n// measured; the numbers in the docs are that file's. Two tools here:\n// - `measurePunchCalibration` scores punch_item decisions against labels\n// the way PoC-1 did: exact class, severity within one level.\n// - `createReplayFetch` answers requests from recorded answers — a smoke\n// test of the code path, not a measurement.\n\nimport { buildJevRequest } from './jev.js'\nimport { severityLevel } from './kinds/punch-item.js'\nimport type { Decision, JevAnswer, KindSpec } from './types.js'\n\nexport interface RecordedCase<I> {\n input: I\n /** The item's answers, keyed by the kind's question suffixes. */\n answers: Record<string, JevAnswer>\n}\n\n/** A request's header and one item line, as a replay key. */\nfunction replayKey(state: string, line: string): string {\n const first = state.search(/^Item 1: /m)\n return `${first > 0 ? state.slice(0, first) : ''}\\u0000${line}`\n}\n\n/**\n * A `fetch` that answers systemone requests for `spec` from recorded answers,\n * matching each item by its request header and its rendered line. An item\n * with no recording gets no answers, which the decider treats as `no_answer`.\n * `calls` counts requests.\n *\n * A replay re-reads the answers a model gave once. It checks the code path —\n * shaping, grouping, batching, reading — and says nothing about how the model\n * answers today; only a live run does.\n */\nexport function createReplayFetch<I>(spec: KindSpec<I, any>, cases: ReadonlyArray<RecordedCase<I>>, model = 'replay'): typeof globalThis.fetch & { calls: number } {\n const byKey = new Map<string, Record<string, JevAnswer>>()\n for (const recorded of cases) {\n const { state } = buildJevRequest(spec, [spec.shape(recorded.input)])\n const line = /^Item 1: (.*)$/m.exec(state)![1]!\n byKey.set(replayKey(state, line), recorded.answers)\n }\n const replay = async (_url: string | URL | Request, init?: RequestInit): Promise<Response> => {\n replay.calls++\n const { state } = JSON.parse(String(init?.body)) as { state: string }\n const answers: Record<string, JevAnswer> = {}\n for (const line of state.split('\\n')) {\n const match = /^Item (\\d+): (.*)$/.exec(line)\n const recorded = match ? byKey.get(replayKey(state, match[2]!)) : undefined\n if (!recorded) continue\n for (const [suffix, answer] of Object.entries(recorded)) answers[`item${match![1]}_${suffix}`] = answer\n }\n return new Response(JSON.stringify({ model, answers }), { status: 200, headers: { 'Content-Type': 'application/json' } })\n }\n replay.calls = 0\n return replay as typeof globalThis.fetch & { calls: number }\n}\n\nexport interface PunchLabel {\n class: string\n /** 1–4. */\n severity: number\n}\n\nexport interface PunchCalibration {\n total: number\n answered: number\n classMatch: number\n severityWithin1: number\n classRate: number\n severityRate: number\n misses: Array<{ index: number, expected: PunchLabel, choice?: string, level?: number }>\n}\n\n/** Exact class and severity within one level, over every label (an unanswered item counts as a miss). */\nexport function measurePunchCalibration(labels: readonly PunchLabel[], decisions: readonly Decision[]): PunchCalibration {\n let answered = 0\n let classMatch = 0\n let severityWithin1 = 0\n const misses: PunchCalibration['misses'] = []\n labels.forEach((expected, index) => {\n const decision = decisions[index]\n if (decision?.choice === undefined || decision.score === undefined || decision.unreviewed) {\n misses.push({ index, expected })\n return\n }\n answered++\n const level = severityLevel(decision.score)\n const classOk = decision.choice === expected.class\n const severityOk = Math.abs(level - expected.severity) <= 1\n if (classOk) classMatch++\n if (severityOk) severityWithin1++\n if (!classOk || !severityOk) misses.push({ index, expected, choice: decision.choice, level })\n })\n const total = labels.length\n return {\n total,\n answered,\n classMatch,\n severityWithin1,\n classRate: total ? classMatch / total : 0,\n severityRate: total ? severityWithin1 / total : 0,\n misses,\n }\n}\n\n/** Whether repeated runs over the same inputs chose the same class for every item. */\nexport function stableChoices(runs: ReadonlyArray<readonly Decision[]>): { stable: number, total: number } {\n const total = runs[0]?.length ?? 0\n let stable = 0\n for (let i = 0; i < total; i++) {\n const choices = new Set(runs.map(run => run[i]?.choice))\n if (choices.size === 1 && !choices.has(undefined)) stable++\n }\n return { stable, total }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentrain/decide",
3
- "version": "0.2.44",
3
+ "version": "0.2.46",
4
4
  "license": "MIT",
5
5
  "description": "Small typed decisions for migration and governance pipelines — rule first, then Jev, then Claude Haiku, cached, budgeted and audited",
6
6
  "type": "module",
@@ -37,7 +37,7 @@
37
37
  "dist"
38
38
  ],
39
39
  "dependencies": {
40
- "@contentrain/types": "1.64.0"
40
+ "@contentrain/types": "1.65.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^22.10.0",