@shield-agent/kya 0.32.4 → 0.32.6-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/.cursor-plugin/plugin.json +2 -2
  2. package/.mcp.json +1 -1
  3. package/LICENSE +1 -1
  4. package/LIMITATIONS.md +3 -1
  5. package/README.md +58 -50
  6. package/amp/settings.example.json +1 -1
  7. package/catalog/agent-trust-baseline-v0.json +75 -75
  8. package/claude/claude_desktop_config.example.json +1 -1
  9. package/cline/cline_mcp_settings.example.json +1 -1
  10. package/copilot/mcp-config.example.json +1 -1
  11. package/dist/certify/evaluate.js +23 -23
  12. package/dist/certify/evaluate.js.map +1 -1
  13. package/dist/client.d.ts +29 -3
  14. package/dist/client.d.ts.map +1 -1
  15. package/dist/client.js +121 -13
  16. package/dist/client.js.map +1 -1
  17. package/dist/commands/orr.d.ts.map +1 -1
  18. package/dist/commands/orr.js +43 -43
  19. package/dist/commands/orr.js.map +1 -1
  20. package/dist/commands/team.d.ts +4 -0
  21. package/dist/commands/team.d.ts.map +1 -1
  22. package/dist/commands/team.js +12 -9
  23. package/dist/commands/team.js.map +1 -1
  24. package/dist/errors.d.ts +3 -1
  25. package/dist/errors.d.ts.map +1 -1
  26. package/dist/errors.js +12 -1
  27. package/dist/errors.js.map +1 -1
  28. package/dist/notify/index.d.ts +1 -1
  29. package/dist/notify/index.d.ts.map +1 -1
  30. package/dist/notify/index.js +2 -2
  31. package/dist/notify/index.js.map +1 -1
  32. package/dist/notify/templates.d.ts +18 -2
  33. package/dist/notify/templates.d.ts.map +1 -1
  34. package/dist/notify/templates.js +56 -1
  35. package/dist/notify/templates.js.map +1 -1
  36. package/dist/receipt/live-server.js +1 -1
  37. package/dist/receipt/live-server.js.map +1 -1
  38. package/dist/receipt/render-receipt.d.ts.map +1 -1
  39. package/dist/receipt/render-receipt.js +61 -49
  40. package/dist/receipt/render-receipt.js.map +1 -1
  41. package/dist/update-check.d.ts +5 -0
  42. package/dist/update-check.d.ts.map +1 -1
  43. package/dist/update-check.js +38 -5
  44. package/dist/update-check.js.map +1 -1
  45. package/droid/README.md +1 -1
  46. package/droid/mcp.example.json +1 -1
  47. package/gemini/settings.example.json +1 -1
  48. package/grok/README.md +1 -1
  49. package/kilo/kilo.example.json +1 -1
  50. package/kimi/mcp.example.json +1 -1
  51. package/kiro/mcp.example.json +1 -1
  52. package/manifest.json +1 -1
  53. package/mastracode/mcp.example.json +1 -1
  54. package/mcp.json +1 -1
  55. package/openai/codex.config.example.toml +1 -1
  56. package/opencode/opencode.example.json +1 -1
  57. package/package.json +2 -2
  58. package/qwen/settings.example.json +1 -1
  59. package/server.json +2 -2
@@ -579,7 +579,7 @@ function reasonsPanel(agg) {
579
579
  .map((r) => `<span class="chip"><code>${esc(clip(r.label, 60))}</code> × ${r.count}</span>`)
580
580
  .join("\n ");
581
581
  return `<section class="panel" aria-label="Reasons">
582
- <h2>Reasons</h2>
582
+ <h2>Why calls were allowed, held, or blocked</h2>
583
583
  <div class="chiprow">
584
584
  ${chips}
585
585
  </div>
@@ -689,7 +689,7 @@ function wiredHostsPanel(hosts) {
689
689
  })
690
690
  .join("\n ");
691
691
  return `<section class="panel" aria-label="Wired hosts">
692
- <h2>Wired hosts</h2>
692
+ <h2>Connected tools</h2>
693
693
  <ul class="rows">
694
694
  ${rows}
695
695
  </ul>
@@ -774,7 +774,7 @@ function capabilitiesPanel(model) {
774
774
  },
775
775
  {
776
776
  name: "ORR board",
777
- blurb: "Operational readiness review across producers",
777
+ blurb: "Checks if your agent setup is safe to run",
778
778
  live: !!model.orr,
779
779
  liveLabel: "ran",
780
780
  setup: "runs automatically at <code>kya start</code>; refresh with <code>kya orr run</code>",
@@ -1273,20 +1273,20 @@ function orrPanel(orr, nowMs, live) {
1273
1273
  : "";
1274
1274
  if (!orr) {
1275
1275
  return `<section class="panel" aria-label="ORR">
1276
- <h2>Operational readiness</h2>
1277
- <p class="line">No ORR board yet. kya runs one automatically when the report starts and refreshes it every 30 minutes; the board rates operational readiness across producers.</p>
1276
+ <h2>Readiness check</h2>
1277
+ <p class="line">No readiness board yet. kya runs one when the report starts and refreshes it every 30 minutes. The board checks if your agent setup is safe to run.</p>
1278
1278
  <p class="mute small">CLI: <code>kya orr run --path .</code></p>
1279
1279
  ${run}
1280
1280
  </section>`;
1281
1281
  }
1282
1282
  const target = orr.targetName
1283
- ? `<span class="mute">target ${esc(clip(orr.targetName, 60))}</span>`
1283
+ ? `<span class="mute">checked ${esc(clip(orr.targetName, 60))}</span>`
1284
1284
  : "";
1285
1285
  const failure = orr.primaryFailureMode
1286
- ? `<p class="line">Primary failure mode: ${esc(clip(orr.primaryFailureMode, 200))}</p>`
1286
+ ? `<p class="line">Main problem: ${esc(clip(orr.primaryFailureMode, 200))}</p>`
1287
1287
  : "";
1288
1288
  const fix = orr.mostUrgentFix
1289
- ? `<p class="line">Most urgent fix: ${esc(clip(orr.mostUrgentFix, 200))}</p>`
1289
+ ? `<p class="line">First fix to make: ${esc(clip(orr.mostUrgentFix, 200))}</p>`
1290
1290
  : "";
1291
1291
  const when = orr.generatedAt ? ` · ${esc(relativeTime(orr.generatedAt, nowMs))}` : "";
1292
1292
  const findings = orr.findings.length
@@ -1303,19 +1303,31 @@ function orrPanel(orr, nowMs, live) {
1303
1303
  .join("")}</ul>`
1304
1304
  : "";
1305
1305
  return `<section class="panel" aria-label="ORR">
1306
- <h2>Operational readiness</h2>
1306
+ <h2>Readiness check</h2>
1307
1307
  <div class="orrline">
1308
1308
  <span class="pill orr-${esc(orr.overall)}">${esc(orr.overall)}</span>
1309
- <span class="disp">${esc(orr.disposition.replace(/_/g, " "))}</span>
1309
+ <span class="disp">${esc(dispositionWord(orr.disposition))}</span>
1310
1310
  ${target}
1311
1311
  </div>
1312
1312
  ${failure}
1313
1313
  ${fix}
1314
1314
  ${findings}
1315
- <p class="mute small">scorecards: ${orr.scorecards.pass} pass · ${orr.scorecards.fail} fail · ${orr.scorecards.partial} partial · ${orr.scorecards.notEvaluated} n/e${when} · auto-refreshes every 30 min while the report runs</p>
1315
+ <p class="mute small">checks: ${orr.scorecards.pass} pass · ${orr.scorecards.fail} fail · ${orr.scorecards.partial} partial · ${orr.scorecards.notEvaluated} n/e${when} · refreshes every 30 min while the report runs</p>
1316
1316
  ${run}
1317
1317
  </section>`;
1318
1318
  }
1319
+ function dispositionWord(disposition) {
1320
+ switch (disposition) {
1321
+ case "go":
1322
+ return "safe to run";
1323
+ case "conditional":
1324
+ return "fix before production";
1325
+ case "no_go":
1326
+ return "not safe to run";
1327
+ default:
1328
+ return disposition.replace(/_/g, " ");
1329
+ }
1330
+ }
1319
1331
  function severityCls(severity) {
1320
1332
  if (severity === "critical" || severity === "high")
1321
1333
  return "orr-red";
@@ -1342,20 +1354,20 @@ function kpiTile(label, value, cls = "") {
1342
1354
  function heroCertifyPanel(certify) {
1343
1355
  if (!certify) {
1344
1356
  return `<section class="panel hero-certify none" id="frag-hero-certify" aria-label="Certify">
1345
- <h2>Certify - Agent Trust Baseline</h2>
1357
+ <h2>Certify - trust checklist for your agent</h2>
1346
1358
  <div class="orrline">
1347
- <span class="pill">not evaluated</span>
1359
+ <span class="pill">not checked yet</span>
1348
1360
  </div>
1349
- <p class="mute small">No live evaluation available - wrap tool calls and run kya certify to build the baseline.</p>
1361
+ <p class="mute small">No check yet - use your coding tools with kya connected, then run kya certify.</p>
1350
1362
  </section>`;
1351
1363
  }
1352
1364
  const state = certify.result === "pass" ? "pass" : "gap";
1353
1365
  // Status legend as a definition list so each counter is explained on first
1354
1366
  // glance, not hidden in a dense sentence.
1355
1367
  const legend = `<dl class="cert-legend">
1356
- <div><dt>Gap</dt><dd>requirement is failing - this is your work plan</dd></div>
1357
- <div><dt>Insufficient</dt><dd>not enough local evidence to evaluate (never counts as a pass)</dd></div>
1358
- <div><dt>Attested</dt><dd>your signed statement, unverified until audited</dd></div>
1368
+ <div><dt>Failing</dt><dd>these rules fail right now - do these first</dd></div>
1369
+ <div><dt>No data</dt><dd>not enough local data to decide (never counts as a pass)</dd></div>
1370
+ <div><dt>Attested</dt><dd>your written statement, not verified</dd></div>
1359
1371
  </dl>`;
1360
1372
  // Attested summary: the hero's gap rows are gap-status only, so attestations
1361
1373
  // surface as one line naming the first attested requirement (+N more) with
@@ -1365,7 +1377,7 @@ function heroCertifyPanel(certify) {
1365
1377
  ? ""
1366
1378
  : firstAttested
1367
1379
  ? `<div class="att-line">attested: <code>${esc(firstAttested.id)}</code>${certify.attested > 1 ? ` (+${certify.attested - 1} more)` : ""} - "${expandableText("att-quote", firstAttested.attestation?.text ?? firstAttested.evidence, 100)}"</div>`
1368
- : `<p class="att-line">attested: ${certify.attested} - your signed statement, unverified</p>`;
1380
+ : `<p class="att-line">attested: ${certify.attested} - your written statement, not verified</p>`;
1369
1381
  // topGaps arrives severity-ordered from the loader; cap defensively at 5.
1370
1382
  // Each gap is an expandable <details> row: summary stays compact, the body
1371
1383
  // reveals the full requirement title, what the status means, the unclipped
@@ -1380,9 +1392,9 @@ ${certify.topGaps
1380
1392
  return ` <details class="req-row">
1381
1393
  <summary><code>${esc(g.id)}</code> - ${esc(g.title)} <span class="sev ${esc(g.severity)}">${esc(g.severity)}</span></summary>
1382
1394
  <div class="req-body">
1383
- <p class="req-mean">Gap means this requirement is currently failing against the local evidence in the ${certify.windowDays}-day window.</p>
1384
- ${g.evidence ? `<p class="req-evi"><strong>Evidence:</strong> ${esc(g.evidence)}</p>` : ""}
1385
- <p class="req-cta"><strong>Close it:</strong> <code>${esc(cmd)}</code> <span class="req-hint">(replace "…" with your accountable statement or fix the underlying control)</span></p>
1395
+ <p class="req-mean">This rule is failing right now, based on activity in the last ${certify.windowDays} days.</p>
1396
+ ${g.evidence ? `<p class="req-evi"><strong>Why:</strong> ${esc(g.evidence)}</p>` : ""}
1397
+ <p class="req-cta"><strong>Fix it:</strong> <code>${esc(cmd)}</code> <span class="req-hint">(replace "…" with your answer, or fix the problem itself)</span></p>
1386
1398
  </div>
1387
1399
  </details>`;
1388
1400
  })
@@ -1390,26 +1402,26 @@ ${certify.topGaps
1390
1402
  </div>`;
1391
1403
  // Call-to-action: one primary command and one secondary link to the detail tab.
1392
1404
  const cta = `<div class="cert-cta">
1393
- <a class="btn" href="#certify">Open full requirement table</a>
1394
- <span class="mute small">or run <code>kya certify --open</code> for the signed bundle</span>
1405
+ <a class="btn" href="#certify">See all rules</a>
1406
+ <span class="mute small">or run <code>kya certify --open</code> for the signed proof file</span>
1395
1407
  </div>`;
1396
1408
  // Pill tones reuse the ORR palette: pass is green, gap is amber.
1397
1409
  return `<section class="panel hero-certify ${state}" id="frag-hero-certify" aria-label="Certify">
1398
- <h2>Certify - Agent Trust Baseline</h2>
1410
+ <h2>Certify - trust checklist for your agent</h2>
1399
1411
  <div class="orrline">
1400
- <span class="pill orr-${state === "pass" ? "green" : "amber"}">${esc(certify.result)}</span>
1412
+ <span class="pill orr-${state === "pass" ? "green" : "amber"}">${esc(certify.result === "pass" ? "pass" : "has gaps")}</span>
1401
1413
  </div>
1402
1414
  <div class="kpi-row">
1403
1415
  ${kpiTile("Pass", certify.pass, "ok")}
1404
- ${kpiTile("Gap", certify.gap, "warn")}
1405
- ${kpiTile("Insufficient", certify.insufficientEvidence, "mute")}
1416
+ ${kpiTile("Failing", certify.gap, "warn")}
1417
+ ${kpiTile("No data", certify.insufficientEvidence, "mute")}
1406
1418
  ${kpiTile("Attested", certify.attested, "mute")}
1407
1419
  </div>
1408
1420
  ${legend}
1409
1421
  ${attestedLine}
1410
1422
  ${gaps}
1411
1423
  ${cta}
1412
- <p class="mute small">live evaluation - window ${certify.windowDays}d, ${certify.trailEvents} trail events · the Certify tab has the complete gap report · <code>kya certify</code> writes the signed evidence bundle</p>
1424
+ <p class="mute small">checked live - last ${certify.windowDays} days, ${certify.trailEvents} recorded events · the Certify tab lists every rule · <code>kya certify</code> writes the signed proof file</p>
1413
1425
  </section>`;
1414
1426
  }
1415
1427
  /** Detail-table pill tones, reusing the existing pill/tone system: pass is
@@ -1482,7 +1494,7 @@ ${items}
1482
1494
  })
1483
1495
  .join("\n");
1484
1496
  return `<section class="panel certify-detail" aria-label="Certify detail">
1485
- <h2>Every requirement - live evaluation</h2>
1497
+ <h2>Every rule, checked live</h2>
1486
1498
  ${sections}
1487
1499
  </section>`;
1488
1500
  }
@@ -1496,7 +1508,7 @@ function verdictsHeroCard(c, total) {
1496
1508
  const pct = (n) => (total > 0 ? Math.round((n / total) * 100) : 0);
1497
1509
  const mixRow = (label, n, fill) => `<div class="mix-row"><span class="mix-lab">${label}</span><span class="mix-bar"><span class="mix-fill ${fill}" style="width:${pct(n)}%"></span></span><span class="mix-num">${n}</span></div>`;
1498
1510
  return `<section class="panel" aria-label="Verdicts">
1499
- <h2>Verdicts</h2>
1511
+ <h2>Decisions</h2>
1500
1512
  <div class="mix">
1501
1513
  ${mixRow("Allow", c.allow, "ok")}
1502
1514
  ${mixRow("Deny", c.deny, "bad")}
@@ -1558,7 +1570,7 @@ ${topRuns
1558
1570
  .join("\n")}
1559
1571
  </ul>`;
1560
1572
  return `<section class="panel" aria-label="Showback">
1561
- <h2>Showback (observe only)</h2>
1573
+ <h2>Token use and cost (information only)</h2>
1562
1574
  <div class="kpi-row">
1563
1575
  ${kpiTile("Tokens in", report.totalTokensIn)}
1564
1576
  ${kpiTile("Tokens out", report.totalTokensOut)}
@@ -1627,7 +1639,7 @@ function importHeroCard(card, nowMs, live) {
1627
1639
  : "";
1628
1640
  return `<section class="panel" aria-label="Import">
1629
1641
  <h2>Import</h2>
1630
- <p class="line">Nothing imported yet. Bring existing LangSmith, Langfuse, Phoenix, OTel, AGT, ADR Sensor, or OpenShell traces into the trail so they show up in this report and feed Certify.</p>
1642
+ <p class="line">Nothing imported yet. Import records from LangSmith, Langfuse, Phoenix, OTel, AGT, ADR Sensor, or OpenShell so they appear in this report and feed Certify.</p>
1631
1643
  <p class="mute small">CLI: <code>kya import --from langsmith|langfuse|phoenix|otel|adr-sensor|openshell FILE</code> · <code>kya import --from agt</code> reads the AGT audit log</p>
1632
1644
  ${form}
1633
1645
  </section>`;
@@ -1661,7 +1673,7 @@ function discoveryHeroCard(card, nowMs, live) {
1661
1673
  : "";
1662
1674
  return `<section class="panel" aria-label="Discovery">
1663
1675
  <h2>Discovery</h2>
1664
- <p class="line">No endpoint scan yet. Discovery inventories AI agents, IDE extensions, desktop apps, model runtimes, and MCP servers on this workstation. Home-directory paths are redacted.</p>
1676
+ <p class="line">No scan yet. Discovery lists the AI agents, IDE extensions, desktop apps, model runtimes, and MCP servers on this computer. Home folder paths are hidden.</p>
1665
1677
  <p class="mute small">CLI: <code>kya discover</code></p>
1666
1678
  ${scan}
1667
1679
  </section>`;
@@ -1701,14 +1713,14 @@ function investigateHeroCard(card, nowMs, live) {
1701
1713
  : "";
1702
1714
  return `<section class="panel" aria-label="Investigations">
1703
1715
  <h2>Investigations</h2>
1704
- <p class="line">No investigation has run yet. Deterministic detectors scan the trail for deny spikes, incidents, and risky patterns, then write fix briefs for your coding agent.</p>
1716
+ <p class="line">No investigation yet. Detectors scan the record for repeated blocks, incidents, and risky patterns, then write fix notes for your coding agent.</p>
1705
1717
  <p class="mute small">CLI: <code>kya investigate</code></p>
1706
1718
  ${run}
1707
1719
  </section>`;
1708
1720
  }
1709
1721
  const findingCount = card.findings.reduce((n, f) => n + f.count, 0);
1710
1722
  const rows = card.findings.length === 0
1711
- ? `<p class="line">No findings - the trail looks clean for all detectors.</p>`
1723
+ ? `<p class="line">No problems found - the record looks clean for all detectors.</p>`
1712
1724
  : `<ul class="rows">
1713
1725
  ${card.findings
1714
1726
  .map((f) => ` <li>${severityPill(f.severity)} <code>${esc(f.detectorId)}</code> - ${esc(f.title)} <span class="cnt">× ${f.count}</span></li>`)
@@ -1741,7 +1753,7 @@ function alertsPanel(card, nowMs, live) {
1741
1753
  : "";
1742
1754
  return `<section class="panel" aria-label="Alerts">
1743
1755
  <h2>Alerts</h2>
1744
- <p class="line">No alert deliveries yet. kya fires webhooks for DENY and REQUIRE_APPROVE verdicts; every delivery attempt is logged here per target.</p>
1756
+ <p class="line">No alerts sent yet. kya sends a webhook when a call is blocked or needs approval. Every attempt is logged here.</p>
1745
1757
  <p class="mute small">send a test alert to see the pipeline work (it uses a temporary loopback receiver until you configure <code>notify.webhooks</code> in .kya/config.json or set <code>KYA_NOTIFY_WEBHOOK</code>)</p>
1746
1758
  ${test}
1747
1759
  </section>`;
@@ -1784,8 +1796,8 @@ function otelPanel(stats, nowMs, live) {
1784
1796
  <div id="report-action-result-otel-test"></div>`
1785
1797
  : "";
1786
1798
  return `<section class="panel" aria-label="OTel export">
1787
- <h2>OTel export</h2>
1788
- <p class="line">No spans exported yet. kya can mirror verdict events to any OTLP/HTTP collector; sent and failed counts are tracked here.</p>
1799
+ <h2>Export to your monitoring (OTel)</h2>
1800
+ <p class="line">Nothing exported yet. kya can send decision events to your monitoring system (any OTLP/HTTP collector). Sent and failed counts appear here.</p>
1789
1801
  <p class="mute small">test the export now (it uses a temporary loopback collector until you configure <code>otlpExport.endpoint</code> in .kya/config.json or set <code>KYA_OTLP_EXPORT_ENDPOINT</code>)</p>
1790
1802
  ${test}
1791
1803
  </section>`;
@@ -1795,7 +1807,7 @@ function otelPanel(stats, nowMs, live) {
1795
1807
  ? `last export ${esc(relativeTime(stats.lastExportAt, nowMs))} · `
1796
1808
  : "";
1797
1809
  return `<section class="panel" aria-label="OTel export">
1798
- <h2>OTel export</h2>
1810
+ <h2>Export to your monitoring (OTel)</h2>
1799
1811
  <div class="orrline">${endpoint}</div>
1800
1812
  <div class="kpi-row">
1801
1813
  ${kpiTile("Spans sent", stats.spansSent)}
@@ -1917,7 +1929,7 @@ export function buildLiveFragments(model, livePaged) {
1917
1929
  showbackHeroCard(model.showback, events),
1918
1930
  ].join("\n "),
1919
1931
  overviewPanels: zoneBody([dashboardPanel(dashboard), sessionsPanel(agg, nowMs, changes), reasonsPanel(agg)], "No activity in this window yet - analytics appear once events land."),
1920
- certifyBody: zoneBody([model.certify ? certifyDetailPanel(model.certify.requirements) : ""], "No live evaluation yet - wrap tool calls and run kya certify to build the baseline."),
1932
+ certifyBody: zoneBody([model.certify ? certifyDetailPanel(model.certify.requirements) : ""], "No check yet - use your coding tools with kya connected, then run kya certify."),
1921
1933
  orrPanel: orrPanel(model.orr, nowMs, livePaged),
1922
1934
  changesList: changesPanel(changes, nowMs),
1923
1935
  },
@@ -2855,7 +2867,7 @@ export function renderReceiptMarkdown(model) {
2855
2867
  lines.push(`- \`${mdInline(g.id)}\` - ${mdText(g.title)} (${mdText(g.severity)})`);
2856
2868
  }
2857
2869
  }
2858
- lines.push(`live evaluation - window ${c.windowDays}d, ${c.trailEvents} trail events · the Certify tab has the full live requirement table · kya certify for the gap report + signed bundle`, "");
2870
+ lines.push(`checked live - last ${c.windowDays} days, ${c.trailEvents} recorded events · the Certify tab lists every rule · kya certify writes the gap report and signed proof file`, "");
2859
2871
  }
2860
2872
  const db = computeDashboard(model.events);
2861
2873
  if (db.verdictMix.total > 0) {
@@ -2927,7 +2939,7 @@ export function renderReceiptMarkdown(model) {
2927
2939
  lines.push("## Sessions", ...agg.sessions.map((s) => `- \`${mdInline(s.sessionId)}\` - ${s.events} event${s.events === 1 ? "" : "s"}, worst: ${s.worst}, last ${relativeTime(s.lastTs, nowMs)}`), "");
2928
2940
  }
2929
2941
  if (agg.reasons.length > 0) {
2930
- lines.push("## Reasons", ...agg.reasons.map((r) => `- ${mdText(r.label)} × ${r.count}`), "");
2942
+ lines.push("## Why calls were allowed, held, or blocked", ...agg.reasons.map((r) => `- ${mdText(r.label)} × ${r.count}`), "");
2931
2943
  }
2932
2944
  if (model.gate) {
2933
2945
  const g = model.gate;
@@ -2953,7 +2965,7 @@ export function renderReceiptMarkdown(model) {
2953
2965
  }
2954
2966
  const hosts = model.wiredHosts ?? [];
2955
2967
  if (hosts.some((h) => h.wired !== "none")) {
2956
- lines.push("## Wired hosts");
2968
+ lines.push("## Connected tools");
2957
2969
  for (const h of hosts) {
2958
2970
  if (h.recipeOnly) {
2959
2971
  lines.push(`- ${mdText(h.label)} - manual setup (docs recipe)`);
@@ -2980,16 +2992,16 @@ export function renderReceiptMarkdown(model) {
2980
2992
  }
2981
2993
  if (model.orr) {
2982
2994
  const orr = model.orr;
2983
- lines.push("## Operational readiness", `overall: ${orr.overall} · disposition: ${orr.disposition.replace(/_/g, " ")}${orr.targetName ? ` · target ${mdText(orr.targetName)}` : ""}`);
2995
+ lines.push("## Readiness check", `overall: ${orr.overall} · disposition: ${orr.disposition.replace(/_/g, " ")}${orr.targetName ? ` · checked ${mdText(orr.targetName)}` : ""}`);
2984
2996
  if (orr.primaryFailureMode)
2985
- lines.push(`Primary failure mode: ${mdText(orr.primaryFailureMode)}`);
2997
+ lines.push(`Main problem: ${mdText(orr.primaryFailureMode)}`);
2986
2998
  if (orr.mostUrgentFix)
2987
- lines.push(`Most urgent fix: ${mdText(orr.mostUrgentFix)}`);
2988
- lines.push(`scorecards: ${orr.scorecards.pass} pass · ${orr.scorecards.fail} fail · ${orr.scorecards.partial} partial · ${orr.scorecards.notEvaluated} n/e${orr.generatedAt ? ` · ${relativeTime(orr.generatedAt, nowMs)}` : ""}`, "");
2999
+ lines.push(`First fix to make: ${mdText(orr.mostUrgentFix)}`);
3000
+ lines.push(`checks: ${orr.scorecards.pass} pass · ${orr.scorecards.fail} fail · ${orr.scorecards.partial} partial · ${orr.scorecards.notEvaluated} n/e${orr.generatedAt ? ` · ${relativeTime(orr.generatedAt, nowMs)}` : ""}`, "");
2989
3001
  }
2990
3002
  if (model.showback) {
2991
3003
  const sb = model.showback;
2992
- lines.push("## Showback (observe only)", `${sb.totalTokensIn} tokens in · ${sb.totalTokensOut} tokens out · ${usdText(sb.estimatedUsd)}`);
3004
+ lines.push("## Token use and cost (information only)", `${sb.totalTokensIn} tokens in · ${sb.totalTokensOut} tokens out · ${usdText(sb.estimatedUsd)}`);
2993
3005
  const topRuns = [...sb.perRun]
2994
3006
  .sort((a, b) => (b.estimatedUsd ?? -1) - (a.estimatedUsd ?? -1))
2995
3007
  .slice(0, 5);
@@ -3022,7 +3034,7 @@ export function renderReceiptMarkdown(model) {
3022
3034
  }
3023
3035
  if (model.otel) {
3024
3036
  const ot = model.otel;
3025
- lines.push("## OTel export", `${ot.endpoint ? `\`${mdInline(ot.endpoint)}\` · ` : ""}${ot.spansSent} sent · ${ot.spansFailed} failed${ot.lastExportAt ? ` · last export ${relativeTime(ot.lastExportAt, nowMs)}` : ""}`, "");
3037
+ lines.push("## Export to your monitoring (OTel)", `${ot.endpoint ? `\`${mdInline(ot.endpoint)}\` · ` : ""}${ot.spansSent} sent · ${ot.spansFailed} failed${ot.lastExportAt ? ` · last export ${relativeTime(ot.lastExportAt, nowMs)}` : ""}`, "");
3026
3038
  }
3027
3039
  const md = `${lines.join("\n")}\n`;
3028
3040
  assertNoSecrets(md);