@motebit/protocol 1.2.0 → 2.0.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/README.md +4 -2
- package/dist/artifact-type.d.ts +144 -0
- package/dist/artifact-type.d.ts.map +1 -0
- package/dist/artifact-type.js +107 -0
- package/dist/artifact-type.js.map +1 -0
- package/dist/audience.d.ts +108 -0
- package/dist/audience.d.ts.map +1 -0
- package/dist/audience.js +104 -0
- package/dist/audience.js.map +1 -0
- package/dist/co-browse.d.ts +369 -0
- package/dist/co-browse.d.ts.map +1 -0
- package/dist/co-browse.js +64 -0
- package/dist/co-browse.js.map +1 -0
- package/dist/computer-use.d.ts +463 -3
- package/dist/computer-use.d.ts.map +1 -1
- package/dist/computer-use.js +40 -0
- package/dist/computer-use.js.map +1 -1
- package/dist/event-type.d.ts +62 -0
- package/dist/event-type.d.ts.map +1 -0
- package/dist/event-type.js +123 -0
- package/dist/event-type.js.map +1 -0
- package/dist/index.d.ts +257 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +84 -1
- package/dist/index.js.map +1 -1
- package/dist/memory-events.d.ts +13 -0
- package/dist/memory-events.d.ts.map +1 -1
- package/dist/money.d.ts +33 -0
- package/dist/money.d.ts.map +1 -0
- package/dist/money.js +41 -0
- package/dist/money.js.map +1 -0
- package/dist/perception.d.ts +347 -0
- package/dist/perception.d.ts.map +1 -0
- package/dist/perception.js +9 -0
- package/dist/perception.js.map +1 -0
- package/dist/retention-policy.d.ts +8 -1
- package/dist/retention-policy.d.ts.map +1 -1
- package/dist/retention-policy.js +18 -0
- package/dist/retention-policy.js.map +1 -1
- package/dist/routing.d.ts +266 -0
- package/dist/routing.d.ts.map +1 -0
- package/dist/routing.js +88 -0
- package/dist/routing.js.map +1 -0
- package/dist/sensitivity.d.ts +123 -0
- package/dist/sensitivity.d.ts.map +1 -0
- package/dist/sensitivity.js +154 -0
- package/dist/sensitivity.js.map +1 -0
- package/dist/settlement-asset.d.ts +92 -0
- package/dist/settlement-asset.d.ts.map +1 -0
- package/dist/settlement-asset.js +82 -0
- package/dist/settlement-asset.js.map +1 -0
- package/dist/settlement-mode.d.ts +144 -13
- package/dist/settlement-mode.d.ts.map +1 -1
- package/dist/settlement-mode.js +45 -1
- package/dist/settlement-mode.js.map +1 -1
- package/dist/transparency.d.ts +116 -0
- package/dist/transparency.d.ts.map +1 -0
- package/dist/transparency.js +67 -0
- package/dist/transparency.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routing primitive — closed-registry types for the auto-router.
|
|
3
|
+
*
|
|
4
|
+
* The auto-router is the model-selection counterpart to the chrome
|
|
5
|
+
* matrix: `f(TaskShape × ProviderCapability × Constraints) →
|
|
6
|
+
* RoutingDecision`. This module defines the wire-shape types; the
|
|
7
|
+
* judgment-layer dispatcher (`dispatchRouting`) lives in BSL
|
|
8
|
+
* `@motebit/policy/src/auto-router.ts`. Consumers (motebit-cloud
|
|
9
|
+
* proxy, BYOK web layer, on-device runtime) call the dispatcher
|
|
10
|
+
* with their own provider catalogs.
|
|
11
|
+
*
|
|
12
|
+
* **Closed registry shape** — same closure pattern as `SuiteId`,
|
|
13
|
+
* `TokenAudience`, `ToolMode`, `ContentArtifactType`. The `TaskShape`
|
|
14
|
+
* literal union is the wire law; named constants are developer
|
|
15
|
+
* ergonomics; `ALL_TASK_SHAPES` is the canonical iteration order.
|
|
16
|
+
* Adding a task shape is intentional protocol-level work: a new
|
|
17
|
+
* entry here, a new arm in `REFERENCE_ROUTING_POLICY`, drift-gate
|
|
18
|
+
* coverage on every consumer.
|
|
19
|
+
*
|
|
20
|
+
* **TaskShape agility — the 7th instance of agility-as-role.**
|
|
21
|
+
* Per [`docs/doctrine/agility-as-role.md`], `TaskShape` is the
|
|
22
|
+
* closed registry (the role); the routing-policy itself is a
|
|
23
|
+
* consumer-side function (`Record<TaskShape, string>` today,
|
|
24
|
+
* potentially a learned function in the future) that branches on
|
|
25
|
+
* it. Distinguishing role (registry-shape) from policy
|
|
26
|
+
* (function-shape) avoids the conflation the codebase corrected
|
|
27
|
+
* for `Provider → InferenceHost`.
|
|
28
|
+
*
|
|
29
|
+
* **Lifted from `services/proxy/src/validation.ts`** (commit
|
|
30
|
+
* 95e3b7af's intelligence-source-agility refactor anticipated this
|
|
31
|
+
* landing site — the three unions `InferenceHost`, `ModelLab`,
|
|
32
|
+
* `Jurisdiction` were always destined for the protocol layer once
|
|
33
|
+
* a second consumer arrived):
|
|
34
|
+
* - `InferenceHost` — where the HTTP request actually goes.
|
|
35
|
+
* - `ModelLab` — who trained the weights.
|
|
36
|
+
* - `Jurisdiction` — legal locus of the host.
|
|
37
|
+
*
|
|
38
|
+
* Permissive floor, type-only, zero runtime deps. The dispatcher's
|
|
39
|
+
* judgment lives in `@motebit/policy`; this file stays pure types
|
|
40
|
+
* + closed-registry constants.
|
|
41
|
+
*/
|
|
42
|
+
import type { SensitivityLevel } from "./index.js";
|
|
43
|
+
/**
|
|
44
|
+
* Where the HTTP request actually goes. The processor that receives
|
|
45
|
+
* the prompt bytes. Anthropic/OpenAI/Google appear here because they
|
|
46
|
+
* run their own hosted inference; Groq appears here because they
|
|
47
|
+
* host other labs' open-source weights on LPU hardware. `local-server`
|
|
48
|
+
* is the on-device case: the request goes to the user's own
|
|
49
|
+
* inference server (Ollama, LM Studio, llama.cpp, Jan, vLLM,
|
|
50
|
+
* text-generation-webui — all expose `/v1/chat/completions` via
|
|
51
|
+
* the OpenAI-compat shim), so the "host" is the user's own
|
|
52
|
+
* machine. Mirrors the `OnDeviceBackend` value of the same name
|
|
53
|
+
* in `@motebit/sdk`.
|
|
54
|
+
*
|
|
55
|
+
* The proxy NEVER routes to `local-server` — it's the on-device
|
|
56
|
+
* consumer's host. The proxy's exhaustive switches throw
|
|
57
|
+
* defensively when they encounter this value, naming the
|
|
58
|
+
* structural violation rather than silently degrading. Doctrine:
|
|
59
|
+
* `docs/doctrine/auto-routing-as-protocol-primitive.md` § "PR 3 —
|
|
60
|
+
* on-device consumer".
|
|
61
|
+
*
|
|
62
|
+
* Closed registry — adding a host is a protocol-level append +
|
|
63
|
+
* `MOTEBIT_CLOUD_ALLOWED_JURISDICTIONS` admission decision +
|
|
64
|
+
* downstream consumer updates.
|
|
65
|
+
*/
|
|
66
|
+
export type InferenceHost = "anthropic" | "openai" | "google" | "groq" | "local-server";
|
|
67
|
+
/**
|
|
68
|
+
* Who trained the weights. Anthropic/OpenAI/Google appear here
|
|
69
|
+
* because they trained Claude/GPT/Gemini respectively; Meta appears
|
|
70
|
+
* here because Llama 3.3 70B is Meta's model (Groq just hosts it).
|
|
71
|
+
* OpenAI appears in BOTH this union AND `InferenceHost` (host =
|
|
72
|
+
* "openai" for gpt-5.4 at api.openai.com; lab = "openai" for
|
|
73
|
+
* gpt-oss-120b released as open weights and hosted by Groq). That's
|
|
74
|
+
* structurally correct — same entity can serve different roles.
|
|
75
|
+
*
|
|
76
|
+
* Mistral / Microsoft / Alibaba added 2026-05-14 alongside the PR 3
|
|
77
|
+
* on-device consumer landing: Mistral AI trains Mistral models,
|
|
78
|
+
* Microsoft trains Phi, Alibaba trains Qwen. All three appear as
|
|
79
|
+
* `lab` in the `ON_DEVICE_MODEL_CATALOG` (`@motebit/policy/on-device-router.ts`)
|
|
80
|
+
* since the canonical local-server suggested-models list
|
|
81
|
+
* (`@motebit/sdk::LOCAL_SERVER_SUGGESTED_MODELS`) includes Mistral,
|
|
82
|
+
* Phi-3, and Qwen2 alongside the existing Meta/Google entries. The
|
|
83
|
+
* proxy never sees these labs (it doesn't host their models); the
|
|
84
|
+
* registry expansion is purely consumer-side (the on-device
|
|
85
|
+
* dispatcher's catalog), which is why the registry's stated semantic
|
|
86
|
+
* "who trained the weights" generalizes cleanly without protocol-
|
|
87
|
+
* layer churn.
|
|
88
|
+
*
|
|
89
|
+
* Closed registry — adding a lab requires a model entry citing it.
|
|
90
|
+
*/
|
|
91
|
+
export type ModelLab = "anthropic" | "openai" | "google" | "meta" | "mistral" | "microsoft" | "alibaba";
|
|
92
|
+
/**
|
|
93
|
+
* Legal locus of the host. Reflective of physical/legal reality,
|
|
94
|
+
* not pluggable. Drives the motebit-cloud admission predicate
|
|
95
|
+
* (`MOTEBIT_CLOUD_ALLOWED_JURISDICTIONS` in
|
|
96
|
+
* `services/proxy/src/validation.ts`). You can't swap a host's
|
|
97
|
+
* jurisdiction; the registry reflects legal reality.
|
|
98
|
+
*
|
|
99
|
+
* NOT an agility-as-role instance — it's a typed admission
|
|
100
|
+
* predicate, not a swappable role. Per
|
|
101
|
+
* [`docs/doctrine/agility-as-role.md`], jurisdiction lifts the
|
|
102
|
+
* previously-tribal "DeepSeek-is-BYOK-only-because-Chinese-hosted"
|
|
103
|
+
* decision into structural enforcement.
|
|
104
|
+
*/
|
|
105
|
+
export type Jurisdiction = "US" | "CN" | "EU";
|
|
106
|
+
/**
|
|
107
|
+
* The closed set of task categories the auto-router branches on.
|
|
108
|
+
* Each task shape maps to a preferred model via
|
|
109
|
+
* `REFERENCE_ROUTING_POLICY` (in `@motebit/policy`); consumers
|
|
110
|
+
* (motebit-cloud / BYOK / on-device) override the policy as
|
|
111
|
+
* needed but the shape registry is interop law.
|
|
112
|
+
*
|
|
113
|
+
* Lifted verbatim from `services/proxy/src/validation.ts`'s
|
|
114
|
+
* `TASK_MODEL_MAP` keys (the seven task types the proxy's
|
|
115
|
+
* classifyTask-based router already produces in production).
|
|
116
|
+
*
|
|
117
|
+
* Adding a shape (e.g., `"voice-conversation"`, `"image-generation"`)
|
|
118
|
+
* is intentional protocol-level work: new entry here + new arm in
|
|
119
|
+
* `REFERENCE_ROUTING_POLICY` + drift-gate-induced coverage in
|
|
120
|
+
* every CONSUMER (motebit-cloud proxy + BYOK + on-device). The
|
|
121
|
+
* TaskShape registry is what's role-shaped; the routing-policy
|
|
122
|
+
* itself is a consumer-side function, not a role.
|
|
123
|
+
*/
|
|
124
|
+
export type TaskShape = "quick" | "chat" | "reasoning" | "code" | "research" | "creative" | "math";
|
|
125
|
+
/** Fast / low-latency tasks (tool-heavy, short responses, sub-second feel). */
|
|
126
|
+
export declare const QUICK_TASK_SHAPE: TaskShape;
|
|
127
|
+
/** Conversational back-and-forth — the default. */
|
|
128
|
+
export declare const CHAT_TASK_SHAPE: TaskShape;
|
|
129
|
+
/** Deep reasoning — chain-of-thought, multi-step inference. */
|
|
130
|
+
export declare const REASONING_TASK_SHAPE: TaskShape;
|
|
131
|
+
/** Code-related — completion, review, debugging. */
|
|
132
|
+
export declare const CODE_TASK_SHAPE: TaskShape;
|
|
133
|
+
/** Research / long-context — synthesis across many sources. */
|
|
134
|
+
export declare const RESEARCH_TASK_SHAPE: TaskShape;
|
|
135
|
+
/** Creative writing — open-ended generation, voice, prose. */
|
|
136
|
+
export declare const CREATIVE_TASK_SHAPE: TaskShape;
|
|
137
|
+
/** Math / scientific — symbolic reasoning, calculation, proofs. */
|
|
138
|
+
export declare const MATH_TASK_SHAPE: TaskShape;
|
|
139
|
+
/**
|
|
140
|
+
* Canonical iteration order, frozen. Consumers that need to
|
|
141
|
+
* enumerate (drift gates, REFERENCE_ROUTING_POLICY validation,
|
|
142
|
+
* docs) use this so TypeScript sees the narrow union rather than
|
|
143
|
+
* `string[]`.
|
|
144
|
+
*/
|
|
145
|
+
export declare const ALL_TASK_SHAPES: readonly TaskShape[];
|
|
146
|
+
/**
|
|
147
|
+
* Type guard — narrows `unknown` to `TaskShape`. Drift-gate-driven
|
|
148
|
+
* literal scanners use this to validate shapes; consumers that
|
|
149
|
+
* detect task shape from user intent (LLM classification,
|
|
150
|
+
* heuristics) call this before dispatching so an unchecked cast
|
|
151
|
+
* is a fail-open path the type system can't catch.
|
|
152
|
+
*/
|
|
153
|
+
export declare function isTaskShape(value: unknown): value is TaskShape;
|
|
154
|
+
/**
|
|
155
|
+
* A model's capability profile — what the dispatcher needs to know
|
|
156
|
+
* to pick it. Lifted from `services/proxy/src/validation.ts`'s
|
|
157
|
+
* `ModelEntry` interface; the proxy now declares its
|
|
158
|
+
* `MODEL_CONFIG` entries satisfying `ProviderCapability[]`.
|
|
159
|
+
*
|
|
160
|
+
* Cost units: USD per million tokens. Same precision the proxy's
|
|
161
|
+
* `calculateCostMicro` consumes (input vs output billed
|
|
162
|
+
* separately).
|
|
163
|
+
*/
|
|
164
|
+
export interface ProviderCapability {
|
|
165
|
+
/** Canonical model identifier — opaque to the dispatcher except as a return value. */
|
|
166
|
+
readonly modelName: string;
|
|
167
|
+
/** Where requests route. */
|
|
168
|
+
readonly host: InferenceHost;
|
|
169
|
+
/** Who trained the weights. */
|
|
170
|
+
readonly lab: ModelLab;
|
|
171
|
+
/** Legal locus of the host. */
|
|
172
|
+
readonly jurisdiction: Jurisdiction;
|
|
173
|
+
/** Input price (USD per million tokens). */
|
|
174
|
+
readonly inputCostPerMillion: number;
|
|
175
|
+
/** Output price (USD per million tokens). */
|
|
176
|
+
readonly outputCostPerMillion: number;
|
|
177
|
+
/**
|
|
178
|
+
* Maximum prompt+completion tokens the model will accept in a single
|
|
179
|
+
* call. Optional + additive per
|
|
180
|
+
* [`docs/doctrine/intelligence-pluggability-contract.md`](../../../docs/doctrine/intelligence-pluggability-contract.md) —
|
|
181
|
+
* consumers performing pre-flight admission (system-prompt + tools +
|
|
182
|
+
* rendered state + user message + output reserve ≤ window) read this
|
|
183
|
+
* to decide whether to deny honestly before invoking the model.
|
|
184
|
+
* Auto-routing dispatch does not consume this field today; admission
|
|
185
|
+
* is a sibling deny semantic to auto-router deny ("I can't pick"
|
|
186
|
+
* vs "the picked model can't carry").
|
|
187
|
+
*/
|
|
188
|
+
readonly contextWindowTokens?: number;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Consumer-neutral constraints the dispatcher honors. **No
|
|
192
|
+
* motebit-cloud-specific fields** — balance-based filtering lives
|
|
193
|
+
* in `@motebit/policy::applyBalanceFilter` (a higher-order wrapper
|
|
194
|
+
* the proxy uses); BYOK and on-device consumers don't have balance
|
|
195
|
+
* and shouldn't see it in the protocol-layer constraint type.
|
|
196
|
+
*
|
|
197
|
+
* All fields optional — an empty constraint means "any
|
|
198
|
+
* jurisdiction, any cost, any capability." The dispatcher returns
|
|
199
|
+
* `{ kind: "deny", reason }` when constraints make every catalog
|
|
200
|
+
* entry ineligible.
|
|
201
|
+
*/
|
|
202
|
+
export interface RoutingConstraint {
|
|
203
|
+
/**
|
|
204
|
+
* Restrict to this jurisdiction. Useful for compliance-bound
|
|
205
|
+
* tasks ("US-only routing") and the motebit-cloud admission
|
|
206
|
+
* predicate. Omit for "any jurisdiction the catalog offers."
|
|
207
|
+
*/
|
|
208
|
+
readonly jurisdiction?: Jurisdiction;
|
|
209
|
+
/**
|
|
210
|
+
* Maximum acceptable input cost in USD per million tokens.
|
|
211
|
+
* Filters the catalog before policy lookup. Useful for
|
|
212
|
+
* cost-aware routing (operator-side budget caps,
|
|
213
|
+
* consumer-side cheap-tier preferences).
|
|
214
|
+
*/
|
|
215
|
+
readonly maxInputCostPerMillion?: number;
|
|
216
|
+
/** Maximum acceptable output cost in USD per million tokens. */
|
|
217
|
+
readonly maxOutputCostPerMillion?: number;
|
|
218
|
+
/**
|
|
219
|
+
* Task requires tool-calling capability. When true, providers
|
|
220
|
+
* known not to support tools are excluded. Today the dispatcher
|
|
221
|
+
* treats all entries as tool-capable; this field is shipped for
|
|
222
|
+
* future capability-aware filtering when a provider that lacks
|
|
223
|
+
* tool support lands.
|
|
224
|
+
*/
|
|
225
|
+
readonly requiresToolUse?: boolean;
|
|
226
|
+
/**
|
|
227
|
+
* Maximum acceptable sensitivity tier the routing target can
|
|
228
|
+
* handle. Sensitivity-elevated tasks (medical / financial /
|
|
229
|
+
* secret) MUST stay on sovereign or on-device routes — the
|
|
230
|
+
* dispatcher's caller is responsible for pre-filtering the
|
|
231
|
+
* catalog accordingly; this field documents the contract.
|
|
232
|
+
*/
|
|
233
|
+
readonly sensitivityCeiling?: SensitivityLevel;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* The dispatcher's typed output. Discriminated union — consumers
|
|
237
|
+
* pattern-match on `kind`:
|
|
238
|
+
*
|
|
239
|
+
* - `route`: a single provider was chosen. The caller invokes
|
|
240
|
+
* it directly.
|
|
241
|
+
* - `fallback`: a primary was preferred but cost / constraint
|
|
242
|
+
* forced a backup. The caller invokes `backup`; the `primary`
|
|
243
|
+
* and `reason` fields are observability surfaces (audit logs,
|
|
244
|
+
* chrome narration in PR 4+).
|
|
245
|
+
* - `deny`: no catalog entry satisfies the constraints. The
|
|
246
|
+
* caller is responsible for surfacing the denial (HTTP 4xx,
|
|
247
|
+
* UI message, etc.).
|
|
248
|
+
*
|
|
249
|
+
* Every variant carries `reason` for observability — the
|
|
250
|
+
* dispatcher's choice should always be human-legible, even when
|
|
251
|
+
* the choice is "I couldn't pick anything."
|
|
252
|
+
*/
|
|
253
|
+
export type RoutingDecision = {
|
|
254
|
+
readonly kind: "route";
|
|
255
|
+
readonly model: string;
|
|
256
|
+
readonly reason: string;
|
|
257
|
+
} | {
|
|
258
|
+
readonly kind: "fallback";
|
|
259
|
+
readonly primary: string;
|
|
260
|
+
readonly backup: string;
|
|
261
|
+
readonly reason: string;
|
|
262
|
+
} | {
|
|
263
|
+
readonly kind: "deny";
|
|
264
|
+
readonly reason: string;
|
|
265
|
+
};
|
|
266
|
+
//# sourceMappingURL=routing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"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"}
|
package/dist/routing.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routing primitive — closed-registry types for the auto-router.
|
|
3
|
+
*
|
|
4
|
+
* The auto-router is the model-selection counterpart to the chrome
|
|
5
|
+
* matrix: `f(TaskShape × ProviderCapability × Constraints) →
|
|
6
|
+
* RoutingDecision`. This module defines the wire-shape types; the
|
|
7
|
+
* judgment-layer dispatcher (`dispatchRouting`) lives in BSL
|
|
8
|
+
* `@motebit/policy/src/auto-router.ts`. Consumers (motebit-cloud
|
|
9
|
+
* proxy, BYOK web layer, on-device runtime) call the dispatcher
|
|
10
|
+
* with their own provider catalogs.
|
|
11
|
+
*
|
|
12
|
+
* **Closed registry shape** — same closure pattern as `SuiteId`,
|
|
13
|
+
* `TokenAudience`, `ToolMode`, `ContentArtifactType`. The `TaskShape`
|
|
14
|
+
* literal union is the wire law; named constants are developer
|
|
15
|
+
* ergonomics; `ALL_TASK_SHAPES` is the canonical iteration order.
|
|
16
|
+
* Adding a task shape is intentional protocol-level work: a new
|
|
17
|
+
* entry here, a new arm in `REFERENCE_ROUTING_POLICY`, drift-gate
|
|
18
|
+
* coverage on every consumer.
|
|
19
|
+
*
|
|
20
|
+
* **TaskShape agility — the 7th instance of agility-as-role.**
|
|
21
|
+
* Per [`docs/doctrine/agility-as-role.md`], `TaskShape` is the
|
|
22
|
+
* closed registry (the role); the routing-policy itself is a
|
|
23
|
+
* consumer-side function (`Record<TaskShape, string>` today,
|
|
24
|
+
* potentially a learned function in the future) that branches on
|
|
25
|
+
* it. Distinguishing role (registry-shape) from policy
|
|
26
|
+
* (function-shape) avoids the conflation the codebase corrected
|
|
27
|
+
* for `Provider → InferenceHost`.
|
|
28
|
+
*
|
|
29
|
+
* **Lifted from `services/proxy/src/validation.ts`** (commit
|
|
30
|
+
* 95e3b7af's intelligence-source-agility refactor anticipated this
|
|
31
|
+
* landing site — the three unions `InferenceHost`, `ModelLab`,
|
|
32
|
+
* `Jurisdiction` were always destined for the protocol layer once
|
|
33
|
+
* a second consumer arrived):
|
|
34
|
+
* - `InferenceHost` — where the HTTP request actually goes.
|
|
35
|
+
* - `ModelLab` — who trained the weights.
|
|
36
|
+
* - `Jurisdiction` — legal locus of the host.
|
|
37
|
+
*
|
|
38
|
+
* Permissive floor, type-only, zero runtime deps. The dispatcher's
|
|
39
|
+
* judgment lives in `@motebit/policy`; this file stays pure types
|
|
40
|
+
* + closed-registry constants.
|
|
41
|
+
*/
|
|
42
|
+
// === Named constants — same value, narrower type ============================
|
|
43
|
+
//
|
|
44
|
+
// Callers that import these get `TaskShape` typing without the union
|
|
45
|
+
// being inferred at every site. Two ergonomic shapes: pass a constant
|
|
46
|
+
// (`QUICK_TASK_SHAPE`) for documentation + grep affordance, or inline
|
|
47
|
+
// the literal — the union narrowing catches typos in either case.
|
|
48
|
+
/** Fast / low-latency tasks (tool-heavy, short responses, sub-second feel). */
|
|
49
|
+
export const QUICK_TASK_SHAPE = "quick";
|
|
50
|
+
/** Conversational back-and-forth — the default. */
|
|
51
|
+
export const CHAT_TASK_SHAPE = "chat";
|
|
52
|
+
/** Deep reasoning — chain-of-thought, multi-step inference. */
|
|
53
|
+
export const REASONING_TASK_SHAPE = "reasoning";
|
|
54
|
+
/** Code-related — completion, review, debugging. */
|
|
55
|
+
export const CODE_TASK_SHAPE = "code";
|
|
56
|
+
/** Research / long-context — synthesis across many sources. */
|
|
57
|
+
export const RESEARCH_TASK_SHAPE = "research";
|
|
58
|
+
/** Creative writing — open-ended generation, voice, prose. */
|
|
59
|
+
export const CREATIVE_TASK_SHAPE = "creative";
|
|
60
|
+
/** Math / scientific — symbolic reasoning, calculation, proofs. */
|
|
61
|
+
export const MATH_TASK_SHAPE = "math";
|
|
62
|
+
// === Iteration + type guard =================================================
|
|
63
|
+
/**
|
|
64
|
+
* Canonical iteration order, frozen. Consumers that need to
|
|
65
|
+
* enumerate (drift gates, REFERENCE_ROUTING_POLICY validation,
|
|
66
|
+
* docs) use this so TypeScript sees the narrow union rather than
|
|
67
|
+
* `string[]`.
|
|
68
|
+
*/
|
|
69
|
+
export const ALL_TASK_SHAPES = Object.freeze([
|
|
70
|
+
"quick",
|
|
71
|
+
"chat",
|
|
72
|
+
"reasoning",
|
|
73
|
+
"code",
|
|
74
|
+
"research",
|
|
75
|
+
"creative",
|
|
76
|
+
"math",
|
|
77
|
+
]);
|
|
78
|
+
/**
|
|
79
|
+
* Type guard — narrows `unknown` to `TaskShape`. Drift-gate-driven
|
|
80
|
+
* literal scanners use this to validate shapes; consumers that
|
|
81
|
+
* detect task shape from user intent (LLM classification,
|
|
82
|
+
* heuristics) call this before dispatching so an unchecked cast
|
|
83
|
+
* is a fail-open path the type system can't catch.
|
|
84
|
+
*/
|
|
85
|
+
export function isTaskShape(value) {
|
|
86
|
+
return typeof value === "string" && ALL_TASK_SHAPES.includes(value);
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.js","sourceRoot":"","sources":["../src/routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAqGH,+EAA+E;AAC/E,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,sEAAsE;AACtE,kEAAkE;AAElE,+EAA+E;AAC/E,MAAM,CAAC,MAAM,gBAAgB,GAAc,OAAO,CAAC;AAEnD,mDAAmD;AACnD,MAAM,CAAC,MAAM,eAAe,GAAc,MAAM,CAAC;AAEjD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAc,WAAW,CAAC;AAE3D,oDAAoD;AACpD,MAAM,CAAC,MAAM,eAAe,GAAc,MAAM,CAAC;AAEjD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,mBAAmB,GAAc,UAAU,CAAC;AAEzD,8DAA8D;AAC9D,MAAM,CAAC,MAAM,mBAAmB,GAAc,UAAU,CAAC;AAEzD,mEAAmE;AACnE,MAAM,CAAC,MAAM,eAAe,GAAc,MAAM,CAAC;AAEjD,+EAA+E;AAE/E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAAyB,MAAM,CAAC,MAAM,CAAC;IACjE,OAAO;IACP,MAAM;IACN,WAAW;IACX,MAAM;IACN,UAAU;IACV,UAAU;IACV,MAAM;CACP,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,eAAqC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC7F,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sensitivity ladder algebra — pure math over the closed
|
|
3
|
+
* `SensitivityLevel` enum.
|
|
4
|
+
*
|
|
5
|
+
* The ladder is interop law. Every motebit implementation must agree
|
|
6
|
+
* on which tier dominates which, or the cross-implementation gate
|
|
7
|
+
* isn't interoperable: device A persisting a turn at "secret" must
|
|
8
|
+
* mean the same thing to device B's session-tier filter.
|
|
9
|
+
*
|
|
10
|
+
* Pure deterministic math over a closed enum — qualifies as a
|
|
11
|
+
* permissive-floor primitive per `packages/protocol/CLAUDE.md` rule 1
|
|
12
|
+
* ("deterministic math (semiring algebra, canonical JSON, hash
|
|
13
|
+
* primitives)"). The functions don't decide policy; they compose
|
|
14
|
+
* ordered values. Policy thresholds (e.g. "medical+ requires
|
|
15
|
+
* sovereign provider") live at the call site so call sites express
|
|
16
|
+
* intent at the right level.
|
|
17
|
+
*
|
|
18
|
+
* Graduation history: `rankSensitivity` had three local definitions
|
|
19
|
+
* by 2026-05-07 (runtime/motebit-runtime.ts, runtime/conversation.ts,
|
|
20
|
+
* ai-core/loop.ts) plus a fourth-shaped table (`LEVEL_RANK` +
|
|
21
|
+
* `higherLevel` in policy-invariants/computer-sensitivity.ts). The
|
|
22
|
+
* ai-core copy's JSDoc explicitly named graduation as the trigger:
|
|
23
|
+
* "if a third reader appears, the helper graduates." Past trigger.
|
|
24
|
+
*
|
|
25
|
+
* Naming distinction:
|
|
26
|
+
* - `rankSensitivity` — load-bearing primitive; ordinal int over the
|
|
27
|
+
* closed union. Comparable, hashable, monotonic.
|
|
28
|
+
* - `maxSensitivity` — typed wrapper for the join-semilattice
|
|
29
|
+
* composition (`max(a, b)`). Identity element is `None`. Used at
|
|
30
|
+
* every egress write boundary that floors message tier at
|
|
31
|
+
* `max(default, effective)`.
|
|
32
|
+
* - `sensitivityPermits` — typed wrapper for the read-side filter
|
|
33
|
+
* (`candidate <= upper`). Used at every egress READ boundary that
|
|
34
|
+
* excludes content tagged above the current effective tier.
|
|
35
|
+
*
|
|
36
|
+
* Not a semiring. There's only one operation (max-monoid / join-
|
|
37
|
+
* semilattice). Calling it a semiring would be a category error.
|
|
38
|
+
*/
|
|
39
|
+
import type { SensitivityLevel } from "./index.js";
|
|
40
|
+
/**
|
|
41
|
+
* Ordinal rank for a `SensitivityLevel`. Returns 0 (`None`) through
|
|
42
|
+
* 4 (`Secret`) — see `SENSITIVITY_RANK` above. Use this as the
|
|
43
|
+
* comparison primitive; prefer `maxSensitivity` / `sensitivityPermits`
|
|
44
|
+
* at call sites that compose or filter.
|
|
45
|
+
*/
|
|
46
|
+
export declare function rankSensitivity(level: SensitivityLevel): number;
|
|
47
|
+
/**
|
|
48
|
+
* Compose two sensitivity tiers: returns whichever has the higher
|
|
49
|
+
* rank. The join-semilattice composition that the egress-write floor
|
|
50
|
+
* arc depends on at every boundary (session × slab, default ×
|
|
51
|
+
* effective, persisted-tier × runtime-tier). Identity is `None`.
|
|
52
|
+
*
|
|
53
|
+
* Property: `maxSensitivity(a, None) === a` for all `a`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function maxSensitivity(a: SensitivityLevel, b: SensitivityLevel): SensitivityLevel;
|
|
56
|
+
/**
|
|
57
|
+
* Does the upper tier permit content tagged at `candidate`? Returns
|
|
58
|
+
* `true` iff `candidate <= upper` in the ladder. Used at every
|
|
59
|
+
* egress READ boundary (trimmed conversation history, memory-
|
|
60
|
+
* candidate filter at AI-context construction, future cross-device-
|
|
61
|
+
* sync filters).
|
|
62
|
+
*
|
|
63
|
+
* The dual of `maxSensitivity`: write-side floor stamps with
|
|
64
|
+
* `maxSensitivity`, read-side filter excludes via
|
|
65
|
+
* `!sensitivityPermits`. Both routes derive from the same single
|
|
66
|
+
* source of truth (`SENSITIVITY_RANK`), so a tier insertion remains
|
|
67
|
+
* a one-file change at the protocol layer.
|
|
68
|
+
*
|
|
69
|
+
* Property: `sensitivityPermits(upper, None) === true` for all
|
|
70
|
+
* `upper` (None content is admissible at every tier).
|
|
71
|
+
*/
|
|
72
|
+
export declare function sensitivityPermits(upper: SensitivityLevel, candidate: SensitivityLevel): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Canonical iteration order over `SensitivityLevel`, frozen. The
|
|
75
|
+
* single source of truth for "every level" — drift gates,
|
|
76
|
+
* consumer-coverage scans, exhaustive switches, and the protocol's
|
|
77
|
+
* registry-coverage gate (`check-sensitivity-canonical`) all
|
|
78
|
+
* enumerate through this array.
|
|
79
|
+
*
|
|
80
|
+
* Ordered low → high to mirror `SENSITIVITY_RANK`: a consumer
|
|
81
|
+
* iterating in declaration order sees the ladder in the same order
|
|
82
|
+
* the algebra ranks it. Same shape as `ALL_SUITE_IDS`,
|
|
83
|
+
* `ALL_TOKEN_AUDIENCES`, `ALL_CONTENT_ARTIFACT_TYPES`,
|
|
84
|
+
* `ALL_TASK_SHAPES`. Adding a level is intentional protocol-level
|
|
85
|
+
* work: new enum member + new entry here + new entry in
|
|
86
|
+
* `SENSITIVITY_RANK` + drift-gate update.
|
|
87
|
+
*
|
|
88
|
+
* Values are the enum's string literals (not enum members) to avoid
|
|
89
|
+
* the init-order cycle the file's `import type` already documents.
|
|
90
|
+
*/
|
|
91
|
+
export declare const ALL_SENSITIVITY_LEVELS: readonly SensitivityLevel[];
|
|
92
|
+
/**
|
|
93
|
+
* Type guard — narrows `unknown` to `SensitivityLevel`. Drift-gate-
|
|
94
|
+
* driven literal scanners use this to validate values pulled from
|
|
95
|
+
* wire-format payloads; consumers that derive sensitivity from
|
|
96
|
+
* user input call this before dispatching so an unchecked cast is
|
|
97
|
+
* a fail-open path the type system can't catch.
|
|
98
|
+
*
|
|
99
|
+
* Same shape as `isSuiteId`, `isTokenAudience`,
|
|
100
|
+
* `isContentArtifactType`, `isTaskShape`.
|
|
101
|
+
*/
|
|
102
|
+
export declare function isSensitivityLevel(value: unknown): value is SensitivityLevel;
|
|
103
|
+
declare const __sensitivityCleared: unique symbol;
|
|
104
|
+
/**
|
|
105
|
+
* Precondition brand: `T` carrying the type-level proof that
|
|
106
|
+
* `assertSensitivityPermitsAiCall()` fired before the value left
|
|
107
|
+
* the gate.
|
|
108
|
+
*
|
|
109
|
+
* Produced only inside the runtime's gate method (the single
|
|
110
|
+
* authorized `as SensitivityCleared<T>` cast). Required as the
|
|
111
|
+
* deps parameter on `runTurn` / `runTurnStreaming`. Propagates
|
|
112
|
+
* through every indirect AI-egress path (`StreamingManager` resume,
|
|
113
|
+
* `PlanEngine` per-step) so the brand is the type-level proof a
|
|
114
|
+
* sensitivity check happened at the right moment.
|
|
115
|
+
*
|
|
116
|
+
* Doctrine: `docs/doctrine/security-boundaries.md` (privacy gate),
|
|
117
|
+
* CLAUDE.md ("Medical/financial/secret never reach external AI").
|
|
118
|
+
*/
|
|
119
|
+
export type SensitivityCleared<T> = T & {
|
|
120
|
+
readonly [__sensitivityCleared]: true;
|
|
121
|
+
};
|
|
122
|
+
export {};
|
|
123
|
+
//# sourceMappingURL=sensitivity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensitivity.d.ts","sourceRoot":"","sources":["../src/sensitivity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAsBnD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAE/D;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,CAEzF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,gBAAgB,GAAG,OAAO,CAEhG;AAsBD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,gBAAgB,EAMtC,CAAC;AAEzB;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AA4BD,OAAO,CAAC,MAAM,oBAAoB,EAAE,OAAO,MAAM,CAAC;AAElD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,QAAQ,CAAC,CAAC,oBAAoB,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sensitivity ladder algebra — pure math over the closed
|
|
3
|
+
* `SensitivityLevel` enum.
|
|
4
|
+
*
|
|
5
|
+
* The ladder is interop law. Every motebit implementation must agree
|
|
6
|
+
* on which tier dominates which, or the cross-implementation gate
|
|
7
|
+
* isn't interoperable: device A persisting a turn at "secret" must
|
|
8
|
+
* mean the same thing to device B's session-tier filter.
|
|
9
|
+
*
|
|
10
|
+
* Pure deterministic math over a closed enum — qualifies as a
|
|
11
|
+
* permissive-floor primitive per `packages/protocol/CLAUDE.md` rule 1
|
|
12
|
+
* ("deterministic math (semiring algebra, canonical JSON, hash
|
|
13
|
+
* primitives)"). The functions don't decide policy; they compose
|
|
14
|
+
* ordered values. Policy thresholds (e.g. "medical+ requires
|
|
15
|
+
* sovereign provider") live at the call site so call sites express
|
|
16
|
+
* intent at the right level.
|
|
17
|
+
*
|
|
18
|
+
* Graduation history: `rankSensitivity` had three local definitions
|
|
19
|
+
* by 2026-05-07 (runtime/motebit-runtime.ts, runtime/conversation.ts,
|
|
20
|
+
* ai-core/loop.ts) plus a fourth-shaped table (`LEVEL_RANK` +
|
|
21
|
+
* `higherLevel` in policy-invariants/computer-sensitivity.ts). The
|
|
22
|
+
* ai-core copy's JSDoc explicitly named graduation as the trigger:
|
|
23
|
+
* "if a third reader appears, the helper graduates." Past trigger.
|
|
24
|
+
*
|
|
25
|
+
* Naming distinction:
|
|
26
|
+
* - `rankSensitivity` — load-bearing primitive; ordinal int over the
|
|
27
|
+
* closed union. Comparable, hashable, monotonic.
|
|
28
|
+
* - `maxSensitivity` — typed wrapper for the join-semilattice
|
|
29
|
+
* composition (`max(a, b)`). Identity element is `None`. Used at
|
|
30
|
+
* every egress write boundary that floors message tier at
|
|
31
|
+
* `max(default, effective)`.
|
|
32
|
+
* - `sensitivityPermits` — typed wrapper for the read-side filter
|
|
33
|
+
* (`candidate <= upper`). Used at every egress READ boundary that
|
|
34
|
+
* excludes content tagged above the current effective tier.
|
|
35
|
+
*
|
|
36
|
+
* Not a semiring. There's only one operation (max-monoid / join-
|
|
37
|
+
* semilattice). Calling it a semiring would be a category error.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Ordinal rank for `SensitivityLevel`: `none(0) < personal(1) <
|
|
41
|
+
* medical(2) < financial(3) < secret(4)`. The single source of truth
|
|
42
|
+
* for the ladder ordering — every consumer must derive comparison
|
|
43
|
+
* decisions from this rank, not from local enum-equality chains
|
|
44
|
+
* (`x === Medical || x === Financial || x === Secret`), so a future
|
|
45
|
+
* tier insertion remains a one-file change at the protocol layer.
|
|
46
|
+
*
|
|
47
|
+
* Keys are the enum's string values (not enum members) to avoid the
|
|
48
|
+
* init-order cycle described above. The `Record<SensitivityLevel,
|
|
49
|
+
* number>` type still binds the keys to the enum at the type layer.
|
|
50
|
+
*/
|
|
51
|
+
const SENSITIVITY_RANK = Object.freeze({
|
|
52
|
+
none: 0,
|
|
53
|
+
personal: 1,
|
|
54
|
+
medical: 2,
|
|
55
|
+
financial: 3,
|
|
56
|
+
secret: 4,
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* Ordinal rank for a `SensitivityLevel`. Returns 0 (`None`) through
|
|
60
|
+
* 4 (`Secret`) — see `SENSITIVITY_RANK` above. Use this as the
|
|
61
|
+
* comparison primitive; prefer `maxSensitivity` / `sensitivityPermits`
|
|
62
|
+
* at call sites that compose or filter.
|
|
63
|
+
*/
|
|
64
|
+
export function rankSensitivity(level) {
|
|
65
|
+
return SENSITIVITY_RANK[level];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Compose two sensitivity tiers: returns whichever has the higher
|
|
69
|
+
* rank. The join-semilattice composition that the egress-write floor
|
|
70
|
+
* arc depends on at every boundary (session × slab, default ×
|
|
71
|
+
* effective, persisted-tier × runtime-tier). Identity is `None`.
|
|
72
|
+
*
|
|
73
|
+
* Property: `maxSensitivity(a, None) === a` for all `a`.
|
|
74
|
+
*/
|
|
75
|
+
export function maxSensitivity(a, b) {
|
|
76
|
+
return rankSensitivity(a) >= rankSensitivity(b) ? a : b;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Does the upper tier permit content tagged at `candidate`? Returns
|
|
80
|
+
* `true` iff `candidate <= upper` in the ladder. Used at every
|
|
81
|
+
* egress READ boundary (trimmed conversation history, memory-
|
|
82
|
+
* candidate filter at AI-context construction, future cross-device-
|
|
83
|
+
* sync filters).
|
|
84
|
+
*
|
|
85
|
+
* The dual of `maxSensitivity`: write-side floor stamps with
|
|
86
|
+
* `maxSensitivity`, read-side filter excludes via
|
|
87
|
+
* `!sensitivityPermits`. Both routes derive from the same single
|
|
88
|
+
* source of truth (`SENSITIVITY_RANK`), so a tier insertion remains
|
|
89
|
+
* a one-file change at the protocol layer.
|
|
90
|
+
*
|
|
91
|
+
* Property: `sensitivityPermits(upper, None) === true` for all
|
|
92
|
+
* `upper` (None content is admissible at every tier).
|
|
93
|
+
*/
|
|
94
|
+
export function sensitivityPermits(upper, candidate) {
|
|
95
|
+
return rankSensitivity(candidate) <= rankSensitivity(upper);
|
|
96
|
+
}
|
|
97
|
+
// ── Canonical registry tooling ─────────────────────────────────────
|
|
98
|
+
//
|
|
99
|
+
// Closed-registry / structural-lock shape. Same five artifacts as
|
|
100
|
+
// `SuiteId` (`crypto-suite.ts`), `TokenAudience` (`audience.ts`),
|
|
101
|
+
// `ContentArtifactType` (`artifact-type.ts`), `TaskShape`
|
|
102
|
+
// (`routing.ts`):
|
|
103
|
+
//
|
|
104
|
+
// 1. closed type (the `SensitivityLevel` enum in `index.ts`)
|
|
105
|
+
// 2. canonical ordering (`SENSITIVITY_RANK` above)
|
|
106
|
+
// 3. frozen iteration array (`ALL_SENSITIVITY_LEVELS` below)
|
|
107
|
+
// 4. type guard (`isSensitivityLevel` below)
|
|
108
|
+
// 5. drift gate (`check-sensitivity-canonical` per `scripts/`)
|
|
109
|
+
//
|
|
110
|
+
// Pre-this-block, `SensitivityLevel` was the only top-tier closed
|
|
111
|
+
// registry without the iteration + guard pair — the gap surfaced in
|
|
112
|
+
// the registry-gate-family audit on 2026-05-14 (post panels-registry
|
|
113
|
+
// arc). The enum is preserved for back-compat with the ~900
|
|
114
|
+
// pre-existing literal sites; this block adds the missing canonical
|
|
115
|
+
// tooling next to it without converting the enum.
|
|
116
|
+
/**
|
|
117
|
+
* Canonical iteration order over `SensitivityLevel`, frozen. The
|
|
118
|
+
* single source of truth for "every level" — drift gates,
|
|
119
|
+
* consumer-coverage scans, exhaustive switches, and the protocol's
|
|
120
|
+
* registry-coverage gate (`check-sensitivity-canonical`) all
|
|
121
|
+
* enumerate through this array.
|
|
122
|
+
*
|
|
123
|
+
* Ordered low → high to mirror `SENSITIVITY_RANK`: a consumer
|
|
124
|
+
* iterating in declaration order sees the ladder in the same order
|
|
125
|
+
* the algebra ranks it. Same shape as `ALL_SUITE_IDS`,
|
|
126
|
+
* `ALL_TOKEN_AUDIENCES`, `ALL_CONTENT_ARTIFACT_TYPES`,
|
|
127
|
+
* `ALL_TASK_SHAPES`. Adding a level is intentional protocol-level
|
|
128
|
+
* work: new enum member + new entry here + new entry in
|
|
129
|
+
* `SENSITIVITY_RANK` + drift-gate update.
|
|
130
|
+
*
|
|
131
|
+
* Values are the enum's string literals (not enum members) to avoid
|
|
132
|
+
* the init-order cycle the file's `import type` already documents.
|
|
133
|
+
*/
|
|
134
|
+
export const ALL_SENSITIVITY_LEVELS = Object.freeze([
|
|
135
|
+
"none",
|
|
136
|
+
"personal",
|
|
137
|
+
"medical",
|
|
138
|
+
"financial",
|
|
139
|
+
"secret",
|
|
140
|
+
]);
|
|
141
|
+
/**
|
|
142
|
+
* Type guard — narrows `unknown` to `SensitivityLevel`. Drift-gate-
|
|
143
|
+
* driven literal scanners use this to validate values pulled from
|
|
144
|
+
* wire-format payloads; consumers that derive sensitivity from
|
|
145
|
+
* user input call this before dispatching so an unchecked cast is
|
|
146
|
+
* a fail-open path the type system can't catch.
|
|
147
|
+
*
|
|
148
|
+
* Same shape as `isSuiteId`, `isTokenAudience`,
|
|
149
|
+
* `isContentArtifactType`, `isTaskShape`.
|
|
150
|
+
*/
|
|
151
|
+
export function isSensitivityLevel(value) {
|
|
152
|
+
return typeof value === "string" && ALL_SENSITIVITY_LEVELS.includes(value);
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=sensitivity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensitivity.js","sourceRoot":"","sources":["../src/sensitivity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AASH;;;;;;;;;;;GAWG;AACH,MAAM,gBAAgB,GAA+C,MAAM,CAAC,MAAM,CAAC;IACjF,IAAI,EAAE,CAAC;IACP,QAAQ,EAAE,CAAC;IACX,OAAO,EAAE,CAAC;IACV,SAAS,EAAE,CAAC;IACZ,MAAM,EAAE,CAAC;CACV,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAuB;IACrD,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,CAAmB,EAAE,CAAmB;IACrE,OAAO,eAAe,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAuB,EAAE,SAA2B;IACrF,OAAO,eAAe,CAAC,SAAS,CAAC,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;AAED,sEAAsE;AACtE,EAAE;AACF,kEAAkE;AAClE,kEAAkE;AAClE,0DAA0D;AAC1D,kBAAkB;AAClB,EAAE;AACF,+DAA+D;AAC/D,qDAAqD;AACrD,+DAA+D;AAC/D,+CAA+C;AAC/C,iEAAiE;AACjE,EAAE;AACF,kEAAkE;AAClE,oEAAoE;AACpE,qEAAqE;AACrE,4DAA4D;AAC5D,oEAAoE;AACpE,kDAAkD;AAElD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAgC,MAAM,CAAC,MAAM,CAAC;IAC/E,MAAM;IACN,UAAU;IACV,SAAS;IACT,WAAW;IACX,QAAQ;CACa,CAAC,CAAC;AAEzB;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,sBAA4C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACpG,CAAC"}
|