modelrig 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/README.md +4 -2
  3. package/dist/artifacts/artifact.d.ts +12 -13
  4. package/dist/artifacts/artifact.d.ts.map +1 -1
  5. package/dist/artifacts/artifact.js +17 -23
  6. package/dist/artifacts/index.d.ts +13 -5
  7. package/dist/artifacts/index.d.ts.map +1 -1
  8. package/dist/artifacts/index.js +11 -4
  9. package/dist/artifacts/run-context.d.ts +3 -24
  10. package/dist/artifacts/run-context.d.ts.map +1 -1
  11. package/dist/artifacts/run-context.js +3 -39
  12. package/dist/bakeoff/engine.d.ts +29 -0
  13. package/dist/bakeoff/engine.d.ts.map +1 -1
  14. package/dist/bakeoff/engine.js +47 -0
  15. package/dist/bakeoff/eval-cases-rig.d.ts +36 -0
  16. package/dist/bakeoff/eval-cases-rig.d.ts.map +1 -0
  17. package/dist/bakeoff/eval-cases-rig.js +27 -0
  18. package/dist/bakeoff/eval-cases.d.ts +19 -0
  19. package/dist/bakeoff/eval-cases.d.ts.map +1 -1
  20. package/dist/bakeoff/eval-cases.js +18 -1
  21. package/dist/bakeoff/golden-judge.d.ts +47 -0
  22. package/dist/bakeoff/golden-judge.d.ts.map +1 -0
  23. package/dist/bakeoff/golden-judge.js +49 -0
  24. package/dist/bakeoff/quality.d.ts +30 -0
  25. package/dist/bakeoff/quality.d.ts.map +1 -1
  26. package/dist/bakeoff/quality.js +21 -0
  27. package/dist/bakeoff/replay.d.ts +11 -0
  28. package/dist/bakeoff/replay.d.ts.map +1 -1
  29. package/dist/bakeoff/replay.js +8 -0
  30. package/dist/bakeoff/report.d.ts +7 -0
  31. package/dist/bakeoff/report.d.ts.map +1 -1
  32. package/dist/bakeoff/report.js +26 -0
  33. package/dist/cli-judge.d.ts +12 -0
  34. package/dist/cli-judge.d.ts.map +1 -0
  35. package/dist/cli-judge.js +48 -0
  36. package/dist/cli.d.ts.map +1 -1
  37. package/dist/cli.js +14 -42
  38. package/dist/config.d.ts +54 -29
  39. package/dist/config.d.ts.map +1 -1
  40. package/dist/config.js +86 -47
  41. package/dist/detect/detector.d.ts +4 -2
  42. package/dist/detect/detector.d.ts.map +1 -1
  43. package/dist/detect/safe-harbor.d.ts +57 -0
  44. package/dist/detect/safe-harbor.d.ts.map +1 -0
  45. package/dist/detect/safe-harbor.js +278 -0
  46. package/dist/feedback/coverage.d.ts +11 -8
  47. package/dist/feedback/coverage.d.ts.map +1 -1
  48. package/dist/feedback/coverage.js +29 -16
  49. package/dist/feedback/grade.d.ts +51 -0
  50. package/dist/feedback/grade.d.ts.map +1 -0
  51. package/dist/feedback/grade.js +63 -0
  52. package/dist/gateway/http-protocol.d.ts +1 -1
  53. package/dist/gateway/http-protocol.d.ts.map +1 -1
  54. package/dist/gateway/http-protocol.js +1 -1
  55. package/dist/index.d.ts +44 -27
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +110 -43
  58. package/dist/init/observe-cli.js +1 -1
  59. package/dist/init/observe.d.ts +2 -2
  60. package/dist/init/observe.d.ts.map +1 -1
  61. package/dist/init/observe.js +11 -7
  62. package/dist/mask/arm.d.ts +112 -0
  63. package/dist/mask/arm.d.ts.map +1 -0
  64. package/dist/mask/arm.js +179 -0
  65. package/dist/mask/index.d.ts +2 -0
  66. package/dist/mask/index.d.ts.map +1 -1
  67. package/dist/mask/index.js +7 -1
  68. package/dist/mask/mask-policy-cli.d.ts +12 -4
  69. package/dist/mask/mask-policy-cli.d.ts.map +1 -1
  70. package/dist/mask/mask-policy-cli.js +34 -9
  71. package/dist/query/grammar.d.ts +2 -2
  72. package/dist/query/grammar.d.ts.map +1 -1
  73. package/dist/query/grammar.js +3 -1
  74. package/dist/query/saved.d.ts +13 -0
  75. package/dist/query/saved.d.ts.map +1 -1
  76. package/dist/query/saved.js +67 -1
  77. package/dist/receipts/types.d.ts +1 -1
  78. package/dist/receipts/types.d.ts.map +1 -1
  79. package/dist/receipts/types.js +1 -0
  80. package/dist/registry/build.d.ts +43 -1
  81. package/dist/registry/build.d.ts.map +1 -1
  82. package/dist/registry/build.js +52 -0
  83. package/dist/registry/pricing-shape.d.ts +29 -0
  84. package/dist/registry/pricing-shape.d.ts.map +1 -1
  85. package/dist/registry/pricing-shape.js +10 -1
  86. package/dist/registry/rows.d.ts.map +1 -1
  87. package/dist/registry/rows.js +1 -0
  88. package/dist/registry/select.d.ts +6 -1
  89. package/dist/registry/select.d.ts.map +1 -1
  90. package/dist/registry/select.js +11 -0
  91. package/dist/routes/call-config.d.ts +199 -0
  92. package/dist/routes/call-config.d.ts.map +1 -0
  93. package/dist/routes/call-config.js +343 -0
  94. package/dist/routes/loader.js +5 -3
  95. package/dist/routes/objective-loader.d.ts +12 -0
  96. package/dist/routes/objective-loader.d.ts.map +1 -1
  97. package/dist/routes/objective-loader.js +82 -0
  98. package/dist/routes/resolved-bundle.d.ts +50 -0
  99. package/dist/routes/resolved-bundle.d.ts.map +1 -1
  100. package/dist/routes/resolved-bundle.js +52 -0
  101. package/dist/routes/screen-loader.d.ts +28 -0
  102. package/dist/routes/screen-loader.d.ts.map +1 -1
  103. package/dist/routes/screen-loader.js +51 -0
  104. package/dist/run/accept.d.ts +2 -0
  105. package/dist/run/accept.d.ts.map +1 -1
  106. package/dist/run/accept.js +1 -0
  107. package/dist/run/dispatch.d.ts +42 -13
  108. package/dist/run/dispatch.d.ts.map +1 -1
  109. package/dist/run/dispatch.js +107 -25
  110. package/dist/run/grounding.d.ts +28 -2
  111. package/dist/run/grounding.d.ts.map +1 -1
  112. package/dist/run/grounding.js +54 -10
  113. package/dist/run/record-attempt.d.ts +4 -0
  114. package/dist/run/record-attempt.d.ts.map +1 -1
  115. package/dist/run/record-attempt.js +4 -0
  116. package/dist/run/routing-docs.js +1 -1
  117. package/dist/run/run.d.ts.map +1 -1
  118. package/dist/run/run.js +21 -26
  119. package/dist/savings/odometer.d.ts +4 -0
  120. package/dist/savings/odometer.d.ts.map +1 -1
  121. package/dist/savings/odometer.js +20 -1
  122. package/dist/savings/swap-execute.d.ts +7 -0
  123. package/dist/savings/swap-execute.d.ts.map +1 -1
  124. package/dist/savings/swap-execute.js +30 -0
  125. package/dist/savings/swaps-client.d.ts +10 -0
  126. package/dist/savings/swaps-client.d.ts.map +1 -1
  127. package/dist/screen/fixtures/probe-corpora.d.ts +23 -0
  128. package/dist/screen/fixtures/probe-corpora.d.ts.map +1 -0
  129. package/dist/screen/fixtures/probe-corpora.js +69 -0
  130. package/dist/screen/index.d.ts +21 -0
  131. package/dist/screen/index.d.ts.map +1 -0
  132. package/dist/screen/index.js +64 -0
  133. package/dist/screen/model-screen.d.ts +111 -0
  134. package/dist/screen/model-screen.d.ts.map +1 -0
  135. package/dist/screen/model-screen.js +178 -0
  136. package/dist/screen/patterns.d.ts +51 -0
  137. package/dist/screen/patterns.d.ts.map +1 -0
  138. package/dist/screen/patterns.js +151 -0
  139. package/dist/screen/phi-gate.d.ts +52 -0
  140. package/dist/screen/phi-gate.d.ts.map +1 -0
  141. package/dist/screen/phi-gate.js +86 -0
  142. package/dist/screen/policy.d.ts +71 -0
  143. package/dist/screen/policy.d.ts.map +1 -0
  144. package/dist/screen/policy.js +334 -0
  145. package/dist/screen/probe.d.ts +118 -0
  146. package/dist/screen/probe.d.ts.map +1 -0
  147. package/dist/screen/probe.js +132 -0
  148. package/dist/screen/screen-cli.d.ts +16 -0
  149. package/dist/screen/screen-cli.d.ts.map +1 -0
  150. package/dist/screen/screen-cli.js +178 -0
  151. package/dist/screen/screen.d.ts +99 -0
  152. package/dist/screen/screen.d.ts.map +1 -0
  153. package/dist/screen/screen.js +0 -0
  154. package/dist/screen/sidecar.d.ts +69 -0
  155. package/dist/screen/sidecar.d.ts.map +1 -0
  156. package/dist/screen/sidecar.js +145 -0
  157. package/dist/screen/types.d.ts +43 -2
  158. package/dist/screen/types.d.ts.map +1 -1
  159. package/dist/settings/api-fetcher.d.ts +14 -3
  160. package/dist/settings/api-fetcher.d.ts.map +1 -1
  161. package/dist/settings/api-fetcher.js +61 -10
  162. package/dist/settings/grading-guide.d.ts +76 -0
  163. package/dist/settings/grading-guide.d.ts.map +1 -0
  164. package/dist/settings/grading-guide.js +23 -0
  165. package/dist/settings/index.d.ts +3 -2
  166. package/dist/settings/index.d.ts.map +1 -1
  167. package/dist/settings/index.js +2 -1
  168. package/dist/settings/task-settings.d.ts +44 -7
  169. package/dist/settings/task-settings.d.ts.map +1 -1
  170. package/dist/settings/task-settings.js +53 -12
  171. package/dist/status.d.ts +26 -20
  172. package/dist/status.d.ts.map +1 -1
  173. package/dist/status.js +47 -29
  174. package/dist/telemetry/artifact-store.d.ts +5 -6
  175. package/dist/telemetry/artifact-store.d.ts.map +1 -1
  176. package/dist/telemetry/artifact-store.js +10 -24
  177. package/dist/telemetry/attempt-meta.d.ts +21 -0
  178. package/dist/telemetry/attempt-meta.d.ts.map +1 -1
  179. package/dist/telemetry/attempt-meta.js +9 -0
  180. package/dist/telemetry/exporter.d.ts +2 -2
  181. package/dist/telemetry/exporter.d.ts.map +1 -1
  182. package/dist/telemetry/exporter.js +22 -41
  183. package/dist/telemetry/grade-mappers.d.ts +22 -0
  184. package/dist/telemetry/grade-mappers.d.ts.map +1 -0
  185. package/dist/telemetry/grade-mappers.js +58 -0
  186. package/dist/telemetry/grades-sql.d.ts +53 -0
  187. package/dist/telemetry/grades-sql.d.ts.map +1 -0
  188. package/dist/telemetry/grades-sql.js +133 -0
  189. package/dist/telemetry/ingest-protocol.d.ts +29 -46
  190. package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
  191. package/dist/telemetry/ingest-protocol.js +16 -54
  192. package/dist/telemetry/store-migrations.d.ts.map +1 -1
  193. package/dist/telemetry/store-migrations.js +51 -0
  194. package/dist/telemetry/store.d.ts +9 -6
  195. package/dist/telemetry/store.d.ts.map +1 -1
  196. package/dist/telemetry/store.js +8 -50
  197. package/dist/tenancy/api-key-format.d.ts +30 -1
  198. package/dist/tenancy/api-key-format.d.ts.map +1 -1
  199. package/dist/tenancy/api-key-format.js +33 -1
  200. package/dist/types/provider.d.ts +3 -0
  201. package/dist/types/provider.d.ts.map +1 -1
  202. package/dist/types/provider.js +25 -0
  203. package/dist/types/route.d.ts +78 -2
  204. package/dist/types/route.d.ts.map +1 -1
  205. package/dist/types/telemetry.d.ts +43 -46
  206. package/dist/types/telemetry.d.ts.map +1 -1
  207. package/dist/validate-cli.d.ts.map +1 -1
  208. package/dist/validate-cli.js +32 -0
  209. package/dist/verify/verify.d.ts +5 -0
  210. package/dist/verify/verify.d.ts.map +1 -1
  211. package/dist/verify/verify.js +2 -0
  212. package/dist/watch/evaluate.d.ts +84 -1
  213. package/dist/watch/evaluate.d.ts.map +1 -1
  214. package/dist/watch/evaluate.js +28 -0
  215. package/dist/watch/monitor.d.ts +8 -2
  216. package/dist/watch/monitor.d.ts.map +1 -1
  217. package/dist/watch/monitor.js +13 -5
  218. package/dist/watch/regret-monitor-cli.d.ts +16 -0
  219. package/dist/watch/regret-monitor-cli.d.ts.map +1 -0
  220. package/dist/watch/regret-monitor-cli.js +137 -0
  221. package/dist/watch/regret-monitor.d.ts +168 -0
  222. package/dist/watch/regret-monitor.d.ts.map +1 -0
  223. package/dist/watch/regret-monitor.js +304 -0
  224. package/dist/watch/upgrade.d.ts +62 -0
  225. package/dist/watch/upgrade.d.ts.map +1 -0
  226. package/dist/watch/upgrade.js +57 -0
  227. package/docs/agent-skill/SKILL.md +109 -5
  228. package/docs/how-it-fits.md +3 -2
  229. package/docs/instrumentation.md +149 -21
  230. package/docs/llms.txt +64 -20
  231. package/docs/mcp-oracle.md +249 -0
  232. package/docs/quickstart.md +95 -7
  233. package/package.json +16 -3
  234. package/registry/leaderboard.json +74 -0
  235. package/registry/registry.json +150 -112
  236. package/screen.d.ts +16 -0
  237. package/templates/call-disposition-qa.json +77 -0
  238. package/templates/catalog-cleansing.json +77 -0
  239. package/templates/compliance-review.json +76 -0
  240. package/templates/cs-next-action.json +76 -0
  241. package/templates/document-extraction.json +78 -0
  242. package/templates/financial-classification.json +75 -0
  243. package/templates/lead-qualification.json +76 -0
  244. package/templates/medical-classification.json +71 -0
  245. package/templates/ticket-triage.json +76 -0
@@ -0,0 +1,278 @@
1
+ "use strict";
2
+ /**
3
+ * SC-2 — deterministic HIPAA Safe Harbor identifier detectors (spec-sc2 §2).
4
+ *
5
+ * These EXTEND scrub v1 (S1: extend, don't twin) as new `Detector`s over the
6
+ * shared interface (src/detect/detector.ts) — `kind: "deterministic"`,
7
+ * `confidence: 1`. They live BESIDE scrub v1's five detectors, NOT inside
8
+ * `scrubContent`: adding one here never widens the custody scrub floor. The
9
+ * composition point is the screen policy `detectors: [...]` opt-in — a route
10
+ * turns a Safe Harbor detector on explicitly (spec-sc2 §2, builder confirmation:
11
+ * "never silently added to the custody scrub floor"). `scrubContent` and the
12
+ * five v1 detectors stay BYTE-IDENTICAL (golden).
13
+ *
14
+ * LEAK INVARIANT (spec-sc2 §1.4): a detector emits SPANS (offsets + type +
15
+ * confidence) — never the matched substring. The matched value is read only to
16
+ * validate (Luhn / VIN checksum / octet range / age bound) and is discarded
17
+ * immediately; nothing here returns, logs, or persists it.
18
+ *
19
+ * SCOPE (honest limits, stated in the coverage table): US-English-shaped,
20
+ * deterministic regex/checksum rules — NOT a model, NOT DLP. Free-text names and
21
+ * street addresses need the customer-run sidecar (src/screen/sidecar.ts); those
22
+ * classes are `sidecar`/`out-of-scope` in the coverage table, never claimed here.
23
+ * Recall on synthetic PHI is MEASURED by the SC-3 probe, not asserted here.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.SAFE_HARBOR_IDS = exports.SAFE_HARBOR_PACK_ID = void 0;
27
+ exports.vinValid = vinValid;
28
+ exports.isSafeHarborId = isSafeHarborId;
29
+ exports.safeHarborDetectors = safeHarborDetectors;
30
+ exports.safeHarborDetectorById = safeHarborDetectorById;
31
+ exports.safeHarborIdentities = safeHarborIdentities;
32
+ exports.safeHarborDetectorsFor = safeHarborDetectorsFor;
33
+ const scrub_1 = require("../artifacts/scrub");
34
+ /** Cap on spans emitted per detect() call ("per-result cap", spec-sc2 §2): a
35
+ * pathological document (a table of dates) yields COUNTS, not an unbounded span
36
+ * list. The count is truthful up to the cap; beyond it the receipt reads
37
+ * "≥ cap", which is enough to drive a policy action. */
38
+ const MAX_SPANS_PER_TYPE = 512;
39
+ /** Push a `{start,end,type,confidence:1}` span, capped. The matched value is the
40
+ * caller's local variable; it never enters the span. */
41
+ function emit(spans, type, start, len) {
42
+ if (spans.length >= MAX_SPANS_PER_TYPE)
43
+ return;
44
+ spans.push({ start, end: start + len, type, confidence: 1 });
45
+ }
46
+ /** Iterate global-regex matches with a fresh RegExp (so /g `lastIndex` never
47
+ * leaks across calls), passing each match to `onMatch`. */
48
+ function eachMatch(re, text, onMatch) {
49
+ const fresh = new RegExp(re.source, re.flags);
50
+ for (const m of text.matchAll(fresh))
51
+ onMatch(m[0], m.index ?? 0);
52
+ }
53
+ // ── date (Safe Harbor: dates except year — DOB/admit/discharge/death) ────────
54
+ // ISO YYYY-MM-DD, US M/D/YYYY (and M/D/YY), and month-name forms. Many formats;
55
+ // per-result cap applies. Conservative: a bare 4-digit year alone is NOT a date
56
+ // (Safe Harbor exempts the year), so the year-only shape is deliberately unmatched.
57
+ const MONTHS = "jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:t(?:ember)?)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?";
58
+ const DATE_ISO = /\b\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])\b/g;
59
+ const DATE_NUMERIC = /\b(?:0?[1-9]|1[0-2])[/-](?:0?[1-9]|[12]\d|3[01])[/-](?:\d{4}|\d{2})\b/g;
60
+ const DATE_MONTH_DMY = new RegExp(`\\b(?:0?[1-9]|[12]\\d|3[01])\\s+(?:${MONTHS})\\.?\\s+\\d{4}\\b`, "gi");
61
+ const DATE_MONTH_MDY = new RegExp(`\\b(?:${MONTHS})\\.?\\s+(?:0?[1-9]|[12]\\d|3[01])(?:st|nd|rd|th)?,?\\s+\\d{4}\\b`, "gi");
62
+ function findDates(text) {
63
+ const spans = [];
64
+ for (const re of [DATE_ISO, DATE_NUMERIC, DATE_MONTH_DMY, DATE_MONTH_MDY]) {
65
+ eachMatch(re, text, (v, i) => emit(spans, "pii:date", i, v.length));
66
+ }
67
+ return spans;
68
+ }
69
+ // ── age-over-89 (Safe Harbor: ages > 89 / dates indicating such age) ─────────
70
+ // A numeric RULE, not a regex-of-content (spec-sc2 §2): match an age-shaped
71
+ // phrase, then ACCEPT only when the number is 90..130 (a sane human-age bound —
72
+ // above it the digits are almost certainly something else, e.g. a quantity).
73
+ const AGE_CONTEXT = /\b(?:age[ds]?|aged)\b[^.\n\d]{0,12}(\d{2,3})\b|\b(\d{2,3})[ -]?(?:years?[ -]old|y(?:rs?)?[ -]?old|yo)\b/gi;
74
+ function findAgeOver89(text) {
75
+ const spans = [];
76
+ const fresh = new RegExp(AGE_CONTEXT.source, AGE_CONTEXT.flags);
77
+ for (const m of text.matchAll(fresh)) {
78
+ const digits = m[1] ?? m[2];
79
+ if (digits === undefined)
80
+ continue;
81
+ const n = Number.parseInt(digits, 10);
82
+ if (n < 90 || n > 130)
83
+ continue; // Safe Harbor floor is >89; 130 caps a human age
84
+ emit(spans, "pii:age_over_89", m.index ?? 0, m[0].length);
85
+ }
86
+ return spans;
87
+ }
88
+ // ── fax (Safe Harbor: telephone / fax) — label-anchored phone shape ──────────
89
+ const FAX = /\bfax\b[^.\n]{0,8}(?:\+?\d{1,3}[ .-]?)?(?:\(\d{3}\)|\d{3})[ .-]\d{3}[ .-]\d{4}\b/gi;
90
+ function findFax(text) {
91
+ const spans = [];
92
+ eachMatch(FAX, text, (v, i) => emit(spans, "pii:fax", i, v.length));
93
+ return spans;
94
+ }
95
+ // ── url (Safe Harbor: URLs; also the INJ-6 egress channel) ───────────────────
96
+ const URL_RE = /\bhttps?:\/\/[^\s"'<>)\]\\]+/gi;
97
+ function findUrls(text) {
98
+ const spans = [];
99
+ eachMatch(URL_RE, text, (v, i) => {
100
+ // Trim trailing sentence punctuation from the span length (the URL proper).
101
+ const trimmed = v.replace(/[.,;:]+$/, "");
102
+ emit(spans, "pii:url", i, trimmed.length);
103
+ });
104
+ return spans;
105
+ }
106
+ // ── ip (Safe Harbor: IP addresses) — v4 (octet-validated) + v6 ───────────────
107
+ const IPV4 = /\b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)\b/g;
108
+ const IPV6 = /\b(?:[0-9A-Fa-f]{1,4}:){2,7}[0-9A-Fa-f]{1,4}\b|\b(?:[0-9A-Fa-f]{1,4}:){1,7}:\b/g;
109
+ function findIps(text) {
110
+ const spans = [];
111
+ eachMatch(IPV4, text, (v, i) => emit(spans, "pii:ip", i, v.length));
112
+ eachMatch(IPV6, text, (v, i) => {
113
+ if (v.split(":").filter((p) => p !== "").length < 2)
114
+ return; // avoid a lone "a:" style false hit
115
+ emit(spans, "pii:ip", i, v.length);
116
+ });
117
+ return spans;
118
+ }
119
+ // ── zip (Safe Harbor: geographic < state) — conservative, anchored ───────────
120
+ // A bare 5-digit run floods (SSN-comment doctrine). Claimed only when it is
121
+ // distinctive: ZIP+4 (`12345-6789`), a `ST 12345` state+ZIP shape, or a labelled
122
+ // `ZIP: 12345`. Street/city need the sidecar and are NOT claimed here.
123
+ const ZIP_PLUS4 = /\b\d{5}-\d{4}\b/g;
124
+ const ZIP_STATE = /\b[A-Z]{2}\s+\d{5}(?:-\d{4})?\b/g;
125
+ const ZIP_LABELLED = /\bzip(?:\s*code)?\b[^.\n\d]{0,6}\d{5}(?:-\d{4})?\b/gi;
126
+ function findZips(text) {
127
+ const spans = [];
128
+ for (const re of [ZIP_PLUS4, ZIP_STATE, ZIP_LABELLED]) {
129
+ eachMatch(re, text, (v, i) => emit(spans, "pii:zip", i, v.length));
130
+ }
131
+ return spans;
132
+ }
133
+ // ── account-id (health-plan beneficiary #, account #, member #) ──────────────
134
+ // Label-anchored + shape — a bare id is unclaimable without a false-positive
135
+ // flood, so the label is what makes it real (the MRN doctrine).
136
+ const ACCOUNT_ID = /\b(?:account|acct|member|beneficiary|policy|plan|subscriber|group)\b[^.\n]{0,4}(?:id|no|number|#)?\s*[:#]?\s*[A-Za-z0-9][A-Za-z0-9-]{3,}\b/gi;
137
+ function findAccountIds(text) {
138
+ const spans = [];
139
+ eachMatch(ACCOUNT_ID, text, (v, i) => emit(spans, "pii:account_id", i, v.length));
140
+ return spans;
141
+ }
142
+ // ── license-id (certificate / license #) — label-anchored ────────────────────
143
+ const LICENSE_ID = /\b(?:licen[cs]e|licence|certificate|cert|permit|dl|driver'?s?\s+licen[cs]e)\b[^.\n]{0,4}(?:id|no|number|#)?\s*[:#]?\s*[A-Za-z0-9][A-Za-z0-9-]{3,}\b/gi;
144
+ function findLicenseIds(text) {
145
+ const spans = [];
146
+ eachMatch(LICENSE_ID, text, (v, i) => emit(spans, "pii:license_id", i, v.length));
147
+ return spans;
148
+ }
149
+ // ── vin (vehicle identifier) — 17-char VIN with check-digit validation ───────
150
+ const VIN_SHAPE = /\b[A-HJ-NPR-Z0-9]{17}\b/gi;
151
+ const VIN_TRANSLIT = {
152
+ A: 1, B: 2, C: 3, D: 4, E: 5, F: 6, G: 7, H: 8, J: 1, K: 2, L: 3, M: 4, N: 5,
153
+ P: 7, R: 9, S: 2, T: 3, U: 4, V: 5, W: 6, X: 7, Y: 8, Z: 9,
154
+ };
155
+ const VIN_WEIGHTS = [8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2];
156
+ /** VIN check-digit rule (position 9): weighted transliteration mod 11, where 10
157
+ * ⇒ 'X'. Separates a real VIN from any 17 alphanumerics — the difference between
158
+ * a false-positive flood and a claimable identifier. */
159
+ function vinValid(vin) {
160
+ const up = vin.toUpperCase();
161
+ if (up.length !== 17)
162
+ return false;
163
+ let sum = 0;
164
+ for (let i = 0; i < 17; i += 1) {
165
+ const ch = up[i];
166
+ const val = ch >= "0" && ch <= "9" ? ch.charCodeAt(0) - 48 : VIN_TRANSLIT[ch];
167
+ if (val === undefined)
168
+ return false; // I/O/Q or other invalid char
169
+ sum += val * VIN_WEIGHTS[i];
170
+ }
171
+ const check = sum % 11;
172
+ const expected = check === 10 ? "X" : String(check);
173
+ return up[8] === expected;
174
+ }
175
+ function findVins(text) {
176
+ const spans = [];
177
+ eachMatch(VIN_SHAPE, text, (v, i) => {
178
+ if (!vinValid(v))
179
+ return;
180
+ emit(spans, "pii:vin", i, v.length);
181
+ });
182
+ return spans;
183
+ }
184
+ // ── device-id (device / serial identifiers) — MAC, IMEI, label-anchored ──────
185
+ const MAC = /\b(?:[0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}\b/g;
186
+ const IMEI_LABELLED = /\bimei\b[^.\n\d]{0,6}(\d{15})\b/gi;
187
+ const DEVICE_LABELLED = /\b(?:device|serial|udid|s\/n|sn)\b[^.\n]{0,4}(?:id|no|number|#)?\s*[:#]?\s*[A-Za-z0-9][A-Za-z0-9-]{3,}\b/gi;
188
+ function findDeviceIds(text) {
189
+ const spans = [];
190
+ eachMatch(MAC, text, (v, i) => emit(spans, "pii:device_id", i, v.length));
191
+ const fresh = new RegExp(IMEI_LABELLED.source, IMEI_LABELLED.flags);
192
+ for (const m of text.matchAll(fresh)) {
193
+ const digits = m[1];
194
+ if (digits === undefined || !(0, scrub_1.luhnValid)(digits))
195
+ continue; // IMEI is Luhn-valid
196
+ emit(spans, "pii:device_id", m.index ?? 0, m[0].length);
197
+ }
198
+ eachMatch(DEVICE_LABELLED, text, (v, i) => emit(spans, "pii:device_id", i, v.length));
199
+ return spans;
200
+ }
201
+ /** The SC-2 deterministic rule set (spec-sc2 §2). One rule per Safe Harbor class
202
+ * that has a deterministic shape; names/streets/biometrics are NOT here (they
203
+ * are `sidecar`/`out-of-scope` in the coverage table). */
204
+ const RULES = [
205
+ { type: "pii:date", id: "pii:date@v1", find: findDates },
206
+ { type: "pii:age_over_89", id: "pii:age_over_89@v1", find: findAgeOver89 },
207
+ { type: "pii:fax", id: "pii:fax@v1", find: findFax },
208
+ { type: "pii:url", id: "pii:url@v1", find: findUrls },
209
+ { type: "pii:ip", id: "pii:ip@v1", find: findIps },
210
+ { type: "pii:zip", id: "pii:zip@v1", find: findZips },
211
+ { type: "pii:account_id", id: "pii:account_id@v1", find: findAccountIds },
212
+ { type: "pii:license_id", id: "pii:license_id@v1", find: findLicenseIds },
213
+ { type: "pii:vin", id: "pii:vin@v1", find: findVins },
214
+ { type: "pii:device_id", id: "pii:device_id@v1", find: findDeviceIds },
215
+ ];
216
+ /** The registry id of the convenience PACK — configuring it in a route's
217
+ * `screen.detectors` opts in to ALL ten deterministic Safe Harbor detectors at
218
+ * once. Individual `pii:<slug>@v1` ids opt in to just that one. */
219
+ exports.SAFE_HARBOR_PACK_ID = "safe-harbor@v1";
220
+ /** All individual Safe Harbor detector ids, for policy validation. */
221
+ exports.SAFE_HARBOR_IDS = new Set(RULES.map((r) => r.id));
222
+ /** True when `id` names a Safe Harbor detector (a `pii:<slug>@v1` or the pack).
223
+ * The screen policy validator uses this to accept the id at load time. */
224
+ function isSafeHarborId(id) {
225
+ return id === exports.SAFE_HARBOR_PACK_ID || exports.SAFE_HARBOR_IDS.has(id);
226
+ }
227
+ /** Collapse overlapping spans of one detector to a single span so one underlying
228
+ * identifier matched by two sub-patterns (e.g. a ZIP caught by both the ZIP+4 and
229
+ * the state+ZIP rule) COUNTS ONCE. Sorted by start; a span whose range overlaps a
230
+ * kept span is dropped (conservative — an adjacency undercount is cheaper than a
231
+ * double count). Offsets only, never a value. */
232
+ function dedupeOverlaps(spans) {
233
+ const sorted = [...spans].sort((a, b) => a.start - b.start || b.end - a.end);
234
+ const kept = [];
235
+ let lastEnd = -1;
236
+ for (const s of sorted) {
237
+ if (s.start >= lastEnd) {
238
+ kept.push(s);
239
+ lastEnd = s.end;
240
+ }
241
+ }
242
+ return kept;
243
+ }
244
+ /** Wrap one rule as the shared `Detector` (kind deterministic, confidence 1). */
245
+ function detectorFor(rule) {
246
+ return {
247
+ id: rule.id,
248
+ kind: "deterministic",
249
+ detect: (input) => Promise.resolve(dedupeOverlaps(rule.find(input.text))),
250
+ };
251
+ }
252
+ /** Every Safe Harbor detector (one per type), for the pack. */
253
+ function safeHarborDetectors() {
254
+ return RULES.map(detectorFor);
255
+ }
256
+ /** The Safe Harbor detector for one id, or `undefined` if `id` is not one.
257
+ * `SAFE_HARBOR_PACK_ID` returns `undefined` here — the pack expands to
258
+ * {@link safeHarborDetectors}; a caller resolves the pack separately. */
259
+ function safeHarborDetectorById(id) {
260
+ const rule = RULES.find((r) => r.id === id);
261
+ return rule === undefined ? undefined : detectorFor(rule);
262
+ }
263
+ /** The detector identities (id + version) for a configured id — the pack
264
+ * expands to all ten; a single id resolves to one. Used to populate the
265
+ * receipt's `detectors[]` at resolve time (counts-only, never a value). */
266
+ function safeHarborIdentities(id) {
267
+ if (id === exports.SAFE_HARBOR_PACK_ID)
268
+ return RULES.map((r) => ({ id: r.id, version: "v1" }));
269
+ return exports.SAFE_HARBOR_IDS.has(id) ? [{ id, version: "v1" }] : [];
270
+ }
271
+ /** Build the Detector instances a configured id contributes (pack ⇒ all ten,
272
+ * single id ⇒ one, unknown ⇒ none). */
273
+ function safeHarborDetectorsFor(id) {
274
+ if (id === exports.SAFE_HARBOR_PACK_ID)
275
+ return safeHarborDetectors();
276
+ const one = safeHarborDetectorById(id);
277
+ return one === undefined ? [] : [one];
278
+ }
@@ -7,12 +7,12 @@
7
7
  * rung 0 — implicit signals only: conformance / repair / refusal rates
8
8
  * from telemetry. Enough confidence for schema-mechanical swap
9
9
  * proposals (the bake-off gate).
10
- * rung 1 — ≥ RUNG1_MIN_FEEDBACK human/agent verdicts attached: prose
10
+ * rung 1 — ≥ RUNG1_MIN_GRADES grades attached: prose
11
11
  * routes (no schema to conform to) gain proposal confidence.
12
12
  * rung 2+ — judges; Phase 5+, out of scope by decision.
13
13
  */
14
- import type { FeedbackRow, TelemetryRow } from "../types/telemetry";
15
- export declare const RUNG1_MIN_FEEDBACK = 10;
14
+ import type { GradeRow, TelemetryRow } from "../types/telemetry";
15
+ export declare const RUNG1_MIN_GRADES = 10;
16
16
  export interface RouteCoverage {
17
17
  readonly route: string;
18
18
  readonly samples: number;
@@ -20,13 +20,16 @@ export interface RouteCoverage {
20
20
  readonly conformRate: number;
21
21
  readonly repairRate: number;
22
22
  readonly refusalRate: number;
23
- readonly feedbackCount: number;
23
+ readonly gradeCount: number;
24
24
  readonly rung: 0 | 1;
25
25
  /** Teaching copy: what reaching the next rung takes and unlocks. */
26
26
  readonly nextRungUnlock: string;
27
27
  }
28
- /** Attribution: a feedback row joins a route via its inference id, or via
29
- * its episode key matching a row's run_id tag. Unmatched feedback attaches
30
- * to nothing (never guessed). */
31
- export declare function computeCoverage(rows: readonly TelemetryRow[], feedback: readonly FeedbackRow[]): RouteCoverage[];
28
+ /** Attribution: a grade joins a route via its inference-subject id, or via its
29
+ * run-subject (episode) id matching a row's run_id tag. Unmatched grades attach
30
+ * to nothing (never guessed). Grade primitive (R6): every grade counts toward
31
+ * readiness — a wrapper-written feedback IS now a grade, so this is
32
+ * behaviour-preserving for the Rung-1 threshold. Artifact-subject grades never
33
+ * resolve to a route here (no artifact→route join) and simply do not count. */
34
+ export declare function computeCoverage(rows: readonly TelemetryRow[], grades: readonly GradeRow[]): RouteCoverage[];
32
35
  //# sourceMappingURL=coverage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/feedback/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEpE,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;IACrB,oEAAoE;IACpE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED;;iCAEiC;AACjC,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC/B,aAAa,EAAE,CA2EjB"}
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/feedback/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEjE,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;IACrB,oEAAoE;IACpE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED;;;;;+EAK+E;AAC/E,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,MAAM,EAAE,SAAS,QAAQ,EAAE,GAC1B,aAAa,EAAE,CAqFjB"}
@@ -8,18 +8,21 @@
8
8
  * rung 0 — implicit signals only: conformance / repair / refusal rates
9
9
  * from telemetry. Enough confidence for schema-mechanical swap
10
10
  * proposals (the bake-off gate).
11
- * rung 1 — ≥ RUNG1_MIN_FEEDBACK human/agent verdicts attached: prose
11
+ * rung 1 — ≥ RUNG1_MIN_GRADES grades attached: prose
12
12
  * routes (no schema to conform to) gain proposal confidence.
13
13
  * rung 2+ — judges; Phase 5+, out of scope by decision.
14
14
  */
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.RUNG1_MIN_FEEDBACK = void 0;
16
+ exports.RUNG1_MIN_GRADES = void 0;
17
17
  exports.computeCoverage = computeCoverage;
18
- exports.RUNG1_MIN_FEEDBACK = 10;
19
- /** Attribution: a feedback row joins a route via its inference id, or via
20
- * its episode key matching a row's run_id tag. Unmatched feedback attaches
21
- * to nothing (never guessed). */
22
- function computeCoverage(rows, feedback) {
18
+ exports.RUNG1_MIN_GRADES = 10;
19
+ /** Attribution: a grade joins a route via its inference-subject id, or via its
20
+ * run-subject (episode) id matching a row's run_id tag. Unmatched grades attach
21
+ * to nothing (never guessed). Grade primitive (R6): every grade counts toward
22
+ * readiness — a wrapper-written feedback IS now a grade, so this is
23
+ * behaviour-preserving for the Rung-1 threshold. Artifact-subject grades never
24
+ * resolve to a route here (no artifact→route join) and simply do not count. */
25
+ function computeCoverage(rows, grades) {
23
26
  const routeByInferenceId = new Map();
24
27
  const routeByEpisode = new Map();
25
28
  const byRoute = new Map();
@@ -42,7 +45,7 @@ function computeCoverage(rows, feedback) {
42
45
  conform: 0,
43
46
  repaired: 0,
44
47
  refused: 0,
45
- feedback: 0,
48
+ grades: 0,
46
49
  };
47
50
  agg.samples += 1;
48
51
  if (row.failureClass === null)
@@ -63,22 +66,32 @@ function computeCoverage(rows, feedback) {
63
66
  // Unparseable tags never break coverage — the row still counts above.
64
67
  }
65
68
  }
66
- for (const f of feedback) {
67
- const route = (f.inferenceId !== null ? routeByInferenceId.get(f.inferenceId) : undefined) ??
68
- (f.episodeKey !== null ? routeByEpisode.get(f.episodeKey) : undefined);
69
+ for (const g of grades) {
70
+ // R6 (grade primitive): EVERY grade counts toward Rung 1, not just the
71
+ // wrapper-written thumbs the pre-grade `feedback` table held. A grade counts
72
+ // only when its subject resolves to a route: an inference-subject id, or a
73
+ // run-subject (episode) id matching a row's run_id tag. Artifact-subject
74
+ // grades and native run verdicts (whose run-subject id is a run UUID, not an
75
+ // episode key) never resolve to a route here, so they do not over-count —
76
+ // behaviour-preserving for existing corpora while opening Rung 1 to
77
+ // model-judge/agent grades on inferences (the R6 intent).
78
+ const inferenceId = g.subjectKind === "inference" ? g.subjectId : null;
79
+ const episodeKey = g.subjectKind === "run" ? g.subjectId : null;
80
+ const route = (inferenceId !== null ? routeByInferenceId.get(inferenceId) : undefined) ??
81
+ (episodeKey !== null ? routeByEpisode.get(episodeKey) : undefined);
69
82
  if (route === undefined)
70
83
  continue;
71
84
  const agg = byRoute.get(route);
72
85
  if (agg !== undefined)
73
- agg.feedback += 1;
86
+ agg.grades += 1;
74
87
  }
75
88
  return [...byRoute.entries()]
76
89
  .sort(([a], [b]) => a.localeCompare(b))
77
90
  .map(([route, agg]) => {
78
- const rung = agg.feedback >= exports.RUNG1_MIN_FEEDBACK ? 1 : 0;
91
+ const rung = agg.grades >= exports.RUNG1_MIN_GRADES ? 1 : 0;
79
92
  const nextRungUnlock = rung === 0
80
- ? `Attach ${exports.RUNG1_MIN_FEEDBACK - agg.feedback} more rig.feedback() verdicts ` +
81
- `(${agg.feedback}/${exports.RUNG1_MIN_FEEDBACK}) to reach rung 1 — human-verdict confidence ` +
93
+ ? `Attach ${exports.RUNG1_MIN_GRADES - agg.grades} more rig.grade() grades ` +
94
+ `(${agg.grades}/${exports.RUNG1_MIN_GRADES}) to reach rung 1 — judged confidence ` +
82
95
  "for routes without a schema to conform to."
83
96
  : "Rung 2 (LLM judges — value accuracy beyond mechanical conformance) arrives in Phase 5.";
84
97
  return {
@@ -87,7 +100,7 @@ function computeCoverage(rows, feedback) {
87
100
  conformRate: agg.samples === 0 ? 0 : agg.conform / agg.samples,
88
101
  repairRate: agg.samples === 0 ? 0 : agg.repaired / agg.samples,
89
102
  refusalRate: agg.samples === 0 ? 0 : agg.refused / agg.samples,
90
- feedbackCount: agg.feedback,
103
+ gradeCount: agg.grades,
91
104
  rung,
92
105
  nextRungUnlock,
93
106
  };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * rig.grade() — the unified judgment primitive (grade primitive, R1).
3
+ *
4
+ * A grade attaches a judgment to a SUBJECT (an inference / run / artifact):
5
+ * `{ score: 0–1 (primitive), scale?, comment?, kind, grader?, source? }`. The
6
+ * pass/fail VERDICT is DERIVED at read time (`pass = score >= threshold`), never
7
+ * stored. `rig.grade` writes one local `grades` row (synchronous SQLite insert,
8
+ * fire-and-forget); the exporter mirrors it to the cloud.
9
+ *
10
+ * `rig.grade` is the SOLE judgment write API. The temporary GP-1 compat wrappers
11
+ * (`rig.feedback` / `artifact.evaluate` / `run.evaluate`) and their adapters were
12
+ * removed in GP-3 — every judgment now builds a grade directly.
13
+ */
14
+ import type { GradeRow, GradeSubject } from "../types/telemetry";
15
+ /** Options for `rig.grade(subject, opts)`. `score` is the 0–1 primitive and is
16
+ * required; everything else is optional display / provenance. */
17
+ export interface GradeOpts {
18
+ /** 0–1 primitive (always present). up/pass = 1.0, down/fail = 0.0, else graded. */
19
+ readonly score: number;
20
+ /** Optional DISPLAY scale — `{ max }` (e.g. out of 100) or `{ label }` (e.g. "B+").
21
+ * Never changes the derived verdict, which is a threshold on `score`. */
22
+ readonly scale?: {
23
+ readonly max: number;
24
+ } | {
25
+ readonly label: string;
26
+ };
27
+ /** Written guidance saved for a later improvement path (was note/explanation). */
28
+ readonly comment?: string;
29
+ readonly kind: "human" | "model-judge" | "deterministic";
30
+ /** Optional specific grader name (e.g. "gpt-5-judge", "schema-check"). */
31
+ readonly grader?: string;
32
+ /** Provenance (e.g. "sdk", "console", a review-agent name). */
33
+ readonly source?: string;
34
+ /** The grade's own org — server-supplied ONLY, already authorized (T3). Omit
35
+ * from application code (a rig has one org and the exporter knows it). */
36
+ readonly orgId?: string;
37
+ /** Authenticated user who recorded it — same provenance rule as `orgId`. */
38
+ readonly createdBy?: string | null;
39
+ }
40
+ /** Build a GradeRow from a subject + opts. Validates the score bound (the one
41
+ * primitive — a judgment with no numeric score has no place in the grade model). */
42
+ export declare function buildGradeRow(subject: GradeSubject, opts: GradeOpts): GradeRow;
43
+ /** Build the rig's `grade` surface over a grade writer (the telemetry store).
44
+ * Kept here (not inlined in index.ts) so the SDK entrypoint stays under the LOC
45
+ * cap and the grade write surface lives with the primitive. */
46
+ export declare function makeGradeApi(store: {
47
+ recordGrade(row: GradeRow): void;
48
+ }): {
49
+ grade(subject: GradeSubject, opts: GradeOpts): GradeRow;
50
+ };
51
+ //# sourceMappingURL=grade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grade.d.ts","sourceRoot":"","sources":["../../src/feedback/grade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEjE;iEACiE;AACjE,MAAM,WAAW,SAAS;IACxB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;6EACyE;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,kFAAkF;IAClF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,eAAe,CAAC;IACzD,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;8EAC0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAQD;oFACoF;AACpF,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,CAuB9E;AAED;;+DAE+D;AAC/D,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAAE,WAAW,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAA;CAAE,GAAG;IACzE,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;CACzD,CAQA"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ /**
3
+ * rig.grade() — the unified judgment primitive (grade primitive, R1).
4
+ *
5
+ * A grade attaches a judgment to a SUBJECT (an inference / run / artifact):
6
+ * `{ score: 0–1 (primitive), scale?, comment?, kind, grader?, source? }`. The
7
+ * pass/fail VERDICT is DERIVED at read time (`pass = score >= threshold`), never
8
+ * stored. `rig.grade` writes one local `grades` row (synchronous SQLite insert,
9
+ * fire-and-forget); the exporter mirrors it to the cloud.
10
+ *
11
+ * `rig.grade` is the SOLE judgment write API. The temporary GP-1 compat wrappers
12
+ * (`rig.feedback` / `artifact.evaluate` / `run.evaluate`) and their adapters were
13
+ * removed in GP-3 — every judgment now builds a grade directly.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.buildGradeRow = buildGradeRow;
17
+ exports.makeGradeApi = makeGradeApi;
18
+ const node_crypto_1 = require("node:crypto");
19
+ function scaleFields(scale) {
20
+ if (scale === undefined)
21
+ return { scaleMax: null, scaleLabel: null };
22
+ if ("max" in scale)
23
+ return { scaleMax: scale.max, scaleLabel: null };
24
+ return { scaleMax: null, scaleLabel: scale.label };
25
+ }
26
+ /** Build a GradeRow from a subject + opts. Validates the score bound (the one
27
+ * primitive — a judgment with no numeric score has no place in the grade model). */
28
+ function buildGradeRow(subject, opts) {
29
+ if (subject.id === "") {
30
+ throw new Error("grade subject must have a non-empty id");
31
+ }
32
+ if (!Number.isFinite(opts.score) || opts.score < 0 || opts.score > 1) {
33
+ throw new Error(`grade score must be in [0, 1], got ${opts.score}`);
34
+ }
35
+ const { scaleMax, scaleLabel } = scaleFields(opts.scale);
36
+ return {
37
+ id: (0, node_crypto_1.randomUUID)(),
38
+ subjectKind: subject.kind,
39
+ subjectId: subject.id,
40
+ score: opts.score,
41
+ scaleMax,
42
+ scaleLabel,
43
+ comment: opts.comment ?? null,
44
+ kind: opts.kind,
45
+ grader: opts.grader ?? null,
46
+ source: opts.source ?? null,
47
+ orgId: opts.orgId !== undefined && opts.orgId !== "" ? opts.orgId : null,
48
+ createdBy: opts.createdBy ?? null,
49
+ ts: new Date().toISOString(),
50
+ };
51
+ }
52
+ /** Build the rig's `grade` surface over a grade writer (the telemetry store).
53
+ * Kept here (not inlined in index.ts) so the SDK entrypoint stays under the LOC
54
+ * cap and the grade write surface lives with the primitive. */
55
+ function makeGradeApi(store) {
56
+ return {
57
+ grade(subject, opts) {
58
+ const row = buildGradeRow(subject, opts);
59
+ store.recordGrade(row);
60
+ return row;
61
+ },
62
+ };
63
+ }
@@ -42,7 +42,7 @@ export declare const MODELRIG_HEADERS: {
42
42
  /** "provider/model" that repaired the output, when repair fired. */
43
43
  readonly repairedBy: "x-modelrig-repaired-by";
44
44
  readonly costUsd: "x-modelrig-cost-usd";
45
- /** The `rig.feedback()` handle (telemetry inference id). */
45
+ /** The `rig.grade()` inference handle (telemetry inference id). */
46
46
  readonly inferenceId: "x-modelrig-inference-id";
47
47
  };
48
48
  export declare const MODELRIG_REQUEST_HEADERS: {
@@ -1 +1 @@
1
- {"version":3,"file":"http-protocol.d.ts","sourceRoot":"","sources":["../../src/gateway/http-protocol.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http-protocol.d.ts","sourceRoot":"","sources":["../../src/gateway/http-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE9E,uCAAuC;AACvC,eAAO,MAAM,qBAAqB,yBAAyB,CAAC;AAC5D,2EAA2E;AAC3E,eAAO,MAAM,WAAW,eAAe,CAAC;AAExC,6DAA6D;AAC7D,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAO1C,eAAO,MAAM,gBAAgB;IAC3B,0EAA0E;;IAE1E;;;;eAIW;;;;IAIX,yEAAyE;;IAEzE,oEAAoE;;;IAGpE,mEAAmE;;CAE3D,CAAC;AAGX,eAAO,MAAM,wBAAwB;IACnC,qCAAqC;;IAErC,oCAAoC;;IAEpC,8EAA8E;;CAEtE,CAAC;AAEX,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;AAElC,4EAA4E;AAC5E,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3E;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,eAAe,GAAE,WAAW,CAAC,MAAM,CAAa,GAC/C,cAAc,CA6BhB;AAID,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IACxD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC1C,0DAA0D;IAC1D,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,eAAe,CAAC,EACrB;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GACzB;QAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;KAAE,GAChC;QACE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;QAC7B,QAAQ,CAAC,WAAW,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC;KACrG,CAAC;IACN,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;KAC9B,CAAC;CACH;AAID,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;QAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;KAC3C,CAAC;IACF,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,gBAAgB,GAAG,IAAI,CAAC;CACpF;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAClD,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;CACrC;AAID,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;QAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;KAC3C,CAAC;IACF,QAAQ,CAAC,aAAa,EAAE,oBAAoB,CAAC,eAAe,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,yBAAyB,EAAE,CAAC;CACxD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,gEAAgE;AAChE,eAAO,MAAM,QAAQ,WAAW,CAAC"}
@@ -51,7 +51,7 @@ exports.MODELRIG_HEADERS = {
51
51
  /** "provider/model" that repaired the output, when repair fired. */
52
52
  repairedBy: "x-modelrig-repaired-by",
53
53
  costUsd: "x-modelrig-cost-usd",
54
- /** The `rig.feedback()` handle (telemetry inference id). */
54
+ /** The `rig.grade()` inference handle (telemetry inference id). */
55
55
  inferenceId: "x-modelrig-inference-id",
56
56
  };
57
57
  // Request-side extension headers (spec §3.4).