modelrig 0.8.0 → 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.
- package/CHANGELOG.md +156 -0
- package/README.md +27 -2
- package/dist/artifacts/artifact.d.ts +12 -13
- package/dist/artifacts/artifact.d.ts.map +1 -1
- package/dist/artifacts/artifact.js +17 -23
- package/dist/artifacts/index.d.ts +13 -5
- package/dist/artifacts/index.d.ts.map +1 -1
- package/dist/artifacts/index.js +11 -4
- package/dist/artifacts/run-context.d.ts +3 -24
- package/dist/artifacts/run-context.d.ts.map +1 -1
- package/dist/artifacts/run-context.js +3 -39
- package/dist/bakeoff/engine.d.ts +29 -0
- package/dist/bakeoff/engine.d.ts.map +1 -1
- package/dist/bakeoff/engine.js +47 -0
- package/dist/bakeoff/eval-cases-rig.d.ts +36 -0
- package/dist/bakeoff/eval-cases-rig.d.ts.map +1 -0
- package/dist/bakeoff/eval-cases-rig.js +27 -0
- package/dist/bakeoff/eval-cases.d.ts +19 -0
- package/dist/bakeoff/eval-cases.d.ts.map +1 -1
- package/dist/bakeoff/eval-cases.js +18 -1
- package/dist/bakeoff/golden-judge.d.ts +47 -0
- package/dist/bakeoff/golden-judge.d.ts.map +1 -0
- package/dist/bakeoff/golden-judge.js +49 -0
- package/dist/bakeoff/quality.d.ts +30 -0
- package/dist/bakeoff/quality.d.ts.map +1 -1
- package/dist/bakeoff/quality.js +21 -0
- package/dist/bakeoff/replay.d.ts +11 -0
- package/dist/bakeoff/replay.d.ts.map +1 -1
- package/dist/bakeoff/replay.js +8 -0
- package/dist/bakeoff/report.d.ts +7 -0
- package/dist/bakeoff/report.d.ts.map +1 -1
- package/dist/bakeoff/report.js +26 -0
- package/dist/cli-judge.d.ts +12 -0
- package/dist/cli-judge.d.ts.map +1 -0
- package/dist/cli-judge.js +48 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -42
- package/dist/config.d.ts +54 -29
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +86 -47
- package/dist/detect/detector.d.ts +4 -2
- package/dist/detect/detector.d.ts.map +1 -1
- package/dist/detect/safe-harbor.d.ts +57 -0
- package/dist/detect/safe-harbor.d.ts.map +1 -0
- package/dist/detect/safe-harbor.js +278 -0
- package/dist/feedback/coverage.d.ts +11 -8
- package/dist/feedback/coverage.d.ts.map +1 -1
- package/dist/feedback/coverage.js +29 -16
- package/dist/feedback/grade.d.ts +51 -0
- package/dist/feedback/grade.d.ts.map +1 -0
- package/dist/feedback/grade.js +63 -0
- package/dist/gateway/http-protocol.d.ts +1 -1
- package/dist/gateway/http-protocol.d.ts.map +1 -1
- package/dist/gateway/http-protocol.js +1 -1
- package/dist/index.d.ts +44 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +110 -43
- package/dist/init/observe-cli.js +1 -1
- package/dist/init/observe.d.ts +2 -2
- package/dist/init/observe.d.ts.map +1 -1
- package/dist/init/observe.js +11 -7
- package/dist/mask/arm.d.ts +112 -0
- package/dist/mask/arm.d.ts.map +1 -0
- package/dist/mask/arm.js +179 -0
- package/dist/mask/index.d.ts +2 -0
- package/dist/mask/index.d.ts.map +1 -1
- package/dist/mask/index.js +7 -1
- package/dist/mask/mask-policy-cli.d.ts +12 -4
- package/dist/mask/mask-policy-cli.d.ts.map +1 -1
- package/dist/mask/mask-policy-cli.js +34 -9
- package/dist/query/grammar.d.ts +2 -2
- package/dist/query/grammar.d.ts.map +1 -1
- package/dist/query/grammar.js +3 -1
- package/dist/query/saved.d.ts +13 -0
- package/dist/query/saved.d.ts.map +1 -1
- package/dist/query/saved.js +67 -1
- package/dist/receipts/types.d.ts +1 -1
- package/dist/receipts/types.d.ts.map +1 -1
- package/dist/receipts/types.js +1 -0
- package/dist/registry/build.d.ts +43 -1
- package/dist/registry/build.d.ts.map +1 -1
- package/dist/registry/build.js +52 -0
- package/dist/registry/pricing-shape.d.ts +29 -0
- package/dist/registry/pricing-shape.d.ts.map +1 -1
- package/dist/registry/pricing-shape.js +10 -1
- package/dist/registry/rows.d.ts.map +1 -1
- package/dist/registry/rows.js +1 -0
- package/dist/registry/select.d.ts +6 -1
- package/dist/registry/select.d.ts.map +1 -1
- package/dist/registry/select.js +11 -0
- package/dist/routes/call-config.d.ts +199 -0
- package/dist/routes/call-config.d.ts.map +1 -0
- package/dist/routes/call-config.js +343 -0
- package/dist/routes/loader.js +5 -3
- package/dist/routes/objective-loader.d.ts +12 -0
- package/dist/routes/objective-loader.d.ts.map +1 -1
- package/dist/routes/objective-loader.js +82 -0
- package/dist/routes/resolved-bundle.d.ts +50 -0
- package/dist/routes/resolved-bundle.d.ts.map +1 -1
- package/dist/routes/resolved-bundle.js +52 -0
- package/dist/routes/screen-loader.d.ts +28 -0
- package/dist/routes/screen-loader.d.ts.map +1 -1
- package/dist/routes/screen-loader.js +51 -0
- package/dist/run/accept.d.ts +2 -0
- package/dist/run/accept.d.ts.map +1 -1
- package/dist/run/accept.js +1 -0
- package/dist/run/dispatch.d.ts +42 -13
- package/dist/run/dispatch.d.ts.map +1 -1
- package/dist/run/dispatch.js +107 -25
- package/dist/run/grounding.d.ts +28 -2
- package/dist/run/grounding.d.ts.map +1 -1
- package/dist/run/grounding.js +54 -10
- package/dist/run/record-attempt.d.ts +4 -0
- package/dist/run/record-attempt.d.ts.map +1 -1
- package/dist/run/record-attempt.js +4 -0
- package/dist/run/routing-docs.js +1 -1
- package/dist/run/run.d.ts.map +1 -1
- package/dist/run/run.js +21 -26
- package/dist/savings/odometer.d.ts +4 -0
- package/dist/savings/odometer.d.ts.map +1 -1
- package/dist/savings/odometer.js +20 -1
- package/dist/savings/swap-execute.d.ts +7 -0
- package/dist/savings/swap-execute.d.ts.map +1 -1
- package/dist/savings/swap-execute.js +30 -0
- package/dist/savings/swaps-client.d.ts +10 -0
- package/dist/savings/swaps-client.d.ts.map +1 -1
- package/dist/screen/fixtures/probe-corpora.d.ts +23 -0
- package/dist/screen/fixtures/probe-corpora.d.ts.map +1 -0
- package/dist/screen/fixtures/probe-corpora.js +69 -0
- package/dist/screen/index.d.ts +21 -0
- package/dist/screen/index.d.ts.map +1 -0
- package/dist/screen/index.js +64 -0
- package/dist/screen/model-screen.d.ts +111 -0
- package/dist/screen/model-screen.d.ts.map +1 -0
- package/dist/screen/model-screen.js +178 -0
- package/dist/screen/patterns.d.ts +51 -0
- package/dist/screen/patterns.d.ts.map +1 -0
- package/dist/screen/patterns.js +151 -0
- package/dist/screen/phi-gate.d.ts +52 -0
- package/dist/screen/phi-gate.d.ts.map +1 -0
- package/dist/screen/phi-gate.js +86 -0
- package/dist/screen/policy.d.ts +71 -0
- package/dist/screen/policy.d.ts.map +1 -0
- package/dist/screen/policy.js +334 -0
- package/dist/screen/probe.d.ts +118 -0
- package/dist/screen/probe.d.ts.map +1 -0
- package/dist/screen/probe.js +132 -0
- package/dist/screen/screen-cli.d.ts +16 -0
- package/dist/screen/screen-cli.d.ts.map +1 -0
- package/dist/screen/screen-cli.js +178 -0
- package/dist/screen/screen.d.ts +99 -0
- package/dist/screen/screen.d.ts.map +1 -0
- package/dist/screen/screen.js +0 -0
- package/dist/screen/sidecar.d.ts +69 -0
- package/dist/screen/sidecar.d.ts.map +1 -0
- package/dist/screen/sidecar.js +145 -0
- package/dist/screen/types.d.ts +43 -2
- package/dist/screen/types.d.ts.map +1 -1
- package/dist/settings/api-fetcher.d.ts +14 -3
- package/dist/settings/api-fetcher.d.ts.map +1 -1
- package/dist/settings/api-fetcher.js +61 -10
- package/dist/settings/grading-guide.d.ts +76 -0
- package/dist/settings/grading-guide.d.ts.map +1 -0
- package/dist/settings/grading-guide.js +23 -0
- package/dist/settings/index.d.ts +3 -2
- package/dist/settings/index.d.ts.map +1 -1
- package/dist/settings/index.js +2 -1
- package/dist/settings/task-settings.d.ts +44 -7
- package/dist/settings/task-settings.d.ts.map +1 -1
- package/dist/settings/task-settings.js +53 -12
- package/dist/status.d.ts +26 -20
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +47 -29
- package/dist/telemetry/artifact-store.d.ts +5 -6
- package/dist/telemetry/artifact-store.d.ts.map +1 -1
- package/dist/telemetry/artifact-store.js +10 -24
- package/dist/telemetry/attempt-meta.d.ts +21 -0
- package/dist/telemetry/attempt-meta.d.ts.map +1 -1
- package/dist/telemetry/attempt-meta.js +9 -0
- package/dist/telemetry/exporter.d.ts +2 -2
- package/dist/telemetry/exporter.d.ts.map +1 -1
- package/dist/telemetry/exporter.js +22 -41
- package/dist/telemetry/grade-mappers.d.ts +22 -0
- package/dist/telemetry/grade-mappers.d.ts.map +1 -0
- package/dist/telemetry/grade-mappers.js +58 -0
- package/dist/telemetry/grades-sql.d.ts +53 -0
- package/dist/telemetry/grades-sql.d.ts.map +1 -0
- package/dist/telemetry/grades-sql.js +133 -0
- package/dist/telemetry/ingest-protocol.d.ts +29 -46
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -1
- package/dist/telemetry/ingest-protocol.js +16 -54
- package/dist/telemetry/store-migrations.d.ts.map +1 -1
- package/dist/telemetry/store-migrations.js +51 -0
- package/dist/telemetry/store.d.ts +9 -6
- package/dist/telemetry/store.d.ts.map +1 -1
- package/dist/telemetry/store.js +8 -50
- package/dist/tenancy/api-key-format.d.ts +30 -1
- package/dist/tenancy/api-key-format.d.ts.map +1 -1
- package/dist/tenancy/api-key-format.js +33 -1
- package/dist/types/provider.d.ts +3 -0
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/types/provider.js +25 -0
- package/dist/types/route.d.ts +78 -2
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +43 -46
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/validate-cli.d.ts.map +1 -1
- package/dist/validate-cli.js +32 -0
- package/dist/verify/verify.d.ts +5 -0
- package/dist/verify/verify.d.ts.map +1 -1
- package/dist/verify/verify.js +2 -0
- package/dist/watch/evaluate.d.ts +84 -1
- package/dist/watch/evaluate.d.ts.map +1 -1
- package/dist/watch/evaluate.js +28 -0
- package/dist/watch/monitor.d.ts +8 -2
- package/dist/watch/monitor.d.ts.map +1 -1
- package/dist/watch/monitor.js +13 -5
- package/dist/watch/regret-monitor-cli.d.ts +16 -0
- package/dist/watch/regret-monitor-cli.d.ts.map +1 -0
- package/dist/watch/regret-monitor-cli.js +137 -0
- package/dist/watch/regret-monitor.d.ts +168 -0
- package/dist/watch/regret-monitor.d.ts.map +1 -0
- package/dist/watch/regret-monitor.js +304 -0
- package/dist/watch/upgrade.d.ts +62 -0
- package/dist/watch/upgrade.d.ts.map +1 -0
- package/dist/watch/upgrade.js +57 -0
- package/docs/agent-skill/SKILL.md +109 -5
- package/docs/how-it-fits.md +3 -2
- package/docs/instrumentation.md +149 -21
- package/docs/llms.txt +64 -20
- package/docs/mcp-oracle.md +249 -0
- package/docs/quickstart.md +103 -9
- package/package.json +16 -3
- package/registry/leaderboard.json +74 -0
- package/registry/registry.json +150 -112
- package/screen.d.ts +16 -0
- package/templates/call-disposition-qa.json +77 -0
- package/templates/catalog-cleansing.json +77 -0
- package/templates/compliance-review.json +76 -0
- package/templates/cs-next-action.json +76 -0
- package/templates/document-extraction.json +78 -0
- package/templates/financial-classification.json +75 -0
- package/templates/lead-qualification.json +76 -0
- package/templates/medical-classification.json +71 -0
- package/templates/ticket-triage.json +76 -0
- package/dist/telemetry/supabase-exporter.d.ts +0 -64
- package/dist/telemetry/supabase-exporter.d.ts.map +0 -1
- package/dist/telemetry/supabase-exporter.js +0 -211
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Screening — T0 deterministic injection patterns + the optional T1 classifier
|
|
4
|
+
* adapter (WIRED 2026-08-25, SC-1a). Spec §3 (Detector) + §4 (T0/T1).
|
|
5
|
+
*
|
|
6
|
+
* An OWASP-derived pattern pack that implements the shared `Detector` interface
|
|
7
|
+
* (packages/modelrig/src/detect/detector.ts) with `kind: "deterministic"`,
|
|
8
|
+
* confidence 1 on a match.
|
|
9
|
+
*
|
|
10
|
+
* DOCTRINE (research §2.2): detection is a SIGNAL, not a control. These patterns
|
|
11
|
+
* are trivially evaded by paraphrase/encoding; they exist to DRIVE the
|
|
12
|
+
* deterministic actions (flag/strip/quarantine) and to populate a MEASURED
|
|
13
|
+
* false-positive rate, NEVER to claim prevention (claim-lint, spec §7).
|
|
14
|
+
*
|
|
15
|
+
* LEAK INVARIANT (spec §1.4): a detector emits SPANS (offsets + type +
|
|
16
|
+
* confidence) — never the matched substring. Nothing in this file returns,
|
|
17
|
+
* logs, or persists a matched value.
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.ScreenDetectorUnavailableError = exports.PATTERNS_ID = void 0;
|
|
21
|
+
exports.createPatternDetector = createPatternDetector;
|
|
22
|
+
exports.createClassifierDetector = createClassifierDetector;
|
|
23
|
+
const node_fs_1 = require("node:fs");
|
|
24
|
+
/** The registry id + version of the deterministic pack. Bumped when the pattern
|
|
25
|
+
* set changes so a receipt's `detectors[].version` pins what ran. */
|
|
26
|
+
exports.PATTERNS_ID = "patterns@v1";
|
|
27
|
+
/** The T0 pack. Deliberately narrow, US-English-shaped (A8), and biased toward
|
|
28
|
+
* classic injection SHAPES over broad keyword nets so the measured FP rate stays
|
|
29
|
+
* honest. Each entry is a signal, not a guarantee. */
|
|
30
|
+
const INJECTION_PATTERNS = [
|
|
31
|
+
// "ignore the previous instructions" / "disregard all prior rules" family.
|
|
32
|
+
{
|
|
33
|
+
type: "injection:instruction_override",
|
|
34
|
+
re: /\b(?:ignore|disregard|forget|override)\b[^.?!\n]{0,40}\b(?:previous|prior|above|earlier|all|any)\b[^.?!\n]{0,20}\b(?:instruction|instructions|prompt|prompts|rule|rules|context|direction|directions)\b/gi,
|
|
35
|
+
},
|
|
36
|
+
// "you are now …", "new instructions:", "act as", "pretend to be" — role hijack.
|
|
37
|
+
{
|
|
38
|
+
type: "injection:role_override",
|
|
39
|
+
re: /\b(?:you\s+are\s+now|from\s+now\s+on|new\s+(?:instructions?|role|persona|system\s+prompt)|act\s+as(?:\s+if)?|pretend\s+to\s+be|roleplay\s+as|switch\s+to\s+developer\s+mode)\b/gi,
|
|
40
|
+
},
|
|
41
|
+
// An untrusted segment carrying its own "system:" / "assistant:" role label —
|
|
42
|
+
// the classic transcript-smuggling shape the raw lane's JSON-turn guard closes.
|
|
43
|
+
{
|
|
44
|
+
type: "injection:role_label",
|
|
45
|
+
re: /(?:^|\n)\s*(?:system|assistant|developer)\s*:/gi,
|
|
46
|
+
},
|
|
47
|
+
// Chat-template / instruction delimiters smuggled into data.
|
|
48
|
+
{
|
|
49
|
+
type: "injection:delimiter",
|
|
50
|
+
re: /<\/?(?:system|assistant|user|instructions?)>|\[\/?INST\]|<\|(?:im_start|im_end|system|user|assistant|endoftext)\|>/gi,
|
|
51
|
+
},
|
|
52
|
+
// "reveal your system prompt" / "print your instructions" — prompt-leak probe.
|
|
53
|
+
{
|
|
54
|
+
type: "injection:prompt_leak",
|
|
55
|
+
re: /\b(?:reveal|print|repeat|show|output|display|tell\s+me)\b[^.?!\n]{0,30}\b(?:system\s+prompt|your\s+instructions|initial\s+prompt|the\s+prompt\s+above|your\s+rules)\b/gi,
|
|
56
|
+
},
|
|
57
|
+
// "email/exfiltrate the api key/password/secret" — data-exfiltration steering.
|
|
58
|
+
{
|
|
59
|
+
type: "injection:exfiltration",
|
|
60
|
+
re: /\b(?:send|exfiltrate|post|email|upload|leak|forward|transmit)\b[^.?!\n]{0,40}\b(?:api[\s_-]?key|password|secret|secrets|token|credential|credentials|private\s+key)\b/gi,
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
/** Unicode tag plane (U+E0000–U+E007F) — invisible chars abused to smuggle
|
|
64
|
+
* instructions past a human reviewer. Detected as its own finding TYPE; the
|
|
65
|
+
* assembler strips them from delivered content, but their PRESENCE in untrusted
|
|
66
|
+
* input is itself a signal worth counting. */
|
|
67
|
+
const UNICODE_TAG_RE = /[\u{E0000}-\u{E007F}]+/gu;
|
|
68
|
+
/** Collect the spans one pattern matches in `text`. Offsets are into the exact
|
|
69
|
+
* string handed in; the matched substring is discarded immediately. */
|
|
70
|
+
function spansFor(type, re, text) {
|
|
71
|
+
const spans = [];
|
|
72
|
+
for (const m of text.matchAll(re)) {
|
|
73
|
+
const start = m.index ?? 0;
|
|
74
|
+
spans.push({ start, end: start + m[0].length, type, confidence: 1 });
|
|
75
|
+
}
|
|
76
|
+
return spans;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The T0 pattern detector. Runs only on untrusted/semi tiers — the template's
|
|
80
|
+
* own trusted text is never scanned (it is the route author's, by construction).
|
|
81
|
+
* Deterministic: confidence 1 on every match, versioned as `patterns@v1`.
|
|
82
|
+
*/
|
|
83
|
+
function createPatternDetector() {
|
|
84
|
+
return {
|
|
85
|
+
id: exports.PATTERNS_ID,
|
|
86
|
+
kind: "deterministic",
|
|
87
|
+
detect(input) {
|
|
88
|
+
// Trusted content is the route's own framing — never an injection source.
|
|
89
|
+
if (input.tier === "trusted")
|
|
90
|
+
return Promise.resolve([]);
|
|
91
|
+
const spans = [];
|
|
92
|
+
for (const p of INJECTION_PATTERNS)
|
|
93
|
+
spans.push(...spansFor(p.type, p.re, input.text));
|
|
94
|
+
spans.push(...spansFor("injection:unicode_tag", UNICODE_TAG_RE, input.text));
|
|
95
|
+
// Reading order keeps the (offsets-only) span list stable and testable.
|
|
96
|
+
spans.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
97
|
+
return Promise.resolve(spans);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Thrown by {@link createClassifierDetector} when the optional peer dep or the
|
|
102
|
+
* local model file is absent — a TYPED signal the engine catches to degrade to
|
|
103
|
+
* T0 with `degraded: true` (spec §4.3), never a run-failing surprise. */
|
|
104
|
+
class ScreenDetectorUnavailableError extends Error {
|
|
105
|
+
constructor(detectorId, reason) {
|
|
106
|
+
super(`screen detector "${detectorId}" is unavailable: ${reason}`);
|
|
107
|
+
this.name = "ScreenDetectorUnavailableError";
|
|
108
|
+
this.detectorId = detectorId;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
exports.ScreenDetectorUnavailableError = ScreenDetectorUnavailableError;
|
|
112
|
+
/**
|
|
113
|
+
* The optional T1 in-process classifier adapter (A3: OPTIONAL peer dependency;
|
|
114
|
+
* NO weights bundled; NO default npm dep). Absent peer dep OR absent model file
|
|
115
|
+
* ⇒ throws {@link ScreenDetectorUnavailableError} so the engine degrades to T0
|
|
116
|
+
* with a once-per-process notice and `degraded: true` on the receipt.
|
|
117
|
+
*
|
|
118
|
+
* ModelRig NEVER bundles or re-hosts weights — the customer fetches them with
|
|
119
|
+
* `modelrig screen pull <detector>` to a local cache and points `modelPath` at
|
|
120
|
+
* the result. The runtime peer (`onnxruntime-node` or a WASM transformers
|
|
121
|
+
* backend) is likewise the customer's to install.
|
|
122
|
+
*/
|
|
123
|
+
function createClassifierDetector(opts) {
|
|
124
|
+
const peer = opts.runtime === "onnx" ? "onnxruntime-node" : "@xenova/transformers";
|
|
125
|
+
// A3: the peer is an OPTIONAL dependency resolved at RUNTIME. `require` is used
|
|
126
|
+
// (not a static import) precisely so a missing peer is a catchable throw, not a
|
|
127
|
+
// load-time crash / a bundled dependency.
|
|
128
|
+
let runtimeModule;
|
|
129
|
+
try {
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
|
|
131
|
+
runtimeModule = require(peer);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
throw new ScreenDetectorUnavailableError(opts.id, `optional peer dependency "${peer}" is not installed (install it and run \`modelrig screen pull ${opts.id}\`)`);
|
|
135
|
+
}
|
|
136
|
+
if (!(0, node_fs_1.existsSync)(opts.modelPath)) {
|
|
137
|
+
throw new ScreenDetectorUnavailableError(opts.id, `model file not found at "${opts.modelPath}" — fetch it with \`modelrig screen pull ${opts.id}\` (weights are never bundled, A3)`);
|
|
138
|
+
}
|
|
139
|
+
// The concrete inference wiring (tokenize → run → score → span) is delegated to
|
|
140
|
+
// the loaded runtime; this SC-1a scaffold proves the OPTIONAL-load contract and
|
|
141
|
+
// the fail-closed degrade path. A configured-and-present classifier tier is a
|
|
142
|
+
// Matt-env run (live weights); the deterministic T0 path is what ships.
|
|
143
|
+
void runtimeModule;
|
|
144
|
+
return {
|
|
145
|
+
id: opts.id,
|
|
146
|
+
kind: "classifier",
|
|
147
|
+
detect(_input) {
|
|
148
|
+
return Promise.resolve([]);
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SC-2 — the gated `phi` route posture (spec-sc2 §4). Deterministic, fail-closed,
|
|
3
|
+
* dependency-free. Runs at ROUTE LOAD (the same place `require:` / `mask:` /
|
|
4
|
+
* `screen:` are validated), so a mis-postured PHI route REFUSES TO LOAD with a
|
|
5
|
+
* teaching error rather than silently serving PHI on an unmasked, un-screened,
|
|
6
|
+
* content-retaining route.
|
|
7
|
+
*
|
|
8
|
+
* A route classified `phi` (route-level `classification: phi`) MUST satisfy ALL:
|
|
9
|
+
* 1. mask effective mode ≥ redact — i.e. mask rewrites (mode `mask` or `block`,
|
|
10
|
+
* CS-1); `off`/`detect` do NOT mask and fail the gate.
|
|
11
|
+
* 2. `require: zero_retention` OR a `sidecar` detector present in
|
|
12
|
+
* `screen.detectors` (the managed-custody + sidecar path).
|
|
13
|
+
*
|
|
14
|
+
* This does NOT claim de-identification (that is a banned claim, §6). It enforces
|
|
15
|
+
* that PHI never rides an unmasked, un-screened, content-retaining route. The
|
|
16
|
+
* gate is code-visible and lane-independent: it checks the mask mode, the
|
|
17
|
+
* `require` list, and the presence of a sidecar detector — all resolved at load.
|
|
18
|
+
* `modelrig validate` prints {@link describePhiPosture}: the resolved posture and
|
|
19
|
+
* the specific unmet requirement.
|
|
20
|
+
*/
|
|
21
|
+
import type { DataClassification } from "../artifacts/classification";
|
|
22
|
+
import type { ResolvedMaskPolicy } from "../mask/types";
|
|
23
|
+
import type { Requirement } from "../types/route";
|
|
24
|
+
import type { ResolvedScreenPolicy } from "./types";
|
|
25
|
+
/** The load-time inputs the gate reads — all already resolved by the loader. */
|
|
26
|
+
export interface PhiPostureInput {
|
|
27
|
+
/** The route-level `classification`, if any. The gate fires only for `phi`. */
|
|
28
|
+
readonly classification?: DataClassification;
|
|
29
|
+
readonly mask?: ResolvedMaskPolicy;
|
|
30
|
+
readonly screen?: ResolvedScreenPolicy;
|
|
31
|
+
readonly require: readonly Requirement[];
|
|
32
|
+
}
|
|
33
|
+
/** The resolved posture — what the gate saw and whether it passed. */
|
|
34
|
+
export interface PhiPosture {
|
|
35
|
+
readonly isPhi: boolean;
|
|
36
|
+
readonly maskRedacts: boolean;
|
|
37
|
+
readonly zeroRetention: boolean;
|
|
38
|
+
readonly sidecarPresent: boolean;
|
|
39
|
+
readonly satisfied: boolean;
|
|
40
|
+
}
|
|
41
|
+
/** Resolve the posture for a route (whether or not it is `phi`). */
|
|
42
|
+
export declare function resolvePhiPosture(input: PhiPostureInput): PhiPosture;
|
|
43
|
+
/**
|
|
44
|
+
* Teaching-style problems for a mis-postured `phi` route (CE-2 fixHint pattern) —
|
|
45
|
+
* EMPTY when the route is not `phi` or the posture is satisfied. Each string
|
|
46
|
+
* names the SPECIFIC unmet requirement so the author knows exactly what to add.
|
|
47
|
+
*/
|
|
48
|
+
export declare function checkPhiPosture(input: PhiPostureInput): readonly string[];
|
|
49
|
+
/** A one-line human posture summary for `modelrig validate` (spec-sc2 §4): the
|
|
50
|
+
* resolved posture and, when unsatisfied, the unmet requirement. */
|
|
51
|
+
export declare function describePhiPosture(input: PhiPostureInput): string;
|
|
52
|
+
//# sourceMappingURL=phi-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phi-gate.d.ts","sourceRoot":"","sources":["../../src/screen/phi-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,QAAQ,CAAC,cAAc,CAAC,EAAE,kBAAkB,CAAC;IAC7C,QAAQ,CAAC,IAAI,CAAC,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C;AAED,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAcD,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,eAAe,GAAG,UAAU,CAYpE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,MAAM,EAAE,CAkBzE;AAED;oEACoE;AACpE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAYjE"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SC-2 — the gated `phi` route posture (spec-sc2 §4). Deterministic, fail-closed,
|
|
4
|
+
* dependency-free. Runs at ROUTE LOAD (the same place `require:` / `mask:` /
|
|
5
|
+
* `screen:` are validated), so a mis-postured PHI route REFUSES TO LOAD with a
|
|
6
|
+
* teaching error rather than silently serving PHI on an unmasked, un-screened,
|
|
7
|
+
* content-retaining route.
|
|
8
|
+
*
|
|
9
|
+
* A route classified `phi` (route-level `classification: phi`) MUST satisfy ALL:
|
|
10
|
+
* 1. mask effective mode ≥ redact — i.e. mask rewrites (mode `mask` or `block`,
|
|
11
|
+
* CS-1); `off`/`detect` do NOT mask and fail the gate.
|
|
12
|
+
* 2. `require: zero_retention` OR a `sidecar` detector present in
|
|
13
|
+
* `screen.detectors` (the managed-custody + sidecar path).
|
|
14
|
+
*
|
|
15
|
+
* This does NOT claim de-identification (that is a banned claim, §6). It enforces
|
|
16
|
+
* that PHI never rides an unmasked, un-screened, content-retaining route. The
|
|
17
|
+
* gate is code-visible and lane-independent: it checks the mask mode, the
|
|
18
|
+
* `require` list, and the presence of a sidecar detector — all resolved at load.
|
|
19
|
+
* `modelrig validate` prints {@link describePhiPosture}: the resolved posture and
|
|
20
|
+
* the specific unmet requirement.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.resolvePhiPosture = resolvePhiPosture;
|
|
24
|
+
exports.checkPhiPosture = checkPhiPosture;
|
|
25
|
+
exports.describePhiPosture = describePhiPosture;
|
|
26
|
+
/** A mask policy "redacts" (rewrites content) iff its effective mode is `mask`
|
|
27
|
+
* or `block` — `off`/`detect` scan but do not rewrite (CS-1 §3). */
|
|
28
|
+
function maskRedacts(mask) {
|
|
29
|
+
return mask !== undefined && (mask.policy.mode === "mask" || mask.policy.mode === "block");
|
|
30
|
+
}
|
|
31
|
+
/** A sidecar detector is present iff the resolved screen policy carries a
|
|
32
|
+
* `sidecar:*` detector identity (built from `screen.sidecar` at resolve time). */
|
|
33
|
+
function hasSidecar(screen) {
|
|
34
|
+
return screen !== undefined && screen.detectorMeta.some((d) => d.id.startsWith("sidecar:"));
|
|
35
|
+
}
|
|
36
|
+
/** Resolve the posture for a route (whether or not it is `phi`). */
|
|
37
|
+
function resolvePhiPosture(input) {
|
|
38
|
+
const isPhi = input.classification === "phi";
|
|
39
|
+
const maskR = maskRedacts(input.mask);
|
|
40
|
+
const zdr = input.require.includes("zero_retention");
|
|
41
|
+
const sidecar = hasSidecar(input.screen);
|
|
42
|
+
return {
|
|
43
|
+
isPhi,
|
|
44
|
+
maskRedacts: maskR,
|
|
45
|
+
zeroRetention: zdr,
|
|
46
|
+
sidecarPresent: sidecar,
|
|
47
|
+
satisfied: maskR && (zdr || sidecar),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Teaching-style problems for a mis-postured `phi` route (CE-2 fixHint pattern) —
|
|
52
|
+
* EMPTY when the route is not `phi` or the posture is satisfied. Each string
|
|
53
|
+
* names the SPECIFIC unmet requirement so the author knows exactly what to add.
|
|
54
|
+
*/
|
|
55
|
+
function checkPhiPosture(input) {
|
|
56
|
+
const posture = resolvePhiPosture(input);
|
|
57
|
+
if (!posture.isPhi || posture.satisfied)
|
|
58
|
+
return [];
|
|
59
|
+
const problems = [];
|
|
60
|
+
if (!posture.maskRedacts) {
|
|
61
|
+
problems.push("a `phi`-classified route must mask its content — set `mask.mode: mask` (or `block`); " +
|
|
62
|
+
"`off`/`detect` do not redact. PHI must never ride an unmasked route.");
|
|
63
|
+
}
|
|
64
|
+
if (!posture.zeroRetention && !posture.sidecarPresent) {
|
|
65
|
+
problems.push("a `phi`-classified route must either `require: [zero_retention]` OR configure a `screen.sidecar` " +
|
|
66
|
+
"(a customer-run de-id detector, present in the resolved `screen.detectors` as `sidecar:<digest>`). " +
|
|
67
|
+
"PHI must never ride a content-retaining route without the sidecar.");
|
|
68
|
+
}
|
|
69
|
+
return problems;
|
|
70
|
+
}
|
|
71
|
+
/** A one-line human posture summary for `modelrig validate` (spec-sc2 §4): the
|
|
72
|
+
* resolved posture and, when unsatisfied, the unmet requirement. */
|
|
73
|
+
function describePhiPosture(input) {
|
|
74
|
+
const p = resolvePhiPosture(input);
|
|
75
|
+
if (!p.isPhi)
|
|
76
|
+
return "";
|
|
77
|
+
const parts = [
|
|
78
|
+
`mask≥redact=${p.maskRedacts ? "yes" : "NO"}`,
|
|
79
|
+
`zero_retention=${p.zeroRetention ? "yes" : "no"}`,
|
|
80
|
+
`sidecar=${p.sidecarPresent ? "yes" : "no"}`,
|
|
81
|
+
];
|
|
82
|
+
const verdict = p.satisfied
|
|
83
|
+
? "OK — PHI posture satisfied"
|
|
84
|
+
: `UNMET — ${checkPhiPosture(input).join(" ")}`;
|
|
85
|
+
return `phi posture [${parts.join(" · ")}] → ${verdict}`;
|
|
86
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screening — policy loading & validation (WIRED 2026-08-25, SC-1a). Spec §4.1.
|
|
3
|
+
*
|
|
4
|
+
* Runs at ROUTE LOAD (same place `require:` / `mask:` are validated),
|
|
5
|
+
* synchronously — the route loader is sync, so the shape check, the detector
|
|
6
|
+
* build, and the hash are too. An unknown detector, an unknown action, or a
|
|
7
|
+
* `sources` key that LOOSENS a default tier is a LOAD error (teaching message,
|
|
8
|
+
* CE-2 fixHint style), never a runtime surprise (spec §4.1, §4.3 row 1).
|
|
9
|
+
*
|
|
10
|
+
* The single discipline shared with mask/policy.ts: validate the raw shape first
|
|
11
|
+
* (returns teaching strings, never throws), then parse, then resolve (builds
|
|
12
|
+
* detectors + the stable `policyHash`). A configured-but-unavailable optional
|
|
13
|
+
* classifier is NOT a load error — it degrades to T0 with `degraded: true`
|
|
14
|
+
* (spec §4.3); only a malformed policy fails the load.
|
|
15
|
+
*/
|
|
16
|
+
import { type ModelScreenCall, type DailyCapMeter } from "./model-screen";
|
|
17
|
+
import type { ResolvedScreenPolicy, ScreenPolicy } from "./types";
|
|
18
|
+
/**
|
|
19
|
+
* Validate the raw YAML `screen:` block shape (used by the route loader and by
|
|
20
|
+
* `modelrig validate`). Returns teaching-style problem strings (CE-2 fixHint
|
|
21
|
+
* pattern) — EMPTY means valid. Never throws.
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateScreenPolicyShape(raw: unknown): readonly string[];
|
|
24
|
+
/** Parse a validated raw block into a typed {@link ScreenPolicy}. Assumes
|
|
25
|
+
* {@link validateScreenPolicyShape} already passed (caller checks first). */
|
|
26
|
+
export declare function parseScreenPolicy(raw: Record<string, unknown>): ScreenPolicy;
|
|
27
|
+
/** Local cache dir for optional classifier weights (`modelrig screen pull`
|
|
28
|
+
* writes here; the resolver reads here). Weights are NEVER bundled or re-hosted
|
|
29
|
+
* (A3) — this is the customer's local store under the home dir. (A configurable
|
|
30
|
+
* location can ride RigConfig in SC-1b; env is read only in config.ts.) */
|
|
31
|
+
export declare function screenCacheDir(): string;
|
|
32
|
+
/** The on-disk model path a classifier id resolves to in the local cache. */
|
|
33
|
+
export declare function classifierModelPath(id: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a parsed policy into built detectors + a stable `policyHash`. The T0
|
|
36
|
+
* pattern detector is ALWAYS built; each `classifier:` id is built from the
|
|
37
|
+
* local cache and, if its optional peer dep or model file is absent, DROPPED
|
|
38
|
+
* with `degraded: true` (spec §4.3 — degrade to T0, never a load failure). A
|
|
39
|
+
* non-`ScreenDetectorUnavailableError` throw is rethrown (a real bug, not an
|
|
40
|
+
* absent optional). Pure but for the cache-existence check. */
|
|
41
|
+
/**
|
|
42
|
+
* SC-3 model-screen wiring (spec-sc3 §2). The T3 tier needs a metered inference
|
|
43
|
+
* on the customer's CONFIGURED provider, which the pure route loader has no
|
|
44
|
+
* handle to — so the dispatch layer injects the screen call (and its daily cap)
|
|
45
|
+
* here. When a `model:screen@<model>` id is configured but NO wiring is supplied
|
|
46
|
+
* (pure `modelrig validate` / route load), the tier is UNAVAILABLE at load and
|
|
47
|
+
* the policy resolves `degraded: true` — exactly like a missing classifier
|
|
48
|
+
* (spec-sc3 §2: optional; absence degrades, never a load failure). When wiring is
|
|
49
|
+
* supplied, the detector is built and its throws (cap-exhausted / call failure)
|
|
50
|
+
* ride the shipped seam's §4.3 fail-closed matrix.
|
|
51
|
+
*/
|
|
52
|
+
export interface ModelScreenWiring {
|
|
53
|
+
/** The metered structured-boolean screen call (customer's provider). */
|
|
54
|
+
readonly call: ModelScreenCall;
|
|
55
|
+
/** Calls allowed per UTC day (mirrors run-judge). */
|
|
56
|
+
readonly dailyCap: number;
|
|
57
|
+
/** Confidence stamped on a flagged span (default 0.9). */
|
|
58
|
+
readonly flagConfidence?: number;
|
|
59
|
+
/** Shared per-process daily meter (defaults to one built per detector). */
|
|
60
|
+
readonly meter?: DailyCapMeter;
|
|
61
|
+
/** Injectable clock for the cap's UTC-day boundary. */
|
|
62
|
+
readonly now?: () => Date;
|
|
63
|
+
}
|
|
64
|
+
export interface ResolveScreenOptions {
|
|
65
|
+
/** Injected model-screen wiring; absent ⇒ a configured model tier degrades. */
|
|
66
|
+
readonly modelScreen?: ModelScreenWiring;
|
|
67
|
+
}
|
|
68
|
+
export declare function resolveScreenPolicy(policy: ScreenPolicy, opts?: ResolveScreenOptions): ResolvedScreenPolicy;
|
|
69
|
+
/** sha256 over the canonical policy JSON — the `policy_hash` a receipt carries. */
|
|
70
|
+
export declare function policyHashOf(policy: ScreenPolicy): string;
|
|
71
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/screen/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAeH,OAAO,EAAmD,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC3H,OAAO,KAAK,EAEV,oBAAoB,EAEpB,YAAY,EACb,MAAM,SAAS,CAAC;AA0CjB;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAgEzE;AAwCD;6EAC6E;AAC7E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CAgB5E;AAaD;;;2EAG2E;AAC3E,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEtD;AAgCD;;;;;;+DAM+D;AAC/D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IAChC,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;IAC/B,uDAAuD;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,+EAA+E;IAC/E,QAAQ,CAAC,WAAW,CAAC,EAAE,iBAAiB,CAAC;CAC1C;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,GAAE,oBAAyB,GAAG,oBAAoB,CAgF/G;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAEzD"}
|