@trazum/cli 1.38.0 → 1.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trazum/cli",
3
- "version": "1.38.0",
3
+ "version": "1.40.0",
4
4
  "description": "Trazum CLI: find where your LLM bill goes, price every finding per month, and enforce token budgets in CI.",
5
5
  "license": "MIT",
6
6
  "author": "David Mu\u00f1oz Rey",
@@ -37,7 +37,7 @@
37
37
  "prepublishOnly": "npm run build && npm test"
38
38
  },
39
39
  "dependencies": {
40
- "@trazum/core": "1.38.0"
40
+ "@trazum/core": "1.40.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^26.2.0",
package/src/i18n/en.ts CHANGED
@@ -40,6 +40,8 @@ ${bold('USAGE')}
40
40
  trazum eval <file> --cases <file> --export promptfoo -o suite.json
41
41
  trazum route <log.jsonl> --prompt-file <file> --cases <file> --yes
42
42
  trazum plan <log.jsonl|dir> [options]
43
+ trazum verify <plan.json> --against <newer.jsonl|dir> [options]
44
+ trazum history <dir-of-stored-reports> [options]
43
45
  trazum diff <before> <after> [options]
44
46
  trazum diff --all <dir> <dir> [options]
45
47
  trazum rank <dir> [options]
@@ -317,6 +319,39 @@ ${bold('OPTIONS FOR plan')}
317
319
  a plan that hides its assumptions is advice pretending to be arithmetic.
318
320
  Projected savings and money already spent are separate totals throughout.
319
321
 
322
+ ${bold('OPTIONS FOR history')}
323
+ --markdown-out <file> Also write the series as Markdown, for a CI job
324
+ summary or a pull request comment.
325
+ --json The history as data.
326
+
327
+ Takes a directory of stored reports — the --json documents profile already
328
+ writes — plus any saved plans beside them, and builds the series no
329
+ pairwise comparison can see: a workload climbing a little every period, a
330
+ model share rising since a date, a cache share decaying slowly enough that
331
+ no single week's report called it a finding, and the same action planned
332
+ again and again with nothing executing it. Derived from stored reports,
333
+ never re-parsed logs, so a year of JSON is enough and the raw logs can be
334
+ thrown away. Shapes are named; nothing is forecast.
335
+
336
+ ${bold('OPTIONS FOR verify')}
337
+ --against <log|dir> The newer usage log the plan is held to. Required.
338
+ --gate Exit 1 when an action did not produce what the
339
+ plan promised, or its fields stopped being
340
+ recorded — "not recorded" must not read as
341
+ "fixed". A vanished workload fails nothing.
342
+ --markdown-out <file> Also write the verdicts as Markdown, for a CI
343
+ job summary or a pull request comment.
344
+ --pricing <file> Local price overlay, as everywhere else.
345
+ --json The verification as data.
346
+
347
+ Holds a saved plan to the log that came after it, with three outcomes and
348
+ never two: the change arrived, it did not, or it cannot be told — because
349
+ the workload vanished, the fields the detection needs stopped being
350
+ recorded, or tokens cannot say which tier billed them. Differences carry
351
+ the world's measured movement (calls, output per call) from the plan's own
352
+ baseline, and a plan priced under a different catalogue says so rather
353
+ than blaming a team for a saving that arithmetic revoked.
354
+
320
355
  ${bold('OPTIONS FOR route')}
321
356
  --prompt-file <file> The prompt those calls send. Not --prompt, which
322
357
  names a marked prompt inside a source file.
@@ -1412,6 +1447,94 @@ ${bold('EXAMPLES')}
1412
1447
  `Plan written to ${path}, dated. Keep it: a prediction nobody wrote down is a prediction nobody can be held to.`,
1413
1448
  },
1414
1449
 
1450
+ history: {
1451
+ noTarget: () =>
1452
+ 'Point this at a directory of stored reports: trazum history reports/. It reads the --json documents "trazum profile" writes (and any saved plans beside them) and builds the series no pairwise comparison can see.',
1453
+ needsThree: (count) =>
1454
+ `A series needs at least three dated reports, and this directory has ${count}. Two reports is a comparison, and "trazum profile --against" already does that better.`,
1455
+ heading: (periods, from, to) => `The long run: ${periods} periods, ${from} → ${to}`,
1456
+ periodRow: (name, usd, calls, days) => `${name} ${usd} · ${calls} calls · ${days} days`,
1457
+ runLabel: (label, periods, sinceName, from, to) =>
1458
+ `${label} has climbed for ${periods} consecutive periods since ${sinceName}: ${from} → ${to}. A shape, not a forecast.`,
1459
+ runModel: (model, periods, sinceName, from, to) =>
1460
+ `${model}'s share of the bill has climbed for ${periods} consecutive periods since ${sinceName}: ${from} → ${to}. The totals can look flat while the mix moves under them.`,
1461
+ runCache: (periods, sinceName, from, to) =>
1462
+ `The cache share has decayed for ${periods} consecutive periods since ${sinceName}: ${from} → ${to} — slowly enough that no single report called it a finding, which is exactly why a series exists.`,
1463
+ repeated: (kind, label, model, appearances, first, last) => {
1464
+ const what =
1465
+ kind === 'route'
1466
+ ? `Routing ${label} (${model})`
1467
+ : kind === 'batch'
1468
+ ? `Batching ${label} (${model})`
1469
+ : kind === 'route+batch'
1470
+ ? `Routing and batching ${label} (${model})`
1471
+ : kind === 'fix-truncation'
1472
+ ? `Fixing the truncation retries on ${label} (${model})`
1473
+ : `Fixing the cache on ${label} (${model})`;
1474
+ const span = first !== null && last !== null ? ` (${first} → ${last})` : '';
1475
+ return `${what} has been planned ${appearances} times${span} and is still in the newest plan — a decision nobody is revisiting.`;
1476
+ },
1477
+ undated: (name) => `${name} carries no span, so it is on no timeline above — named, never silently absorbed.`,
1478
+ unrecognized: (name) => `${name} is neither a stored report nor a saved plan, so it is in no series above.`,
1479
+ footer: () =>
1480
+ 'A series names shapes, not futures. Twenty points make a trend visible; they do not make next month knowable — where these lines go next is yours to judge.',
1481
+ },
1482
+
1483
+ verify: {
1484
+ noTarget: () =>
1485
+ 'Point this at a saved plan and a newer log: trazum verify plan.json --against usage.jsonl. It says, per action, whether the change arrived, did not arrive, or cannot be told — and never fewer than those three.',
1486
+ needsAgainst: () =>
1487
+ '--against <newer.jsonl|dir> is required. A plan can only be verified against a log that came after it; without one there is nothing to hold the prediction to.',
1488
+ badPlan: (path) =>
1489
+ `${path} is not a plan document this tool can verify — expected the JSON that "trazum plan -o" writes (schemaVersion 1, with an actions array).`,
1490
+ heading: (actions, planDate) =>
1491
+ planDate === null
1492
+ ? `Did it work? ${actions} actions from an undated plan, against this log`
1493
+ : `Did it work? ${actions} actions from the plan of ${planDate}, against this log`,
1494
+ counts: (arrived, notArrived, cannotTell) =>
1495
+ `${arrived} arrived · ${notArrived} did not arrive · ${cannotTell} cannot be told. The third is not a soft version of the second: it means this log cannot answer, which is its own finding.`,
1496
+ pricesChanged: (planReviewed, nowReviewed) =>
1497
+ `Prices were reviewed ${planReviewed} when the plan was made and ${nowReviewed} now, so every dollar comparison here is two price lists, not one measurement — a team must not be blamed for a saving that arithmetic revoked.`,
1498
+ action: (kind, label, model, outcome) => {
1499
+ const what =
1500
+ kind === 'route'
1501
+ ? `Route ${label} (${model})`
1502
+ : kind === 'batch'
1503
+ ? `Batch ${label} (${model})`
1504
+ : kind === 'route+batch'
1505
+ ? `Route and batch ${label} (${model})`
1506
+ : kind === 'fix-truncation'
1507
+ ? `Fix the truncation retries on ${label} (${model})`
1508
+ : `Fix the cache on ${label} (${model})`;
1509
+ const verdict =
1510
+ outcome === 'arrived' ? 'ARRIVED' : outcome === 'not-arrived' ? 'DID NOT ARRIVE' : 'CANNOT BE TOLD';
1511
+ return `${what} — ${verdict}`;
1512
+ },
1513
+ reason: (reason) =>
1514
+ reason === 'workload-vanished'
1515
+ ? 'the label carries no priced traffic in this log — a vanished workload is not a fixed one, and not a broken one either'
1516
+ : reason === 'fields-stopped'
1517
+ ? 'the fields the detection needs are not in this log — "not recorded" must not read as "fixed", so with --gate this fails'
1518
+ : 'the log records tokens, and tokens do not say which tier billed them — the Batch API cannot be seen from here',
1519
+ routeObserved: (dearestModel, onTargetUsd, onOldUsd) =>
1520
+ `the label's dearest model is now ${dearestModel} · ${onTargetUsd} on the target, ${onOldUsd} still on the old model`,
1521
+ batchUnobservable: () =>
1522
+ 'the batch half of this action cannot be seen in token counts; the verdict above is the route half alone',
1523
+ truncationObserved: (retryBillUsd) =>
1524
+ `this log still shows ${retryBillUsd} of truncation waste and retries`,
1525
+ cacheObserved: (deltaUsd, outcome) =>
1526
+ outcome === 'arrived'
1527
+ ? `caching now pays for itself on this slice (${deltaUsd} against the no-cache bill)`
1528
+ : `caching still adds ${deltaUsd} to this slice's bill`,
1529
+ attribution: (callsBefore, callsAfter, outBefore, outAfter) =>
1530
+ `the world moved too: calls ${callsBefore} → ${callsAfter}, output/call ${outBefore} → ${outAfter} tokens — stated so the verdict is not read as the whole story`,
1531
+ gateFailed: (failures, total) =>
1532
+ `GATE FAILED — ${failures} of ${total} actions did not produce what the plan promised, or stopped being measurable by the team's own log.`,
1533
+ gateOk: () => 'Gate passed: every verifiable action arrived, and nothing became unverifiable.',
1534
+ footer: () =>
1535
+ 'Arrived and did-not-arrive are measurements; cannot-be-told is the log refusing to guess. All three are the verification working, not failing.',
1536
+ },
1537
+
1415
1538
  route: {
1416
1539
  noTarget: () =>
1417
1540
  'Point this at a usage log and a prompt: trazum route usage.jsonl --prompt-file prompts/support.txt --cases cases.txt --yes. It finds the slice worth the most, then measures whether the cheaper model still does the job. The flag is --prompt-file and not --prompt, because --prompt names a marked prompt inside a source file everywhere else in this tool.',
package/src/i18n/es.ts CHANGED
@@ -27,6 +27,8 @@ ${bold('USO')}
27
27
  trazum eval <fichero> --cases <fichero> --export promptfoo -o suite.json
28
28
  trazum route <log.jsonl> --prompt-file <fichero> --cases <fichero> --yes
29
29
  trazum plan <log.jsonl|dir> [opciones]
30
+ trazum verify <plan.json> --against <nuevo.jsonl|dir> [opciones]
31
+ trazum history <dir-de-informes-guardados> [opciones]
30
32
  trazum diff <antes> <después> [opciones]
31
33
  trazum diff --all <dir> <dir> [opciones]
32
34
  trazum rank <dir> [opciones]
@@ -324,6 +326,42 @@ ${bold('OPCIONES DE plan')}
324
326
  consejo haciéndose pasar por aritmética. El ahorro proyectado y el dinero ya
325
327
  gastado son totales separados en todas partes.
326
328
 
329
+ ${bold('OPCIONES DE history')}
330
+ --markdown-out <fichero> Escribe además la serie como Markdown, para un
331
+ resumen de CI o un comentario de pull request.
332
+ --json La historia como datos.
333
+
334
+ Toma un directorio de informes guardados — los documentos --json que
335
+ profile ya escribe — más los planes guardados que haya al lado, y construye
336
+ la serie que ninguna comparación por pares puede ver: una carga que sube un
337
+ poco cada período, una cuota de modelo creciendo desde una fecha, una cuota
338
+ de caché decayendo tan despacio que ningún informe semanal lo llamó
339
+ hallazgo, y la misma acción planificada una y otra vez sin que nadie la
340
+ ejecute. Derivada de informes guardados, nunca de registros re-parseados:
341
+ un año de JSON basta y los registros crudos pueden tirarse. Las formas se
342
+ nombran; nada se pronostica.
343
+
344
+ ${bold('OPCIONES DE verify')}
345
+ --against <log|dir> El registro de uso posterior al que se somete el
346
+ plan. Obligatorio.
347
+ --gate Sale con 1 cuando una acción no produjo lo que el
348
+ plan prometió, o sus campos dejaron de
349
+ registrarse — "no registrado" no puede leerse
350
+ como "arreglado". Una carga de trabajo
351
+ desaparecida no suspende nada.
352
+ --markdown-out <fichero> Escribe además los veredictos como Markdown, para
353
+ un resumen de CI o un comentario de pull request.
354
+ --pricing <fichero> Tarifas locales superpuestas, como en el resto.
355
+ --json La verificación como datos.
356
+
357
+ Somete un plan guardado al registro que vino después, con tres resultados y
358
+ nunca dos: el cambio llegó, no llegó, o no se puede saber — porque la carga
359
+ desapareció, los campos que la detección necesita dejaron de registrarse, o
360
+ los tokens no dicen con qué tarifa se facturaron. Las diferencias llevan el
361
+ movimiento medido del mundo (llamadas, salida por llamada) desde la línea
362
+ base del propio plan, y un plan tasado con otro catálogo lo dice en vez de
363
+ culpar a un equipo por un ahorro que la aritmética revocó.
364
+
327
365
  ${bold('OPCIONES DE route')}
328
366
  --prompt-file <fichero> El prompt que mandan esas llamadas. No --prompt,
329
367
  que nombra un prompt marcado dentro de un fuente.
@@ -1432,6 +1470,94 @@ ${bold('EJEMPLOS')}
1432
1470
  `Plan escrito en ${path}, con fecha. Guárdalo: una predicción que nadie apuntó es una predicción que no se le puede exigir a nadie.`,
1433
1471
  },
1434
1472
 
1473
+ history: {
1474
+ noTarget: () =>
1475
+ 'Apunta esto a un directorio de informes guardados: trazum history informes/. Lee los documentos --json que escribe "trazum profile" (y los planes guardados que haya al lado) y construye la serie que ninguna comparación por pares puede ver.',
1476
+ needsThree: (count) =>
1477
+ `Una serie necesita al menos tres informes con fecha, y este directorio tiene ${count}. Dos informes son una comparación, y "trazum profile --against" ya la hace mejor.`,
1478
+ heading: (periods, from, to) => `La larga distancia: ${periods} períodos, ${from} → ${to}`,
1479
+ periodRow: (name, usd, calls, days) => `${name} ${usd} · ${calls} llamadas · ${days} días`,
1480
+ runLabel: (label, periods, sinceName, from, to) =>
1481
+ `${label} lleva ${periods} períodos consecutivos subiendo desde ${sinceName}: ${from} → ${to}. Una forma, no un pronóstico.`,
1482
+ runModel: (model, periods, sinceName, from, to) =>
1483
+ `La cuota de ${model} en la factura lleva ${periods} períodos consecutivos subiendo desde ${sinceName}: ${from} → ${to}. Los totales pueden parecer planos mientras la mezcla se mueve debajo.`,
1484
+ runCache: (periods, sinceName, from, to) =>
1485
+ `La cuota de caché lleva ${periods} períodos consecutivos decayendo desde ${sinceName}: ${from} → ${to} — tan despacio que ningún informe suelto lo llamó hallazgo, que es exactamente para lo que existe una serie.`,
1486
+ repeated: (kind, label, model, appearances, first, last) => {
1487
+ const what =
1488
+ kind === 'route'
1489
+ ? `Enrutar ${label} (${model})`
1490
+ : kind === 'batch'
1491
+ ? `Agrupar en batch ${label} (${model})`
1492
+ : kind === 'route+batch'
1493
+ ? `Enrutar y agrupar ${label} (${model})`
1494
+ : kind === 'fix-truncation'
1495
+ ? `Arreglar los reintentos por truncado de ${label} (${model})`
1496
+ : `Arreglar la caché de ${label} (${model})`;
1497
+ const span = first !== null && last !== null ? ` (${first} → ${last})` : '';
1498
+ return `${what} se ha planificado ${appearances} veces${span} y sigue en el plan más reciente — una decisión que nadie está revisando.`;
1499
+ },
1500
+ undated: (name) => `${name} no lleva período, así que no está en ninguna línea de tiempo de arriba — nombrado, nunca absorbido en silencio.`,
1501
+ unrecognized: (name) => `${name} no es ni un informe guardado ni un plan guardado, así que no está en ninguna serie de arriba.`,
1502
+ footer: () =>
1503
+ 'Una serie nombra formas, no futuros. Veinte puntos hacen visible una tendencia; no hacen conocible el mes que viene — adónde van estas líneas después lo juzgas tú.',
1504
+ },
1505
+
1506
+ verify: {
1507
+ noTarget: () =>
1508
+ 'Apunta esto a un plan guardado y a un registro posterior: trazum verify plan.json --against usage.jsonl. Dice, por acción, si el cambio llegó, no llegó o no se puede saber — y nunca menos de esos tres.',
1509
+ needsAgainst: () =>
1510
+ '--against <nuevo.jsonl|dir> es obligatorio. Un plan solo puede verificarse contra un registro posterior; sin uno no hay nada a lo que someter la predicción.',
1511
+ badPlan: (path) =>
1512
+ `${path} no es un documento de plan que esta herramienta pueda verificar — se esperaba el JSON que escribe "trazum plan -o" (schemaVersion 1, con un array actions).`,
1513
+ heading: (actions, planDate) =>
1514
+ planDate === null
1515
+ ? `¿Funcionó? ${actions} acciones de un plan sin fecha, contra este registro`
1516
+ : `¿Funcionó? ${actions} acciones del plan del ${planDate}, contra este registro`,
1517
+ counts: (arrived, notArrived, cannotTell) =>
1518
+ `${arrived} llegaron · ${notArrived} no llegaron · ${cannotTell} no se puede saber. Lo tercero no es una versión suave de lo segundo: significa que este registro no puede responder, y eso es un hallazgo en sí.`,
1519
+ pricesChanged: (planReviewed, nowReviewed) =>
1520
+ `Las tarifas se revisaron el ${planReviewed} cuando se hizo el plan y el ${nowReviewed} ahora, así que cada comparación en dólares aquí son dos listas de precios, no una medición — no se puede culpar a un equipo por un ahorro que la aritmética revocó.`,
1521
+ action: (kind, label, model, outcome) => {
1522
+ const what =
1523
+ kind === 'route'
1524
+ ? `Enrutar ${label} (${model})`
1525
+ : kind === 'batch'
1526
+ ? `Agrupar en batch ${label} (${model})`
1527
+ : kind === 'route+batch'
1528
+ ? `Enrutar y agrupar ${label} (${model})`
1529
+ : kind === 'fix-truncation'
1530
+ ? `Arreglar los reintentos por truncado de ${label} (${model})`
1531
+ : `Arreglar la caché de ${label} (${model})`;
1532
+ const verdict =
1533
+ outcome === 'arrived' ? 'LLEGÓ' : outcome === 'not-arrived' ? 'NO LLEGÓ' : 'NO SE PUEDE SABER';
1534
+ return `${what} — ${verdict}`;
1535
+ },
1536
+ reason: (reason) =>
1537
+ reason === 'workload-vanished'
1538
+ ? 'el label no lleva tráfico tasado en este registro — una carga desaparecida no está arreglada, y tampoco rota'
1539
+ : reason === 'fields-stopped'
1540
+ ? 'los campos que la detección necesita no están en este registro — "no registrado" no puede leerse como "arreglado", así que con --gate esto suspende'
1541
+ : 'el registro guarda tokens, y los tokens no dicen con qué tarifa se facturaron — el Batch API no se puede ver desde aquí',
1542
+ routeObserved: (dearestModel, onTargetUsd, onOldUsd) =>
1543
+ `el modelo más caro del label ahora es ${dearestModel} · ${onTargetUsd} en el destino, ${onOldUsd} todavía en el modelo antiguo`,
1544
+ batchUnobservable: () =>
1545
+ 'la mitad batch de esta acción no se puede ver en los recuentos de tokens; el veredicto de arriba es solo la mitad de la ruta',
1546
+ truncationObserved: (retryBillUsd) =>
1547
+ `este registro todavía muestra ${retryBillUsd} de desperdicio y reintentos por truncado`,
1548
+ cacheObserved: (deltaUsd, outcome) =>
1549
+ outcome === 'arrived'
1550
+ ? `la caché ahora se paga sola en esta porción (${deltaUsd} contra la factura sin caché)`
1551
+ : `la caché todavía añade ${deltaUsd} a la factura de esta porción`,
1552
+ attribution: (callsBefore, callsAfter, outBefore, outAfter) =>
1553
+ `el mundo también se movió: llamadas ${callsBefore} → ${callsAfter}, salida/llamada ${outBefore} → ${outAfter} tokens — dicho para que el veredicto no se lea como toda la historia`,
1554
+ gateFailed: (failures, total) =>
1555
+ `GATE SUSPENDIDO — ${failures} de ${total} acciones no produjeron lo que el plan prometió, o dejaron de poder medirse por el propio registro del equipo.`,
1556
+ gateOk: () => 'Gate superado: toda acción verificable llegó, y nada se volvió inverificable.',
1557
+ footer: () =>
1558
+ 'Llegó y no-llegó son mediciones; no-se-puede-saber es el registro negándose a adivinar. Los tres son la verificación funcionando, no fallando.',
1559
+ },
1560
+
1435
1561
  route: {
1436
1562
  noTarget: () =>
1437
1563
  'Apunta esto a un registro de uso y a un prompt: trazum route usage.jsonl --prompt-file prompts/soporte.txt --cases casos.txt --yes. Busca la porción que más vale y mide si el modelo más barato sigue haciendo el trabajo. El flag es --prompt-file y no --prompt, porque en el resto de la herramienta --prompt nombra un prompt marcado dentro de un fichero fuente.',
package/src/i18n/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { EvalVerdict, Locale, PlanActionKind, PlanAssumption, RuleLevel } from '@trazum/core';
1
+ import type { CannotTellReason, EvalVerdict, Locale, PlanActionKind, PlanAssumption, RuleLevel, VerifyOutcome } from '@trazum/core';
2
2
 
3
3
  /**
4
4
  * The CLI's own message catalogue.
@@ -1072,6 +1072,60 @@ export interface CliMessages {
1072
1072
  wrote(path: string): string;
1073
1073
  };
1074
1074
 
1075
+ /**
1076
+ * `trazum history` — many reports over many periods, as one series.
1077
+ *
1078
+ * Shapes are named as consecutive movement, never a fitted line, and no
1079
+ * series becomes a forecast: where the line goes next stays the reader's.
1080
+ */
1081
+ history: {
1082
+ noTarget(): string;
1083
+ /** Under three dated reports there is no series — only the comparison --against already does. */
1084
+ needsThree(count: string): string;
1085
+ heading(periods: string, from: string, to: string): string;
1086
+ periodRow(name: string, usd: string, calls: string, days: string): string;
1087
+ runLabel(label: string, periods: string, sinceName: string, from: string, to: string): string;
1088
+ runModel(model: string, periods: string, sinceName: string, from: string, to: string): string;
1089
+ runCache(periods: string, sinceName: string, from: string, to: string): string;
1090
+ /** The same action in plan after plan: a decision nobody is executing. */
1091
+ repeated(kind: PlanActionKind, label: string, model: string, appearances: string, first: string | null, last: string | null): string;
1092
+ undated(name: string): string;
1093
+ unrecognized(name: string): string;
1094
+ footer(): string;
1095
+ };
1096
+
1097
+ /**
1098
+ * `trazum verify` — the plan held to the log that came after it.
1099
+ *
1100
+ * Three outcomes and never two: arrived, did not arrive, cannot be told.
1101
+ * The third is the honest one, and the one every other tool renders as
1102
+ * the first. Differences carry the world's measured movement, and a plan
1103
+ * priced under another catalogue says so rather than blaming a team for
1104
+ * a saving that arithmetic revoked.
1105
+ */
1106
+ verify: {
1107
+ noTarget(): string;
1108
+ needsAgainst(): string;
1109
+ /** Not a plan document: wrong shape, wrong version, or not JSON at all. */
1110
+ badPlan(path: string): string;
1111
+ heading(actions: string, planDate: string | null): string;
1112
+ counts(arrived: string, notArrived: string, cannotTell: string): string;
1113
+ /** Two price lists are two measurements; every dollar line inherits this. */
1114
+ pricesChanged(planReviewed: string, nowReviewed: string): string;
1115
+ action(kind: PlanActionKind, label: string, model: string, outcome: VerifyOutcome): string;
1116
+ reason(reason: CannotTellReason): string;
1117
+ routeObserved(dearestModel: string, onTargetUsd: string, onOldUsd: string): string;
1118
+ /** Tokens do not say which tier billed them; named, never assumed arrived. */
1119
+ batchUnobservable(): string;
1120
+ truncationObserved(retryBillUsd: string): string;
1121
+ cacheObserved(deltaUsd: string, outcome: VerifyOutcome): string;
1122
+ /** The world's movement, measured: never a verdict, always both numbers. */
1123
+ attribution(callsBefore: string, callsAfter: string, outBefore: string, outAfter: string): string;
1124
+ gateFailed(failures: string, total: string): string;
1125
+ gateOk(): string;
1126
+ footer(): string;
1127
+ };
1128
+
1075
1129
  /**
1076
1130
  * `trazum route` — the loop the levers section could only point at.
1077
1131
  *