@sanctuary-framework/mcp-server 1.2.13 → 1.2.15

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/dist/index.d.ts CHANGED
@@ -4356,108 +4356,6 @@ declare class MalformedPrincipalPolicyError extends Error {
4356
4356
  */
4357
4357
  declare function loadPrincipalPolicy(storagePath: string): Promise<PrincipalPolicy>;
4358
4358
 
4359
- /**
4360
- * Sanctuary MCP Server — SHR Generator
4361
- *
4362
- * Generates a Sovereignty Health Report from current server state,
4363
- * signs it with a specified identity, and returns the complete signed SHR.
4364
- */
4365
-
4366
- /**
4367
- * Observed L4 reputation state used by the emitter. Callers gather these
4368
- * facts from the reputation store + audit log; the emitter derives
4369
- * degradations from them. Keeping evidence as plain data keeps the
4370
- * generator synchronous and easy to test.
4371
- */
4372
- interface L4Evidence {
4373
- /** Total attestations attributed to the signing identity */
4374
- attestation_count: number;
4375
- /** Count of attestations at each sovereignty tier */
4376
- tier_distribution: Record<SovereigntyTier, number>;
4377
- /** ISO timestamp of most recent attestation, or null when none exist */
4378
- most_recent_attestation_at: string | null;
4379
- /** Count of attestations with outcome_result === "disputed" */
4380
- dispute_count: number;
4381
- /** Attestation count per context label (optional; used by dashboard) */
4382
- context_breakdown?: Record<string, number>;
4383
- /**
4384
- * True iff the `reputation_publish` tool has been successfully invoked
4385
- * for this identity (i.e., there is at least one success audit entry).
4386
- */
4387
- verascore_linked: boolean;
4388
- /**
4389
- * Optional overrides for the emitter thresholds. Defaults apply when
4390
- * omitted or when a field is missing.
4391
- */
4392
- thresholds?: {
4393
- freshness_window_days?: number;
4394
- low_tier_dominance_threshold?: number;
4395
- };
4396
- }
4397
- interface SHRGeneratorOptions {
4398
- config: SanctuaryConfig;
4399
- identityManager: IdentityManager;
4400
- masterKey: Uint8Array;
4401
- /** Override validity window (milliseconds). Default: 1 hour. */
4402
- validityMs?: number;
4403
- /**
4404
- * Optional L4 reputation evidence. When provided, the generator emits
4405
- * L4 degradations (NO_REPUTATION_HISTORY, LOW_TIER_DOMINANCE,
4406
- * STALE_REPUTATION, DISPUTE_ON_RECORD, NO_VERASCORE_LINK) accordingly
4407
- * and downgrades `layers.l4.status` to `degraded` when any fire.
4408
- * When omitted, L4 is left at "active" (backward-compatible).
4409
- */
4410
- l4Evidence?: L4Evidence;
4411
- /**
4412
- * Clock override for deterministic testing of staleness behavior.
4413
- * Defaults to the current wall clock.
4414
- */
4415
- now?: Date;
4416
- }
4417
- /**
4418
- * Generate and sign a Sovereignty Health Report.
4419
- *
4420
- * @param identityId - Which identity to sign with (defaults to primary)
4421
- * @param opts - Generator dependencies
4422
- * @returns The signed SHR, or an error string
4423
- */
4424
- declare function generateSHR(identityId: string | undefined, opts: SHRGeneratorOptions): SignedSHR | string;
4425
-
4426
- /**
4427
- * Sanctuary v1.1 Operator Hub API Constants
4428
- *
4429
- * Routes, prefixes, and small enums shared across the hub modules.
4430
- * The hub API surface is consumed by the v1.1 dashboard UI (Prompt 8).
4431
- *
4432
- * Local-only invariant:
4433
- * Every route here describes activity inside a single fortress on a single
4434
- * operator's machine. Cross-fortress, fleet, and public-federation routes
4435
- * are out of scope.
4436
- */
4437
-
4438
- /**
4439
- * Inbox-resolve actions. The router rejects any other action token.
4440
- */
4441
- declare const HUB_INBOX_ACTIONS: readonly ["approve", "deny", "dismiss"];
4442
- type HubInboxAction = (typeof HUB_INBOX_ACTIONS)[number];
4443
- /**
4444
- * Agent-control actions surfaced by `POST /api/hub/agents/:id/:action`.
4445
- *
4446
- * `pause` / `resume` / `restart` are control-plane operations that the
4447
- * underlying harness may execute immediately; they are not Tier 1.
4448
- *
4449
- * `unwrap` and `lockdown` are Tier 1 operations per the Principal Policy
4450
- * loader. Hub endpoints for these MUST enqueue an `approval_pending` inbox
4451
- * item rather than execute directly. Tier 1 approval gates remain in force
4452
- * from the dashboard. The dashboard never auto-approves Tier 1 work.
4453
- */
4454
- declare const HUB_AGENT_CONTROL_ACTIONS: readonly ["pause", "resume", "restart", "unwrap", "lockdown"];
4455
- type HubAgentControlAction = (typeof HUB_AGENT_CONTROL_ACTIONS)[number];
4456
-
4457
- /** Channel-template identifiers per the five-template canonical starter set. */
4458
- declare const CHANNEL_TEMPLATE_IDS: readonly ["request-approve-act", "read-then-report", "scheduled-digest", "plan-draft-only", "fortress-relay"];
4459
- type ChannelTemplateId = (typeof CHANNEL_TEMPLATE_IDS)[number];
4460
-
4461
4359
  /**
4462
4360
  * Sanctuary MCP Server — Intelligence Substrate Selector Types
4463
4361
  *
@@ -5102,28 +5000,445 @@ declare class SubstrateSelector {
5102
5000
  * doesn't pre-spawn HTTP clients for substrates the operator never
5103
5001
  * touches.
5104
5002
  */
5105
- private buildHandle;
5106
- private disabledHandle;
5107
- private localHandle;
5108
- private veniceHandle;
5109
- private frontierHandle;
5110
- private probeSurfaceHealth;
5111
- private makeBadge;
5112
- private fallbackAction;
5003
+ private buildHandle;
5004
+ private disabledHandle;
5005
+ private localHandle;
5006
+ private veniceHandle;
5007
+ private frontierHandle;
5008
+ private probeSurfaceHealth;
5009
+ private makeBadge;
5010
+ private fallbackAction;
5011
+ /**
5012
+ * Internal hook for the Privacy Filter Tier 2 commit. Lets a redactor
5013
+ * audit-emit a `pii_redaction_event` payload through the selector
5014
+ * without exposing the AuditLog binding directly to redactor
5015
+ * implementations.
5016
+ */
5017
+ emitRedactionEvent(args: {
5018
+ surface: Surface;
5019
+ substrate: SubstrateChoice;
5020
+ matchCount: number;
5021
+ filterTier: 1 | 2;
5022
+ }): void;
5023
+ private emit;
5024
+ }
5025
+
5026
+ /**
5027
+ * Sanctuary v1.3 WP-V1.3-1 Sentinel Finding Store.
5028
+ *
5029
+ * Encrypted at-rest persistence for sentinel findings. Sibling to the
5030
+ * Upsilon-3 aggregator-store: same fortress-master-key-derived HKDF
5031
+ * subkey shape, AAD-bound to the finding_id, retention-aware.
5032
+ *
5033
+ * Storage layout:
5034
+ * namespace: `_sentinel_findings`
5035
+ * key: `finding.{finding_id}` (one record per finding)
5036
+ * payload: AES-256-GCM ciphertext of the JSON-serialized record.
5037
+ * key: `l2-sentinel-finding-v1` HKDF subkey of fortress master.
5038
+ * AAD: UTF-8 bytes of `finding_id`.
5039
+ *
5040
+ * Multi-fortress isolation: HKDF subkey derives from the fortress
5041
+ * master key. Two fortresses never produce identical encryption keys
5042
+ * for identical finding_ids.
5043
+ *
5044
+ * Retention: 30 days default, mirroring the audit-log envelope and the
5045
+ * aggregator payload store.
5046
+ */
5047
+
5048
+ interface SentinelFindingStoreOptions {
5049
+ storage: StorageBackend;
5050
+ masterKey: Uint8Array;
5051
+ fortressId: string;
5052
+ /** Operator-tunable retention window. Default 30 days. */
5053
+ retentionDays?: number;
5054
+ /** Wall-clock provider for deterministic tests. */
5055
+ now?: () => Date;
5056
+ }
5057
+ declare class SentinelFindingStore {
5058
+ private readonly storage;
5059
+ private readonly encryptionKey;
5060
+ private readonly fortressId;
5061
+ private readonly retentionDays;
5062
+ private readonly now;
5063
+ constructor(opts: SentinelFindingStoreOptions);
5064
+ /**
5065
+ * Persist a finding. Truncates the operator-visible summary to
5066
+ * SENTINEL_SUMMARY_MAX_CHARS so the dashboard render stays bounded.
5067
+ * Returns the retention deadline so callers can audit it.
5068
+ */
5069
+ saveFinding(finding: SentinelFinding): Promise<string>;
5070
+ /** Load a single finding by id, or null when absent / corrupted. */
5071
+ loadFinding(findingId: string): Promise<SentinelFinding | null>;
5072
+ /**
5073
+ * List findings, newest first. Optional filters: since (ISO 8601),
5074
+ * severity, sentinel_id, agent_id, limit. Default limit 100.
5075
+ */
5076
+ listFindings(opts?: {
5077
+ since?: string;
5078
+ severity?: SentinelSeverity;
5079
+ sentinelId?: string;
5080
+ agentId?: string;
5081
+ limit?: number;
5082
+ }): Promise<SentinelFinding[]>;
5083
+ /**
5084
+ * Drop expired findings. Returns the count removed.
5085
+ */
5086
+ pruneExpired(now?: Date): Promise<{
5087
+ pruned: number;
5088
+ }>;
5089
+ private decode;
5090
+ }
5091
+
5092
+ /**
5093
+ * Sanctuary v1.3 WP-V1.3-1 Sentinel Baseline Pack (Castle Layer 2 anchor)
5094
+ *
5095
+ * Shared types for the Sentinel observation surface.
5096
+ *
5097
+ * Castle-walking discipline:
5098
+ * - Castle Layer 1 (Castle Wall) blocks unauthorized egress at the kernel
5099
+ * boundary. That is the enforcement layer.
5100
+ * - Castle Layer 2 (Sentinels) observes server-local data only and surfaces
5101
+ * anomalies. NO outbound network. NO blocking. Findings flow into the
5102
+ * operator surface they already check.
5103
+ * - Castle Layer 3 (Cooperative MCP) is the agent contract. Sentinels do
5104
+ * not wrap agent tools and do not negotiate with agents.
5105
+ *
5106
+ * Phi-1 ships the framework + the egress-volume watcher. Phi-2 through
5107
+ * Phi-5 add credential-usage, cross-agent-chatter, suspicious-tool-call,
5108
+ * and anomaly-trigger sentinels against this same shape.
5109
+ */
5110
+
5111
+ /** Severity tier returned by `Sentinel.evaluate()`. */
5112
+ type SentinelSeverity = "info" | "warn" | "alert";
5113
+ /**
5114
+ * Read-only context handed to every sentinel on subscribe + evaluate.
5115
+ * Sentinels do NOT receive a writable storage handle and do NOT receive
5116
+ * an outbound HTTP client. The substrate selector is the single
5117
+ * outbound-capable surface; Phi-1 sentinels do not exercise it but
5118
+ * Phi-2/3/4/5 may want to invoke a local LLM for reasoning.
5119
+ */
5120
+ interface SentinelContext {
5121
+ /** Stable per-fortress identifier; multi-fortress isolation pivot. */
5122
+ fortressId: string;
5123
+ /** Audit log read API. Sentinels MUST NOT call append() through this. */
5124
+ auditLog: AuditLog;
5125
+ /** Optional substrate selector for LLM-backed reasoning. v1.3 Phi-1 unused. */
5126
+ substrateSelector?: SubstrateSelector;
5127
+ /** Wall-clock provider. Tests inject a deterministic clock. */
5128
+ now: () => Date;
5129
+ /**
5130
+ * Optional read view of the per-fortress sentinel finding store
5131
+ * (Phi-1 surface). First-order sentinels (Phi-1/2/3/4) do not need
5132
+ * this; the Phi-5 meta-sentinel reads it to detect patterns ACROSS
5133
+ * other sentinels' findings (compound finding, fortress-wide count
5134
+ * spikes, novel sentinel-ID combinations). The dispatcher attaches
5135
+ * the store automatically on `subscribeSentinel`; tests can omit it
5136
+ * when constructing a context literal for a first-order watcher.
5137
+ *
5138
+ * Multi-fortress isolation rides on the store's existing key shape:
5139
+ * the store is constructed per-fortress from the fortress master
5140
+ * key, so two fortresses' stores produce distinct ciphertext for
5141
+ * identical finding-ids and one fortress's read cannot decode
5142
+ * another fortress's findings.
5143
+ */
5144
+ findingStore?: SentinelFindingStore;
5145
+ }
5146
+ /**
5147
+ * One observation a sentinel produced. Persisted under the sentinel
5148
+ * findings store + emitted as an audit event +
5149
+ * surfaced to the operator dashboard.
5150
+ */
5151
+ interface SentinelFinding {
5152
+ /** Stable per-fortress finding id (UUID v4). */
5153
+ finding_id: string;
5154
+ /** Identifier of the sentinel that produced this finding. */
5155
+ sentinel_id: string;
5156
+ severity: SentinelSeverity;
5157
+ /**
5158
+ * Optional agent-id this finding pertains to. Absent when the finding
5159
+ * is fortress-wide (e.g. cross-agent chatter spike).
5160
+ */
5161
+ agent_id?: string;
5162
+ /** Operator-friendly one-liner. Truncated to 240 chars on persist. */
5163
+ summary: string;
5164
+ /**
5165
+ * Structured payload. Schema varies per sentinel but every payload is
5166
+ * a flat record of JSON-serializable values.
5167
+ */
5168
+ details: Record<string, unknown>;
5169
+ /** ISO 8601 timestamp at evaluation time. */
5170
+ observed_at: string;
5171
+ /**
5172
+ * Audit-log entries that triggered this finding. Sentinels populate
5173
+ * with `${entry.timestamp}:${entry.operation}` tuples (mirrors the
5174
+ * aggregator's audit_log_entry_id shape from Upsilon-1).
5175
+ */
5176
+ evidence_audit_ids: string[];
5177
+ /** Stable fortress id stamped at emit. Multi-fortress isolation pivot. */
5178
+ fortress_id: string;
5179
+ }
5180
+
5181
+ /**
5182
+ * Sanctuary v1.3 WP-V1.3-5 Pi-1 Honeypot Authoring types + audit ops.
5183
+ *
5184
+ * OPENS WP-V1.3-5 Honeypot Authoring. Operator writes a honeypot in
5185
+ * plain English; the compiler maps the English to a structured
5186
+ * TrapSpec; the runtime registers trap-handlers in the dashboard
5187
+ * route table; trap activations emit `honeypot_triggered` audit
5188
+ * events AND sentinel findings (Pi-1 reuses Phi-1's finding store so
5189
+ * traps surface in the existing sentinel UX).
5190
+ *
5191
+ * Pi-1 ships the http_endpoint trap class only; Pi-2 adds filesystem,
5192
+ * Pi-3 adds tool_call, Pi-4 adds credential. Architectural shape:
5193
+ * TrapSpec is a discriminated union keyed by `trap_class` so new
5194
+ * trap classes extend by adding a union arm + a runtime handler.
5195
+ *
5196
+ * Castle-walking discipline:
5197
+ * - Trap responses are server-local (404 or 500 returned to the
5198
+ * caller). No outbound surface from the trap path itself.
5199
+ * - The compile call routes through the substrate selector at the
5200
+ * `template-suggestion` surface (canonical outbound LLM channel
5201
+ * for template-shape generation; Rho-1 header strip applies).
5202
+ * - Trap findings route through the Phi-1 finding store, the
5203
+ * existing canonical pipeline for Castle Layer 2 observability.
5204
+ */
5205
+
5206
+ /** Operator-friendly trap class enum. */
5207
+ type TrapClass = "http_endpoint" | "filesystem" | "tool_call" | "credential";
5208
+ /**
5209
+ * HTTP-endpoint trap trigger. The runtime matches incoming requests
5210
+ * against `path_pattern` (glob-style with `*` and `**`); `method`
5211
+ * narrows to a specific HTTP method when set, otherwise any method
5212
+ * fires. `expected_caller_types` is operator-recorded metadata that
5213
+ * surfaces in the finding's evidence; the runtime does not gate on
5214
+ * it (caller identity is observed, not constrained, at the trap
5215
+ * boundary).
5216
+ */
5217
+ interface HttpEndpointTrigger {
5218
+ kind: "http_endpoint";
5219
+ path_pattern: string;
5220
+ method?: string;
5221
+ expected_caller_types: string[];
5222
+ }
5223
+ /**
5224
+ * Filesystem trap trigger (Pi-2). The runtime monitor observes
5225
+ * filesystem-shaped operations the operator declared sensitive and
5226
+ * fires when a matching operation is reported through
5227
+ * `FilesystemTrapMonitor.observe(...)`. Pi-2 ships the monitor as a
5228
+ * pure observation primitive; specific wiring (proxy-call accesses,
5229
+ * state-store reads, future tool-call instrumentation) attaches in
5230
+ * follow-up PRs by calling the monitor's observe API.
5231
+ *
5232
+ * `ops` declares which operations the operator cares about; an
5233
+ * `observe()` call whose `operation` is not in this set will not
5234
+ * fire the trap.
5235
+ */
5236
+ interface FilesystemTrigger {
5237
+ kind: "filesystem";
5238
+ /**
5239
+ * Filesystem-path glob with `*` (one segment) / `**` (multiple
5240
+ * segments). Anchored at both ends per the Pi-1 glob contract.
5241
+ */
5242
+ path_pattern: string;
5243
+ /** Operations the trap fires on. */
5244
+ ops: FilesystemOp[];
5245
+ /** Operator-recorded metadata; not gated on. */
5246
+ expected_caller_types: string[];
5247
+ }
5248
+ /** Filesystem operations recognized by the monitor. */
5249
+ type FilesystemOp = "read" | "write" | "delete" | "list";
5250
+ /**
5251
+ * Discriminated-union trigger keyed by `kind`. The outer `trap_class`
5252
+ * field on TrapSpec keeps the operator-facing taxonomy; the inner
5253
+ * `kind` discriminator on the trigger is what TypeScript narrows on
5254
+ * inside runtime handlers + the registry's matching code.
5255
+ */
5256
+ type TrapTrigger = HttpEndpointTrigger | FilesystemTrigger;
5257
+ /**
5258
+ * One compiled trap. Persisted by the registry, deployed to the
5259
+ * runtime route table, and used by the finding emitter when a trap
5260
+ * triggers. Pi-1 shipped http_endpoint only; Pi-2 adds filesystem
5261
+ * via the `kind`-discriminated trigger union.
5262
+ */
5263
+ interface TrapSpec {
5264
+ trap_id: string;
5265
+ trap_class: TrapClass;
5266
+ trigger: TrapTrigger;
5267
+ finding_severity: SentinelSeverity;
5268
+ english_text: string;
5269
+ explanation_paragraph: string;
5270
+ compiled_at: string;
5271
+ }
5272
+
5273
+ /**
5274
+ * Sanctuary v1.3 WP-V1.3-5 Pi-2 Trap Store.
5275
+ *
5276
+ * Encrypted at-rest persistence for deployed honeypot TrapSpecs.
5277
+ * Sibling to Phi-1's SentinelFindingStore: same fortress-master-key-
5278
+ * derived HKDF subkey shape, AAD-bound to the trap_id, per-fortress
5279
+ * scoped.
5280
+ *
5281
+ * Storage layout:
5282
+ * namespace: `_honeypot_traps`
5283
+ * key: `trap.{trap_id}` (one record per deployed trap)
5284
+ * payload: AES-256-GCM ciphertext of the JSON-serialized spec.
5285
+ * key: `l2-honeypot-trap-v1` HKDF subkey of fortress master.
5286
+ * AAD: UTF-8 bytes of `trap_id`.
5287
+ *
5288
+ * Multi-fortress isolation: HKDF subkey derives from the fortress
5289
+ * master key. Two fortresses never produce identical encryption keys
5290
+ * for identical trap_ids; a fortress that reads another fortress's
5291
+ * encrypted record cannot decrypt it.
5292
+ *
5293
+ * Persistence contract:
5294
+ * - save(spec): write the spec under its trap_id. Idempotent;
5295
+ * re-saves overwrite.
5296
+ * - delete(trapId): remove the record. Idempotent.
5297
+ * - loadAll(): rehydrate every persisted spec. Used at boot to
5298
+ * populate the in-memory TrapRegistry. Corrupted records are
5299
+ * dropped (best-effort recovery: a malformed entry should not
5300
+ * block the rest of the fortress).
5301
+ *
5302
+ * Pi-2 ships traps with no retention window (traps stay deployed
5303
+ * until explicitly undeployed). The store mirrors SentinelFindingStore's
5304
+ * AES-256-GCM envelope shape but omits retention deadlines.
5305
+ */
5306
+
5307
+ interface TrapStoreOptions {
5308
+ storage: StorageBackend;
5309
+ masterKey: Uint8Array;
5310
+ fortressId: string;
5311
+ }
5312
+ declare class TrapStore {
5313
+ private readonly storage;
5314
+ private readonly encryptionKey;
5315
+ private readonly fortressId;
5316
+ constructor(opts: TrapStoreOptions);
5317
+ /** Persist (or overwrite) one trap. Returns the trap_id on success. */
5318
+ save(spec: TrapSpec): Promise<string>;
5319
+ /**
5320
+ * Remove one trap by id. Returns true when a record was removed,
5321
+ * false when no record existed (idempotent).
5322
+ */
5323
+ delete(trapId: string): Promise<boolean>;
5324
+ /**
5325
+ * Load every persisted trap. Used at boot to repopulate the
5326
+ * in-memory TrapRegistry. Corrupted records are silently skipped
5327
+ * so one malformed entry never blocks the rest of the fortress's
5328
+ * traps from rehydrating.
5329
+ *
5330
+ * Returns the specs sorted by `compiled_at` ascending so the
5331
+ * in-memory registry's insertion order matches the original
5332
+ * deploy order (relevant for Pi-1's "first-deployed wins on
5333
+ * overlapping match" contract).
5334
+ */
5335
+ loadAll(): Promise<TrapSpec[]>;
5336
+ /** Read-only fortress-id getter. */
5337
+ getFortressId(): string;
5338
+ private decode;
5339
+ }
5340
+
5341
+ /**
5342
+ * Sanctuary MCP Server — SHR Generator
5343
+ *
5344
+ * Generates a Sovereignty Health Report from current server state,
5345
+ * signs it with a specified identity, and returns the complete signed SHR.
5346
+ */
5347
+
5348
+ /**
5349
+ * Observed L4 reputation state used by the emitter. Callers gather these
5350
+ * facts from the reputation store + audit log; the emitter derives
5351
+ * degradations from them. Keeping evidence as plain data keeps the
5352
+ * generator synchronous and easy to test.
5353
+ */
5354
+ interface L4Evidence {
5355
+ /** Total attestations attributed to the signing identity */
5356
+ attestation_count: number;
5357
+ /** Count of attestations at each sovereignty tier */
5358
+ tier_distribution: Record<SovereigntyTier, number>;
5359
+ /** ISO timestamp of most recent attestation, or null when none exist */
5360
+ most_recent_attestation_at: string | null;
5361
+ /** Count of attestations with outcome_result === "disputed" */
5362
+ dispute_count: number;
5363
+ /** Attestation count per context label (optional; used by dashboard) */
5364
+ context_breakdown?: Record<string, number>;
5365
+ /**
5366
+ * True iff the `reputation_publish` tool has been successfully invoked
5367
+ * for this identity (i.e., there is at least one success audit entry).
5368
+ */
5369
+ verascore_linked: boolean;
5370
+ /**
5371
+ * Optional overrides for the emitter thresholds. Defaults apply when
5372
+ * omitted or when a field is missing.
5373
+ */
5374
+ thresholds?: {
5375
+ freshness_window_days?: number;
5376
+ low_tier_dominance_threshold?: number;
5377
+ };
5378
+ }
5379
+ interface SHRGeneratorOptions {
5380
+ config: SanctuaryConfig;
5381
+ identityManager: IdentityManager;
5382
+ masterKey: Uint8Array;
5383
+ /** Override validity window (milliseconds). Default: 1 hour. */
5384
+ validityMs?: number;
5385
+ /**
5386
+ * Optional L4 reputation evidence. When provided, the generator emits
5387
+ * L4 degradations (NO_REPUTATION_HISTORY, LOW_TIER_DOMINANCE,
5388
+ * STALE_REPUTATION, DISPUTE_ON_RECORD, NO_VERASCORE_LINK) accordingly
5389
+ * and downgrades `layers.l4.status` to `degraded` when any fire.
5390
+ * When omitted, L4 is left at "active" (backward-compatible).
5391
+ */
5392
+ l4Evidence?: L4Evidence;
5113
5393
  /**
5114
- * Internal hook for the Privacy Filter Tier 2 commit. Lets a redactor
5115
- * audit-emit a `pii_redaction_event` payload through the selector
5116
- * without exposing the AuditLog binding directly to redactor
5117
- * implementations.
5394
+ * Clock override for deterministic testing of staleness behavior.
5395
+ * Defaults to the current wall clock.
5118
5396
  */
5119
- emitRedactionEvent(args: {
5120
- surface: Surface;
5121
- substrate: SubstrateChoice;
5122
- matchCount: number;
5123
- filterTier: 1 | 2;
5124
- }): void;
5125
- private emit;
5397
+ now?: Date;
5126
5398
  }
5399
+ /**
5400
+ * Generate and sign a Sovereignty Health Report.
5401
+ *
5402
+ * @param identityId - Which identity to sign with (defaults to primary)
5403
+ * @param opts - Generator dependencies
5404
+ * @returns The signed SHR, or an error string
5405
+ */
5406
+ declare function generateSHR(identityId: string | undefined, opts: SHRGeneratorOptions): SignedSHR | string;
5407
+
5408
+ /**
5409
+ * Sanctuary v1.1 Operator Hub API Constants
5410
+ *
5411
+ * Routes, prefixes, and small enums shared across the hub modules.
5412
+ * The hub API surface is consumed by the v1.1 dashboard UI (Prompt 8).
5413
+ *
5414
+ * Local-only invariant:
5415
+ * Every route here describes activity inside a single fortress on a single
5416
+ * operator's machine. Cross-fortress, fleet, and public-federation routes
5417
+ * are out of scope.
5418
+ */
5419
+
5420
+ /**
5421
+ * Inbox-resolve actions. The router rejects any other action token.
5422
+ */
5423
+ declare const HUB_INBOX_ACTIONS: readonly ["approve", "deny", "dismiss"];
5424
+ type HubInboxAction = (typeof HUB_INBOX_ACTIONS)[number];
5425
+ /**
5426
+ * Agent-control actions surfaced by `POST /api/hub/agents/:id/:action`.
5427
+ *
5428
+ * `pause` / `resume` / `restart` are control-plane operations that the
5429
+ * underlying harness may execute immediately; they are not Tier 1.
5430
+ *
5431
+ * `unwrap` and `lockdown` are Tier 1 operations per the Principal Policy
5432
+ * loader. Hub endpoints for these MUST enqueue an `approval_pending` inbox
5433
+ * item rather than execute directly. Tier 1 approval gates remain in force
5434
+ * from the dashboard. The dashboard never auto-approves Tier 1 work.
5435
+ */
5436
+ declare const HUB_AGENT_CONTROL_ACTIONS: readonly ["pause", "resume", "restart", "unwrap", "lockdown"];
5437
+ type HubAgentControlAction = (typeof HUB_AGENT_CONTROL_ACTIONS)[number];
5438
+
5439
+ /** Channel-template identifiers per the five-template canonical starter set. */
5440
+ declare const CHANNEL_TEMPLATE_IDS: readonly ["request-approve-act", "read-then-report", "scheduled-digest", "plan-draft-only", "fortress-relay"];
5441
+ type ChannelTemplateId = (typeof CHANNEL_TEMPLATE_IDS)[number];
5127
5442
 
5128
5443
  /**
5129
5444
  * Sanctuary MCP Server — Operator Chat Types
@@ -7258,161 +7573,6 @@ declare class ApprovalAggregator {
7258
7573
  private hydrate;
7259
7574
  }
7260
7575
 
7261
- /**
7262
- * Sanctuary v1.3 WP-V1.3-1 Sentinel Finding Store.
7263
- *
7264
- * Encrypted at-rest persistence for sentinel findings. Sibling to the
7265
- * Upsilon-3 aggregator-store: same fortress-master-key-derived HKDF
7266
- * subkey shape, AAD-bound to the finding_id, retention-aware.
7267
- *
7268
- * Storage layout:
7269
- * namespace: `_sentinel_findings`
7270
- * key: `finding.{finding_id}` (one record per finding)
7271
- * payload: AES-256-GCM ciphertext of the JSON-serialized record.
7272
- * key: `l2-sentinel-finding-v1` HKDF subkey of fortress master.
7273
- * AAD: UTF-8 bytes of `finding_id`.
7274
- *
7275
- * Multi-fortress isolation: HKDF subkey derives from the fortress
7276
- * master key. Two fortresses never produce identical encryption keys
7277
- * for identical finding_ids.
7278
- *
7279
- * Retention: 30 days default, mirroring the audit-log envelope and the
7280
- * aggregator payload store.
7281
- */
7282
-
7283
- interface SentinelFindingStoreOptions {
7284
- storage: StorageBackend;
7285
- masterKey: Uint8Array;
7286
- fortressId: string;
7287
- /** Operator-tunable retention window. Default 30 days. */
7288
- retentionDays?: number;
7289
- /** Wall-clock provider for deterministic tests. */
7290
- now?: () => Date;
7291
- }
7292
- declare class SentinelFindingStore {
7293
- private readonly storage;
7294
- private readonly encryptionKey;
7295
- private readonly fortressId;
7296
- private readonly retentionDays;
7297
- private readonly now;
7298
- constructor(opts: SentinelFindingStoreOptions);
7299
- /**
7300
- * Persist a finding. Truncates the operator-visible summary to
7301
- * SENTINEL_SUMMARY_MAX_CHARS so the dashboard render stays bounded.
7302
- * Returns the retention deadline so callers can audit it.
7303
- */
7304
- saveFinding(finding: SentinelFinding): Promise<string>;
7305
- /** Load a single finding by id, or null when absent / corrupted. */
7306
- loadFinding(findingId: string): Promise<SentinelFinding | null>;
7307
- /**
7308
- * List findings, newest first. Optional filters: since (ISO 8601),
7309
- * severity, sentinel_id, agent_id, limit. Default limit 100.
7310
- */
7311
- listFindings(opts?: {
7312
- since?: string;
7313
- severity?: SentinelSeverity;
7314
- sentinelId?: string;
7315
- agentId?: string;
7316
- limit?: number;
7317
- }): Promise<SentinelFinding[]>;
7318
- /**
7319
- * Drop expired findings. Returns the count removed.
7320
- */
7321
- pruneExpired(now?: Date): Promise<{
7322
- pruned: number;
7323
- }>;
7324
- private decode;
7325
- }
7326
-
7327
- /**
7328
- * Sanctuary v1.3 WP-V1.3-1 Sentinel Baseline Pack (Castle Layer 2 anchor)
7329
- *
7330
- * Shared types for the Sentinel observation surface.
7331
- *
7332
- * Castle-walking discipline:
7333
- * - Castle Layer 1 (Castle Wall) blocks unauthorized egress at the kernel
7334
- * boundary. That is the enforcement layer.
7335
- * - Castle Layer 2 (Sentinels) observes server-local data only and surfaces
7336
- * anomalies. NO outbound network. NO blocking. Findings flow into the
7337
- * operator surface they already check.
7338
- * - Castle Layer 3 (Cooperative MCP) is the agent contract. Sentinels do
7339
- * not wrap agent tools and do not negotiate with agents.
7340
- *
7341
- * Phi-1 ships the framework + the egress-volume watcher. Phi-2 through
7342
- * Phi-5 add credential-usage, cross-agent-chatter, suspicious-tool-call,
7343
- * and anomaly-trigger sentinels against this same shape.
7344
- */
7345
-
7346
- /** Severity tier returned by `Sentinel.evaluate()`. */
7347
- type SentinelSeverity = "info" | "warn" | "alert";
7348
- /**
7349
- * Read-only context handed to every sentinel on subscribe + evaluate.
7350
- * Sentinels do NOT receive a writable storage handle and do NOT receive
7351
- * an outbound HTTP client. The substrate selector is the single
7352
- * outbound-capable surface; Phi-1 sentinels do not exercise it but
7353
- * Phi-2/3/4/5 may want to invoke a local LLM for reasoning.
7354
- */
7355
- interface SentinelContext {
7356
- /** Stable per-fortress identifier; multi-fortress isolation pivot. */
7357
- fortressId: string;
7358
- /** Audit log read API. Sentinels MUST NOT call append() through this. */
7359
- auditLog: AuditLog;
7360
- /** Optional substrate selector for LLM-backed reasoning. v1.3 Phi-1 unused. */
7361
- substrateSelector?: SubstrateSelector;
7362
- /** Wall-clock provider. Tests inject a deterministic clock. */
7363
- now: () => Date;
7364
- /**
7365
- * Optional read view of the per-fortress sentinel finding store
7366
- * (Phi-1 surface). First-order sentinels (Phi-1/2/3/4) do not need
7367
- * this; the Phi-5 meta-sentinel reads it to detect patterns ACROSS
7368
- * other sentinels' findings (compound finding, fortress-wide count
7369
- * spikes, novel sentinel-ID combinations). The dispatcher attaches
7370
- * the store automatically on `subscribeSentinel`; tests can omit it
7371
- * when constructing a context literal for a first-order watcher.
7372
- *
7373
- * Multi-fortress isolation rides on the store's existing key shape:
7374
- * the store is constructed per-fortress from the fortress master
7375
- * key, so two fortresses' stores produce distinct ciphertext for
7376
- * identical finding-ids and one fortress's read cannot decode
7377
- * another fortress's findings.
7378
- */
7379
- findingStore?: SentinelFindingStore;
7380
- }
7381
- /**
7382
- * One observation a sentinel produced. Persisted under the sentinel
7383
- * findings store + emitted as an audit event +
7384
- * surfaced to the operator dashboard.
7385
- */
7386
- interface SentinelFinding {
7387
- /** Stable per-fortress finding id (UUID v4). */
7388
- finding_id: string;
7389
- /** Identifier of the sentinel that produced this finding. */
7390
- sentinel_id: string;
7391
- severity: SentinelSeverity;
7392
- /**
7393
- * Optional agent-id this finding pertains to. Absent when the finding
7394
- * is fortress-wide (e.g. cross-agent chatter spike).
7395
- */
7396
- agent_id?: string;
7397
- /** Operator-friendly one-liner. Truncated to 240 chars on persist. */
7398
- summary: string;
7399
- /**
7400
- * Structured payload. Schema varies per sentinel but every payload is
7401
- * a flat record of JSON-serializable values.
7402
- */
7403
- details: Record<string, unknown>;
7404
- /** ISO 8601 timestamp at evaluation time. */
7405
- observed_at: string;
7406
- /**
7407
- * Audit-log entries that triggered this finding. Sentinels populate
7408
- * with `${entry.timestamp}:${entry.operation}` tuples (mirrors the
7409
- * aggregator's audit_log_entry_id shape from Upsilon-1).
7410
- */
7411
- evidence_audit_ids: string[];
7412
- /** Stable fortress id stamped at emit. Multi-fortress isolation pivot. */
7413
- fortress_id: string;
7414
- }
7415
-
7416
7576
  /**
7417
7577
  * Sanctuary v1.3 WP-V1.3-1 Sentinel base class.
7418
7578
  *
@@ -8035,6 +8195,69 @@ declare class HandoffEventBridge {
8035
8195
  emit(entry: HandoffEntry): void;
8036
8196
  }
8037
8197
 
8198
+ /**
8199
+ * Sanctuary v1.3 WP-V1.3-5 Pi-1 Trap Registry.
8200
+ *
8201
+ * Per-fortress in-memory registry of deployed honeypot traps. Holds
8202
+ * the live TrapSpec set + provides path-matching for the runtime
8203
+ * dispatcher.
8204
+ *
8205
+ * Lifecycle:
8206
+ * deploy(spec): activates the trap; idempotent on trap_id.
8207
+ * undeploy(trapId): removes the trap; returns whether anything
8208
+ * was actually removed (idempotent).
8209
+ * list(): returns the live trap set as a fresh array.
8210
+ * findMatching(path,m): returns the first trap matching the request.
8211
+ *
8212
+ * Castle-walking discipline:
8213
+ * - Read-only path against deployed traps; mutating calls land here
8214
+ * deliberately from the management routes.
8215
+ * - No outbound surface; the registry is purely server-local state.
8216
+ * - Per-fortress isolation: one registry instance per fortress. The
8217
+ * dispatcher wires one registry per dashboard instance.
8218
+ *
8219
+ * Path-matching glob:
8220
+ * * matches one path segment (no slashes)
8221
+ * ** matches multiple path segments (zero or more, including
8222
+ * slashes)
8223
+ * anything else is a literal character. The pattern is anchored at
8224
+ * both ends so `/admin` does NOT match `/admin/foo`; the operator
8225
+ * must use `/admin/**` to match prefix-style.
8226
+ */
8227
+
8228
+ interface TrapMatchInput {
8229
+ /** Request URL path. */
8230
+ path: string;
8231
+ /** Uppercased HTTP method. */
8232
+ method: string;
8233
+ }
8234
+ declare class TrapRegistry {
8235
+ private readonly traps;
8236
+ /**
8237
+ * Deploy a trap. Idempotent on `trap_id`: re-deploying replaces the
8238
+ * previous spec for that id. Returns true on first deploy, false on
8239
+ * re-deploy (so callers can branch audit emission).
8240
+ */
8241
+ deploy(spec: TrapSpec): boolean;
8242
+ /**
8243
+ * Undeploy by trap_id. Returns true when a trap was removed, false
8244
+ * when no trap had that id (idempotent).
8245
+ */
8246
+ undeploy(trapId: string): boolean;
8247
+ /** List deployed traps. Returns a fresh array; mutation is safe. */
8248
+ list(): TrapSpec[];
8249
+ /** Look up a single trap by id. */
8250
+ get(trapId: string): TrapSpec | undefined;
8251
+ /**
8252
+ * Find the first trap matching the request. Iteration order is
8253
+ * insertion order; operators who deploy multiple overlapping traps
8254
+ * see the earliest-deployed one fire. Tests cover this contract.
8255
+ */
8256
+ findMatching(input: TrapMatchInput): TrapSpec | undefined;
8257
+ /** Drop every trap. Tests use this between runs; not surfaced via API. */
8258
+ clear(): void;
8259
+ }
8260
+
8038
8261
  interface DashboardConfig {
8039
8262
  port: number;
8040
8263
  host: string;
@@ -8131,6 +8354,13 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
8131
8354
  private workflowStateTracker;
8132
8355
  private handoffAuditLog;
8133
8356
  private handoffOperatorId;
8357
+ private honeypotRegistry;
8358
+ private honeypotFindingStore;
8359
+ private honeypotAuditLog;
8360
+ private honeypotOperatorId;
8361
+ private honeypotFortressId;
8362
+ private honeypotSelector;
8363
+ private honeypotStore;
8134
8364
  constructor(config: DashboardConfig);
8135
8365
  /**
8136
8366
  * Inject dependencies after construction.
@@ -8199,6 +8429,38 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
8199
8429
  */
8200
8430
  workflowStateTracker?: WorkflowStateTracker | null;
8201
8431
  }): void;
8432
+ /**
8433
+ * v1.3 WP-V1.3-5 Pi-1 Honeypot Authoring: bind the per-fortress
8434
+ * trap registry + finding store + audit log + operator id. Once
8435
+ * set, two surfaces activate:
8436
+ * 1. Front-of-dispatch trap-trigger hook: every request runs
8437
+ * through `handleHoneypotTriggerIfMatch` BEFORE legacy/v1.1/
8438
+ * sentinel/coordination routing. Matching traps return 404
8439
+ * and the request never reaches the regular dispatcher.
8440
+ * 2. Management API at /api/honeypot/* routes through
8441
+ * `handleHoneypotRoute`.
8442
+ *
8443
+ * The optional `selector` opt wires the LLM compile path; absent
8444
+ * selector forces the heuristic compile path (which still produces
8445
+ * a usable TrapSpec with warnings).
8446
+ */
8447
+ setHoneypotRegistry(opts: {
8448
+ registry: TrapRegistry | null;
8449
+ findingStore?: SentinelFindingStore | null;
8450
+ auditLog?: AuditLog | null;
8451
+ operatorId?: string | null;
8452
+ fortressId?: string | null;
8453
+ selector?: SubstrateSelector | null;
8454
+ /**
8455
+ * Pi-2: encrypted at-rest persistence for the deployed traps. When
8456
+ * non-null, the management API's deploy + undeploy handlers write
8457
+ * through to the store so the fortress keeps its trap deployment
8458
+ * across restart. Boot rehydration is the host's responsibility:
8459
+ * call `store.loadAll()` and `registry.deploy(spec)` for each
8460
+ * persisted spec BEFORE calling this method.
8461
+ */
8462
+ store?: TrapStore | null;
8463
+ }): void;
8202
8464
  /**
8203
8465
  * v1.3 WP-V1.3-10 dispatch entry point. Called from `handleRequest`
8204
8466
  * before the legacy approval route table. Returns true when served.
@@ -8216,6 +8478,21 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
8216
8478
  * when a HandoffLog has been bound. Returns true when served.
8217
8479
  */
8218
8480
  private dispatchCoordination;
8481
+ /**
8482
+ * v1.3 WP-V1.3-5 Pi-1 dispatch entry point. Routes
8483
+ * `/api/honeypot/*` requests through the honeypot management
8484
+ * router when a registry has been bound. Returns true when served.
8485
+ */
8486
+ private dispatchHoneypot;
8487
+ /**
8488
+ * v1.3 WP-V1.3-5 Pi-1 front-of-dispatch trap-trigger hook. Examines
8489
+ * every request BEFORE legacy/v1.1/sentinel/coordination routing.
8490
+ * Returns true when a deployed trap matched the request and the
8491
+ * handler emitted the audit event + sentinel finding + plausible
8492
+ * 404 response. Returns false when no trap matched; caller
8493
+ * continues with normal routing.
8494
+ */
8495
+ private dispatchHoneypotTrap;
8219
8496
  /**
8220
8497
  * v1.1 dispatch entry point. Called from `handleRequest` before the
8221
8498
  * legacy route table. Returns true when the request was served by v1.1
@@ -8302,6 +8579,14 @@ declare class DashboardApprovalChannel implements ApprovalChannel {
8302
8579
  */
8303
8580
  private pruneRateLimits;
8304
8581
  private handleRequest;
8582
+ /**
8583
+ * v1.3 WP-V1.3-5 Pi-1: post-honeypot-trap request continuation. The
8584
+ * front-of-dispatch trap-trigger hook may short-circuit a request;
8585
+ * when it does not, this method runs the original dispatch ladder.
8586
+ * Pulled out as a helper so the trap-hook + non-trap paths share
8587
+ * one code path through every downstream dispatcher.
8588
+ */
8589
+ private continueHandleRequest;
8305
8590
  private handleLegacyRequest;
8306
8591
  /**
8307
8592
  * SEC-012: Exchange a long-lived auth token (in Authorization header)