theorum 0.1.11 → 0.1.14

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 (51) hide show
  1. package/README.md +102 -2
  2. package/docs/cli.md +97 -0
  3. package/docs/guardrails.md +178 -0
  4. package/docs/host.md +97 -0
  5. package/docs/kernel.md +404 -0
  6. package/docs/observability.md +105 -0
  7. package/docs/openrouter.md +125 -0
  8. package/docs/presets-google.md +91 -0
  9. package/docs/presets.md +88 -0
  10. package/docs/providers.md +201 -0
  11. package/docs/streaming.md +96 -0
  12. package/esm/mod.d.ts +7 -3
  13. package/esm/mod.js +4 -2
  14. package/esm/src/cli/commands/bench.js +2 -4
  15. package/esm/src/cli/commands/fuzz-guardrails.js +195 -48
  16. package/esm/src/guardrails/injection.js +13 -8
  17. package/esm/src/guardrails/normalize.js +65 -38
  18. package/esm/src/guardrails/sensitive.js +1 -1
  19. package/esm/src/kernel/engine/compaction.d.ts +69 -0
  20. package/esm/src/kernel/engine/compaction.js +141 -0
  21. package/esm/src/kernel/engine/delta.js +30 -7
  22. package/esm/src/kernel/engine/history-tokens.d.ts +43 -0
  23. package/esm/src/kernel/engine/history-tokens.js +100 -0
  24. package/esm/src/kernel/engine/runner/mod.js +164 -62
  25. package/esm/src/kernel/engine/runner/state.d.ts +3 -1
  26. package/esm/src/kernel/engine/runner/steps.js +3 -0
  27. package/esm/src/kernel/mod.d.ts +5 -1
  28. package/esm/src/kernel/mod.js +3 -1
  29. package/esm/src/kernel/registry/catalog.d.ts +3 -3
  30. package/esm/src/kernel/registry/catalog.js +5 -5
  31. package/esm/src/kernel/registry/ingress.js +6 -6
  32. package/esm/src/kernel/registry/profiles.js +37 -0
  33. package/esm/src/kernel/stop.d.ts +75 -0
  34. package/esm/src/kernel/stop.js +120 -0
  35. package/esm/src/kernel/types.d.ts +120 -4
  36. package/esm/src/providers/create-provider.d.ts +7 -0
  37. package/esm/src/providers/create-provider.js +24 -4
  38. package/esm/src/providers/expose-for-tests.js +5 -1
  39. package/esm/src/providers/local.d.ts +29 -0
  40. package/esm/src/providers/local.js +259 -0
  41. package/esm/src/providers/mod.d.ts +2 -0
  42. package/esm/src/providers/mod.js +1 -0
  43. package/esm/src/providers/openrouter.js +32 -13
  44. package/esm/src/providers/provider.js +1 -1
  45. package/esm/src/providers/speech.js +1 -1
  46. package/esm/src/streaming/mod.d.ts +3 -1
  47. package/esm/src/streaming/mod.js +2 -1
  48. package/package.json +6 -1
  49. package/docs/AGENT_PROFILE_CONTRACT.md +0 -189
  50. package/docs/CLI_SPEC.md +0 -183
  51. package/docs/SECRETS.md +0 -60
package/README.md CHANGED
@@ -288,6 +288,8 @@ import { createProvider, runTurn } from "jsr:@theorum/core";
288
288
  const provider = createProvider(profile, {
289
289
  gemini: { vault: hostGeminiKeyVault, fetch },
290
290
  openRouter: { apiKey: hostSecrets.openRouterApiKey },
291
+ // openAi + local — optional; default baseUrl http://127.0.0.1:11434
292
+ local: { baseUrl: hostResolvedLocalBaseUrl },
291
293
  });
292
294
 
293
295
  for await (const event of runTurn({ profile: profile.id, input: { text: "…" } }, provider)) {
@@ -302,10 +304,21 @@ for await (const event of runTurn({ profile: profile.id, input: { text: "…" }
302
304
  | `geminiInteractions` + `google` | Google Interactions (chat, image, speech) |
303
305
  | `openAi` + `openrouter` (chat) | OpenRouter chat completions |
304
306
  | `openAi` + `openrouter` (speech role) | OpenRouter `/audio/speech` |
307
+ | `openAi` + `local` | Local OpenAI-compatible `/v1/chat/completions` (Ollama, llama.cpp, vLLM, LM Studio, …) |
305
308
 
306
- OpenRouter uses Vercel AI SDK Core inside THEORUM's provider adapter. The adapter still emits THEORUM `TurnEvent` values and preserves raw provider evidence for citations/provenance where the normalized SDK stream does not expose enough detail.
309
+ Local adapters take an optional `baseUrl` (default `http://127.0.0.1:11434`). THEORUM does not read `OLLAMA_HOST`; hosts that honor that env should resolve it and pass `local.baseUrl`. History `parts` (including images) are mapped on the wire; `done` events include a normalized `stop` from the OpenAI `finish_reason`.
307
310
 
308
- Advanced OpenRouter exports live under `theorum/openrouter` (`createOpenRouterProvider`, `toOpenRouterPayload`, …). Prefer `createProvider` for turns unless the host needs to wire the OpenRouter adapter directly.
311
+ OpenRouter uses Vercel AI SDK Core inside THEORUM's provider adapter. That stack
312
+ loads **lazily on the first `complete` call** for `openAi` + `openrouter` chat —
313
+ not when importing THEORUM, and not for Google or local providers. The adapter
314
+ still emits THEORUM `TurnEvent` values and preserves raw provider evidence for
315
+ citations/provenance where the normalized SDK stream does not expose enough detail.
316
+
317
+ Advanced OpenRouter exports live under `theorum/openrouter` (`createOpenRouterProvider`,
318
+ `toOpenRouterPayload`, …). Prefer `createProvider` for turns unless the host needs
319
+ to wire the OpenRouter adapter directly. Direct local construction is also available
320
+ as `createLocalProvider` from the main / providers entrypoints. Importing
321
+ `theorum/openrouter` loads the Vercel SDK immediately.
309
322
 
310
323
  ---
311
324
 
@@ -326,6 +339,56 @@ Advanced OpenRouter exports live under `theorum/openrouter` (`createOpenRouterPr
326
339
 
327
340
  Internal files remain present in source for maintainability, but package consumers should use the public entrypoints above.
328
341
 
342
+ ### Exported API (`mod.ts`)
343
+
344
+ Named exports from the root barrel (same symbols hosts get from `theorum` /
345
+ `jsr:@theorum/core`):
346
+
347
+ | Group | Symbols |
348
+ | --- | --- |
349
+ | Guardrails errors | `describeError`, `isAbortError`, `publicError`, `TheorumError`, `throwIfAborted`, `toErrorEvent` |
350
+ | Quota | `QuotaSlotStatus`, `clientIp`, `quotaMessage`, `releaseSlot`, `resetSlots`, `skipQuota`, `takeSlot` |
351
+ | Sanitize | `PROJECT_ID_MAX`, `sanitizeProjectId`, `sanitizeText`, `sanitizeTurnRequest` |
352
+ | Compaction | `CompactionSplit`, `CompactionTokens`, `compactionMeter`, `compactionNeeded`, `estimateHistoryTokens`, `HISTORY_MEDIA_TOKENS`, `HISTORY_TEXT_ENCODING`, `resolveCompactionTokens`, `resolveHistoryTokens`, `shouldCompact`, `splitForCompaction` |
353
+ | Runner | `runTurn` |
354
+ | Catalog | `CATALOG`, `clampThinkingLevel`, `clampThinkingLevelForApiId`, `mediaKindForMime`, `getTool`, `listBuiltinIds`, `mimeAllowed`, `mimeEssence`, `modelEntryByApiId`, `registerTools`, `requireModelSpec`, `resetTools` |
355
+ | Profiles | `ProfileDefinition`, `clearProfiles`, `defineProfile`, `getProfile`, `hasProfile`, `listProfiles`, `registerProfile`, `registerProfiles`, `projectProfile`, `resolveTurn` |
356
+ | Structured | `getStructured`, `registerStructured`, `executeTool` |
357
+ | Stop / resume | `ProfileResumeSpec`, `TurnContinueFrom`, `TurnStop`, `TurnStopKind`, `AUTO_CONTINUE_DELAY_MS`, `CONTINUE_INSTRUCTION`, `DEFAULT_AUTO_CONTINUE`, `GenerationStopError`, `isGenerationStopError`, `isResumeableStop`, `isUserCancelledStop`, `shouldAutoContinue`, `turnStopFromClientStreamEnd`, `turnStopFromInteractionStatus`, `turnStopFromOpenRouter` |
358
+ | Observability | `jsonlSink`, `memorySink`, `noopSink`, `resolveTraceDir`, `sinkFromDir`, `writeTrace`, `TraceRecord` |
359
+ | Providers | `CreateProviderOptions`, `GeminiTransport`, `GeminiVault`, `LocalProviderConfig`, `createLocalProvider`, `createProvider`, `DEFAULT_LOCAL_BASE_URL` |
360
+
361
+ Kernel types re-exported through this barrel follow `export type *` from
362
+ `src/kernel/types.ts` (see `src/kernel/CONTRACT.md`).
363
+
364
+ ---
365
+
366
+ ## Documentation
367
+
368
+ Package docs are co-located with each public export (plus this README for `.`):
369
+
370
+ | Doc | Export |
371
+ | :--- | :--- |
372
+ | [`src/kernel/CONTRACT.md`](src/kernel/CONTRACT.md) | `theorum/kernel` — profiles, runner, compaction, stop/resume |
373
+ | [`src/providers/CONTRACT.md`](src/providers/CONTRACT.md) | `theorum/providers` — `createProvider`, secrets boundary |
374
+ | [`src/providers/OPENROUTER.md`](src/providers/OPENROUTER.md) | `theorum/openrouter` |
375
+ | [`src/guardrails/CONTRACT.md`](src/guardrails/CONTRACT.md) | `theorum/guardrails` |
376
+ | [`src/observability/CONTRACT.md`](src/observability/CONTRACT.md) | `theorum/observability` |
377
+ | [`src/host/CONTRACT.md`](src/host/CONTRACT.md) | `theorum/host` |
378
+ | [`src/cli/CONTRACT.md`](src/cli/CONTRACT.md) | `theorum/cli` |
379
+ | [`src/presets/CONTRACT.md`](src/presets/CONTRACT.md) | `theorum/presets` |
380
+ | [`src/presets/GOOGLE.md`](src/presets/GOOGLE.md) | `theorum/presets/google` |
381
+ | [`src/streaming/CONTRACT.md`](src/streaming/CONTRACT.md) | `theorum/streaming` |
382
+
383
+ Document health is enforced by `npm run lint:docs` — the **first** step of
384
+ `npm run lint` / `deno task lint` (`docs/_map.mjs`):
385
+
386
+ - Full production-file ownership (`mod.ts`, `src/**/*.ts`, `package.json`, docs-truth scripts)
387
+ - Export parity with `package.json` and export-drift vs entry `mod.ts` files
388
+ - Doc + **section** freshness on every code change (no Export-only gaming)
389
+ - Behavioral sections require `contract_test` evidence (≥2 supports each)
390
+ - Pre-commit runs `lint:docs` automatically (`prepare` installs the hook on `npm install`)
391
+
329
392
  ---
330
393
 
331
394
  ## Development
@@ -392,3 +455,40 @@ If an app needs domain rules, platform delivery policy, product copy, database a
392
455
  ## License
393
456
 
394
457
  MIT License. Copyright (c) ORCHID AI LLC.
458
+
459
+ ```theorum-evidence
460
+ {
461
+ "sections": {
462
+ "Core Principles": {
463
+ "supports": [
464
+ { "kind": "source", "path": "mod.ts" },
465
+ { "kind": "contract_test", "path": "tests/kernel/theorum.test.ts" }
466
+ ]
467
+ },
468
+ "Architecture": {
469
+ "supports": [
470
+ { "kind": "source", "path": "src/kernel/engine/runner.ts" },
471
+ { "kind": "contract_test", "path": "tests/kernel/theorum.test.ts" }
472
+ ]
473
+ },
474
+ "Public Entrypoints": {
475
+ "supports": [
476
+ { "kind": "config", "path": "package.json" },
477
+ { "kind": "contract_test", "path": "scripts/docs-truth/graph.test.mjs" }
478
+ ]
479
+ },
480
+ "Documentation": {
481
+ "supports": [
482
+ { "kind": "graph", "path": "docs/_map.mjs" },
483
+ { "kind": "contract_test", "path": "scripts/docs-truth/graph.test.mjs" }
484
+ ]
485
+ },
486
+ "Package Boundary": {
487
+ "supports": [
488
+ { "kind": "source", "path": "src/providers/create-provider.ts" },
489
+ { "kind": "contract_test", "path": "tests/providers/create-provider.test.ts" }
490
+ ]
491
+ }
492
+ }
493
+ }
494
+ ```
package/docs/cli.md ADDED
@@ -0,0 +1,97 @@
1
+ # CLI (`theorum/cli`)
2
+
3
+ Profile inspection and stress-test CLI. On npm this entry is also the
4
+ `theorum` binary. Hosts must register profiles (and providers) in-process
5
+ before commands that execute turns — the CLI does not embed app profiles.
6
+
7
+ ## Export
8
+
9
+ | Field | Value |
10
+ | --- | --- |
11
+ | Import | `theorum/cli` / `jsr:@theorum/core/cli` |
12
+ | Module | `src/cli/index.ts` |
13
+ | Binary | `theorum` (npm `bin`) |
14
+
15
+ ## Ownership
16
+
17
+ | Path | Role |
18
+ | --- | --- |
19
+ | `src/cli/index.ts` | Argument parser + command dispatch |
20
+ | `src/cli/commands/*` | `bench`, `fuzz`, `test`, `run`, `profile` |
21
+ | `src/cli/matrix/*` | Permutation synthesizer + fixtures |
22
+
23
+ ## Commands
24
+
25
+ ```text
26
+ theorum <command> [options]
27
+ ```
28
+
29
+ | Command | Purpose |
30
+ | --- | --- |
31
+ | `bench` | Synthetic kernel performance benchmark (`--chunks`, `--iterations`, `--warmup`) |
32
+ | `fuzz` | Adversarial guardrail fuzzer |
33
+ | `test` | Stress matrix or custom profile tests (`--profile`, `--all`, `--lite`, `--matrix`, `--mode`, `--search`, `--map`) |
34
+ | `run` | Execute a turn with streaming output (`--profile`, `--prompt`, `--mode`, …) |
35
+ | `profile list` / `profile show <id>` | Inspect registered profile blueprints |
36
+ | `help` | Usage |
37
+
38
+ Exit code `1` on failed `test` runs. `run` requires `--profile` (or `-p`).
39
+
40
+ ```bash
41
+ theorum test --profile my.agent --matrix
42
+ theorum run --profile my.agent --prompt "ping"
43
+ ```
44
+
45
+ ## Matrix and fixtures
46
+
47
+ | Module | Role |
48
+ | --- | --- |
49
+ | `matrix/synthesizer.ts` | Builds valid permutation cases (modes, optional tools) |
50
+ | `matrix/fixtures.ts` | Shared harness fixtures (not product personas) |
51
+
52
+ The matrix respects profile allowlists — e.g. `--search` only applies when
53
+ `googleSearch` is allowlisted.
54
+
55
+ ## Exported API
56
+
57
+ The entry module is the CLI program itself (side-effect main when run as a
58
+ bin). Prefer `deno task theorum` / `npx theorum` over importing commands in
59
+ application code.
60
+
61
+ ```theorum-evidence
62
+ {
63
+ "sections": {
64
+ "Export": {
65
+ "supports": [
66
+ { "kind": "source", "path": "src/cli/index.ts" },
67
+ { "kind": "config", "path": "package.json" }
68
+ ]
69
+ },
70
+ "Ownership": {
71
+ "supports": [
72
+ { "kind": "source", "path": "src/cli/index.ts" },
73
+ { "kind": "graph", "path": "docs/_map.mjs" }
74
+ ]
75
+ },
76
+ "Commands": {
77
+ "supports": [
78
+ { "kind": "source", "path": "src/cli/index.ts" },
79
+ { "kind": "source", "path": "src/cli/commands/run.ts" },
80
+ { "kind": "contract_test", "path": "tests/cli/cli.test.ts" }
81
+ ]
82
+ },
83
+ "Matrix and fixtures": {
84
+ "supports": [
85
+ { "kind": "source", "path": "src/cli/matrix/synthesizer.ts" },
86
+ { "kind": "contract_test", "path": "tests/cli/cli.test.ts" }
87
+ ]
88
+ },
89
+ "Exported API": {
90
+ "supports": [
91
+ { "kind": "source", "path": "src/cli/index.ts" },
92
+ { "kind": "contract_test", "path": "tests/cli/cli.test.ts" }
93
+ ]
94
+ }
95
+ }
96
+ }
97
+ ```
@@ -0,0 +1,178 @@
1
+ # Guardrails (`theorum/guardrails`)
2
+
3
+ Generic inbound and outbound guardrail primitives. App-specific policy,
4
+ product copy, and channel UX remain host-owned — this entry ships reusable
5
+ detectors, sanitizers, public error mapping, and optional per-day quota slots.
6
+
7
+ ## Export
8
+
9
+ | Field | Value |
10
+ | --- | --- |
11
+ | Import | `theorum/guardrails` / `jsr:@theorum/core/guardrails` |
12
+ | Module | `src/guardrails/mod.ts` |
13
+ | Also on | Root `theorum` re-exports common error/sanitize/quota helpers |
14
+
15
+ ## Ownership
16
+
17
+ Owns every module under `src/guardrails/`.
18
+
19
+ | Module | Role |
20
+ | --- | --- |
21
+ | `error.ts` | `TheorumError`, `publicError`, abort helpers |
22
+ | `sanitize.ts` | Turn + text sanitization |
23
+ | `injection.ts` | Prompt-injection span patterns |
24
+ | `sensitive.ts` | Credential / PII span patterns |
25
+ | `normalize.ts` | Detection normalization |
26
+ | `quota.ts` | In-memory daily slots for HTTP hosts |
27
+
28
+ ## Public errors
29
+
30
+ `TheorumError` marks expected contract failures. Never show raw internal
31
+ messages to end users — map through `publicError(err)` (or `toErrorEvent` for
32
+ streams).
33
+
34
+ | Internal marker | Public copy |
35
+ | --- | --- |
36
+ | `UPSTREAM_FAILED` | `PUBLIC_UNAVAILABLE` |
37
+ | `canary leaked` / egress violations | `PUBLIC_CANARY` |
38
+ | Abort | `PUBLIC_CANCELLED` |
39
+ | Tool / MIME / size denials | `PUBLIC_ACTION` / `PUBLIC_FILE_*` |
40
+
41
+ `describeError` returns structured detail for logs. `throwIfAborted(signal)`
42
+ rethrows `AbortError` when a turn should stop early.
43
+
44
+ Exact-message and regex rules live in `error.ts` (`EXACT`, `RULES` arrays) —
45
+ extend there when adding new stable public mappings.
46
+
47
+ ## Sanitization
48
+
49
+ Driven by profile `guardrails.sanitizeInput` and `guardrails.redactSensitive`
50
+ (default both on in `sanitizeText` unless overridden).
51
+
52
+ | API | Role |
53
+ | --- | --- |
54
+ | `sanitizeText` | Strip injection + sensitive spans from one string |
55
+ | `sanitizeTurnRequest` | Full turn: text, slots, dynamic tool args, blobs |
56
+ | `sanitizeProjectId` | Bound project id strings (`PROJECT_ID_MAX`) |
57
+
58
+ `injectionSpans` and `sensitiveSpans` return `RedactSpan[]`; `applySpans`
59
+ (from observability) performs replacement. Detection runs on normalized text
60
+ (`normalizeForDetection`).
61
+
62
+ ### Injection categories (non-exhaustive)
63
+
64
+ Patterns target untrusted user text before provider submission:
65
+
66
+ - Instruction override (`ignore previous instructions`, `disregard rules`, …)
67
+ - Mode hijack (`developer mode`, `jailbreak`, `DAN`, `do anything now`)
68
+ - Safety bypass (`disable safety filters`, …)
69
+ - Role / delimiter forgery (`<system>`, `[System Message]`, ChatML tokens)
70
+ - Prompt exfiltration (`reveal your system prompt`, …)
71
+ - Multilingual override fragments
72
+
73
+ False-positive tuning belongs in `injection.ts` tests
74
+ (`tests/guardrails/false-positives.test.ts`).
75
+
76
+ ## Sensitive data
77
+
78
+ | API | Role |
79
+ | --- | --- |
80
+ | `sensitiveSpans` | Credential / PII span detection |
81
+ | `redactSensitiveOnly` | Model output path without injection patterns |
82
+
83
+ `sensitiveSpans` redacts credential-like and PII patterns from inbound text and,
84
+ when enabled, outbound paths. Use `redactSensitiveOnly` on model output when
85
+ injection patterns should not run.
86
+
87
+ ## Quota
88
+
89
+ **Not** enforced inside `runTurn`. HTTP hosts call:
90
+
91
+ ```ts
92
+ const ip = clientIp(peer, req);
93
+ if (skipQuota(peer, req)) { /* local dev */ }
94
+ const status = takeSlot(profile, ip, Date.now());
95
+ // 'ok' | 'busy' | 'quota' | 'not_configured'
96
+ try {
97
+ await runTurn(...);
98
+ } finally {
99
+ releaseSlot(profile, ip);
100
+ }
101
+ ```
102
+
103
+ | Status | Meaning |
104
+ | --- | --- |
105
+ | `ok` | Slot taken; increment daily count |
106
+ | `busy` | Same ip/profile already in flight |
107
+ | `quota` | `perDay` exhausted |
108
+ | `not_configured` | Profile has no `guardrails.quota` |
109
+
110
+ `quotaMessage(profile)` uses `identity.handle` for user-facing limit copy.
111
+ `resetSlots()` clears in-memory state (tests).
112
+
113
+ ## Exported API
114
+
115
+ From `src/guardrails/mod.ts`:
116
+
117
+ | Group | Symbols |
118
+ | --- | --- |
119
+ | Public errors | `describeError`, `isAbortError`, `publicError`, `TheorumError`, `throwIfAborted`, `toErrorEvent`, `PUBLIC_ACTION`, `PUBLIC_CANARY`, `PUBLIC_CANCELLED`, `PUBLIC_FILE_COUNT`, `PUBLIC_FILE_SIZE`, `PUBLIC_FILE_TYPE`, `PUBLIC_GENERIC`, `PUBLIC_IMAGE_SIZE`, `PUBLIC_UNAVAILABLE`, `UPSTREAM_FAILED` |
120
+ | Injection / sensitive | `injectionSpans`, `sensitiveSpans` |
121
+ | Quota | `QuotaSlotStatus`, `clientIp`, `quotaMessage`, `releaseSlot`, `resetSlots`, `skipQuota`, `takeSlot` |
122
+ | Sanitize | `PROJECT_ID_MAX`, `sanitizeProjectId`, `sanitizeText`, `sanitizeTurnRequest` |
123
+
124
+ ```theorum-evidence
125
+ {
126
+ "sections": {
127
+ "Export": {
128
+ "supports": [
129
+ { "kind": "source", "path": "src/guardrails/mod.ts" },
130
+ { "kind": "config", "path": "package.json" }
131
+ ]
132
+ },
133
+ "Ownership": {
134
+ "supports": [
135
+ { "kind": "source", "path": "src/guardrails/mod.ts" },
136
+ { "kind": "graph", "path": "docs/_map.mjs" }
137
+ ]
138
+ },
139
+ "Public errors": {
140
+ "supports": [
141
+ { "kind": "source", "path": "src/guardrails/error.ts" },
142
+ { "kind": "contract_test", "path": "tests/guardrails/error.test.ts" }
143
+ ]
144
+ },
145
+ "Sanitization": {
146
+ "supports": [
147
+ { "kind": "source", "path": "src/guardrails/sanitize.ts" },
148
+ { "kind": "source", "path": "src/guardrails/injection.ts" },
149
+ { "kind": "contract_test", "path": "tests/guardrails/sanitize.test.ts" }
150
+ ]
151
+ },
152
+ "Injection categories (non-exhaustive)": {
153
+ "supports": [
154
+ { "kind": "source", "path": "src/guardrails/injection.ts" },
155
+ { "kind": "contract_test", "path": "tests/guardrails/false-positives.test.ts" }
156
+ ]
157
+ },
158
+ "Sensitive data": {
159
+ "supports": [
160
+ { "kind": "source", "path": "src/guardrails/sensitive.ts" },
161
+ { "kind": "contract_test", "path": "tests/guardrails/sanitize.test.ts" }
162
+ ]
163
+ },
164
+ "Quota": {
165
+ "supports": [
166
+ { "kind": "source", "path": "src/guardrails/quota.ts" },
167
+ { "kind": "contract_test", "path": "tests/guardrails/quota.test.ts" }
168
+ ]
169
+ },
170
+ "Exported API": {
171
+ "supports": [
172
+ { "kind": "source", "path": "src/guardrails/mod.ts" },
173
+ { "kind": "contract_test", "path": "tests/guardrails/error.test.ts" }
174
+ ]
175
+ }
176
+ }
177
+ }
178
+ ```
package/docs/host.md ADDED
@@ -0,0 +1,97 @@
1
+ # Host (`theorum/host`)
2
+
3
+ Optional Deno HTTP helpers for host applications. **Not** part of the turn
4
+ kernel — import only when you want shared reply/status glue and cutout-trace
5
+ flushing without reimplementing it per route.
6
+
7
+ ## Export
8
+
9
+ | Field | Value |
10
+ | --- | --- |
11
+ | Import | `theorum/host` / `jsr:@theorum/core/host` |
12
+ | Module | `src/host/mod.ts` |
13
+
14
+ ## Ownership
15
+
16
+ | Path | Role |
17
+ | --- | --- |
18
+ | `src/host/reply.ts` | JSON responses + HTTP status constants |
19
+ | `src/host/mint-trace.ts` | Cutout mint trace flush helpers |
20
+ | `src/host/mod.ts` | Public barrel |
21
+
22
+ ## HTTP replies
23
+
24
+ | Export | Role |
25
+ | --- | --- |
26
+ | `json(status, body, cors)` | JSON `Response` with merged CORS headers |
27
+ | `caughtStatus(err)` | `400` for `TheorumError`, else `500` |
28
+ | `HTTP_OK` | `200` |
29
+ | `HTTP_BUSY` | `429` |
30
+ | `HTTP_NOT_FOUND` | `404` |
31
+ | `HTTP_METHOD` | `405` |
32
+
33
+ Example:
34
+
35
+ ```ts
36
+ import { caughtStatus, HTTP_BUSY, json } from "theorum/host";
37
+
38
+ try {
39
+ return json(200, { ok: true }, cors);
40
+ } catch (err) {
41
+ return json(caughtStatus(err), { error: publicError(err) }, cors);
42
+ }
43
+ ```
44
+
45
+ Quota busy responses typically use `HTTP_BUSY` after `takeSlot` returns `busy`.
46
+
47
+ ## Cutout mint trace
48
+
49
+ | Export | Role |
50
+ | --- | --- |
51
+ | `flushMintTrace` | Flush pending cutout mint records after a turn |
52
+ | `CutoutTape` | Tape type for mint/cutout correlation |
53
+
54
+ Use when your Deno HTTP host records mint/cutout telemetry alongside THEORUM
55
+ turns. Skip entirely for non-HTTP or non-Deno hosts.
56
+
57
+ ## Exported API
58
+
59
+ Live list: `src/host/mod.ts` (`json`, status constants, `caughtStatus`,
60
+ `flushMintTrace`, `CutoutTape`).
61
+
62
+ ```theorum-evidence
63
+ {
64
+ "sections": {
65
+ "Export": {
66
+ "supports": [
67
+ { "kind": "source", "path": "src/host/mod.ts" },
68
+ { "kind": "config", "path": "package.json" }
69
+ ]
70
+ },
71
+ "Ownership": {
72
+ "supports": [
73
+ { "kind": "source", "path": "src/host/mod.ts" },
74
+ { "kind": "graph", "path": "docs/_map.mjs" }
75
+ ]
76
+ },
77
+ "HTTP replies": {
78
+ "supports": [
79
+ { "kind": "source", "path": "src/host/reply.ts" },
80
+ { "kind": "contract_test", "path": "tests/host/host.test.ts" }
81
+ ]
82
+ },
83
+ "Cutout mint trace": {
84
+ "supports": [
85
+ { "kind": "source", "path": "src/host/mint-trace.ts" },
86
+ { "kind": "contract_test", "path": "tests/host/host.test.ts" }
87
+ ]
88
+ },
89
+ "Exported API": {
90
+ "supports": [
91
+ { "kind": "source", "path": "src/host/mod.ts" },
92
+ { "kind": "contract_test", "path": "tests/host/host.test.ts" }
93
+ ]
94
+ }
95
+ }
96
+ }
97
+ ```