@sanctuary-framework/mcp-server 1.2.11 → 1.2.12

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.js CHANGED
@@ -16704,6 +16704,276 @@ var COORDINATION_VIEW_AUDIT_OPS = {
16704
16704
  ENTRY_DRILLED: "operator_handoff_entry_drilled"
16705
16705
  };
16706
16706
 
16707
+ // src/coordination/context-transfer-extractor.ts
16708
+ var SUMMARY_MAX_CHARS = 240;
16709
+ var CATEGORY_VALUES = [
16710
+ "memory",
16711
+ "credentials",
16712
+ "plans",
16713
+ "outputs",
16714
+ "audit-refs",
16715
+ "other"
16716
+ ];
16717
+ async function extractContextTransferBreakdown(detail, deps = {}) {
16718
+ const pathA = tryStructuredPath(detail);
16719
+ if (pathA) return pathA;
16720
+ const pathB = tryCompositionPath(detail);
16721
+ if (pathB) return pathB;
16722
+ const pathC = tryHeuristicPath(detail);
16723
+ if (pathC.confidence >= 0.5 || !deps.substrateSelector) {
16724
+ return pathC;
16725
+ }
16726
+ const assist = await tryLlmAssistPath(detail, deps.substrateSelector);
16727
+ return assist ?? pathC;
16728
+ }
16729
+ function tryStructuredPath(detail) {
16730
+ const details = sourceDetails(detail.source_audit_entry);
16731
+ if (!details) return null;
16732
+ const transferredRaw = details["transferred"];
16733
+ const withheldRaw = details["withheld"];
16734
+ if (transferredRaw === void 0 && withheldRaw === void 0) return null;
16735
+ const transferred = parseExplicitContextItems(transferredRaw);
16736
+ const withheld = parseExplicitContextItems(withheldRaw);
16737
+ return {
16738
+ handoff_entry_id: detail.entry.entry_id,
16739
+ transferred,
16740
+ withheld,
16741
+ source: "structured",
16742
+ confidence: 1
16743
+ };
16744
+ }
16745
+ function tryCompositionPath(detail) {
16746
+ const op = detail.source_audit_entry.operation;
16747
+ if (!op.startsWith("composition_completed")) return null;
16748
+ const details = sourceDetails(detail.source_audit_entry);
16749
+ if (!details) return null;
16750
+ const receiptRaw = details["receipt"];
16751
+ const sourceStateRaw = details["source_state_snapshot"];
16752
+ if (receiptRaw === void 0) return null;
16753
+ const transferred = parseExplicitContextItems(receiptRaw);
16754
+ const withheld = [];
16755
+ if (Array.isArray(sourceStateRaw)) {
16756
+ const transferredKeys = new Set(
16757
+ transferred.map((t) => `${t.category}:${t.summary}`)
16758
+ );
16759
+ for (const item of parseExplicitContextItems(sourceStateRaw)) {
16760
+ const key = `${item.category}:${item.summary}`;
16761
+ if (!transferredKeys.has(key)) withheld.push(item);
16762
+ }
16763
+ }
16764
+ return {
16765
+ handoff_entry_id: detail.entry.entry_id,
16766
+ transferred,
16767
+ withheld,
16768
+ source: "composition",
16769
+ confidence: 0.9
16770
+ };
16771
+ }
16772
+ function tryHeuristicPath(detail) {
16773
+ const entry = detail.entry;
16774
+ const audit = detail.source_audit_entry;
16775
+ const details = sourceDetails(audit);
16776
+ if (audit.operation === "cross_harness_approval_aggregated") {
16777
+ const ruleId = optString2(details, "policy_rule_id");
16778
+ if (ruleId) {
16779
+ const category = categoryFromPolicyRuleId(ruleId);
16780
+ const summary = `${ruleId} (${entry.source_agent_id} -> operator)`;
16781
+ return {
16782
+ handoff_entry_id: entry.entry_id,
16783
+ transferred: [
16784
+ {
16785
+ category,
16786
+ summary: truncate(summary, SUMMARY_MAX_CHARS),
16787
+ size_hint: "minimal"
16788
+ }
16789
+ ],
16790
+ withheld: [],
16791
+ source: "heuristic",
16792
+ confidence: 0.5
16793
+ };
16794
+ }
16795
+ }
16796
+ if (audit.operation === "v1.1_local_handoff") {
16797
+ const reasonClass = optString2(details, "reason_class");
16798
+ const newStatus = optString2(details, "new_status");
16799
+ const previousStatus = optString2(details, "previous_status");
16800
+ const transferred = [];
16801
+ const withheld = [];
16802
+ if (newStatus === "denied" || newStatus === "failed") {
16803
+ withheld.push({
16804
+ category: "other",
16805
+ summary: truncate(
16806
+ `handoff ${newStatus}${reasonClass ? ` (${reasonClass})` : ""}: ${entry.source_agent_id} -> ${entry.target_agent_id}`,
16807
+ SUMMARY_MAX_CHARS
16808
+ ),
16809
+ size_hint: "minimal"
16810
+ });
16811
+ } else if (newStatus === "accepted" || newStatus === "completed") {
16812
+ transferred.push({
16813
+ category: "other",
16814
+ summary: truncate(
16815
+ `handoff ${newStatus}${previousStatus ? ` (from ${previousStatus})` : ""}: ${entry.source_agent_id} -> ${entry.target_agent_id}`,
16816
+ SUMMARY_MAX_CHARS
16817
+ ),
16818
+ size_hint: "small"
16819
+ });
16820
+ } else {
16821
+ transferred.push({
16822
+ category: "other",
16823
+ summary: truncate(
16824
+ `handoff ${entry.source_agent_id} -> ${entry.target_agent_id}${newStatus ? ` (${newStatus})` : ""}`,
16825
+ SUMMARY_MAX_CHARS
16826
+ ),
16827
+ size_hint: "minimal"
16828
+ });
16829
+ }
16830
+ return {
16831
+ handoff_entry_id: entry.entry_id,
16832
+ transferred,
16833
+ withheld,
16834
+ source: "heuristic",
16835
+ confidence: reasonClass || newStatus ? 0.5 : 0.3
16836
+ };
16837
+ }
16838
+ return {
16839
+ handoff_entry_id: entry.entry_id,
16840
+ transferred: [
16841
+ {
16842
+ category: "other",
16843
+ summary: truncate(
16844
+ `handoff ${entry.source_agent_id} -> ${entry.target_agent_id}`,
16845
+ SUMMARY_MAX_CHARS
16846
+ ),
16847
+ size_hint: "minimal"
16848
+ }
16849
+ ],
16850
+ withheld: [],
16851
+ source: "heuristic",
16852
+ confidence: 0.3
16853
+ };
16854
+ }
16855
+ async function tryLlmAssistPath(detail, selector) {
16856
+ const entry = detail.entry;
16857
+ const audit = detail.source_audit_entry;
16858
+ const probe = `event=${audit.operation} sender=${entry.source_agent_id} target=${entry.target_agent_id} summary=${entry.context_transfer_summary}`;
16859
+ try {
16860
+ const response = await selector.invokeClassify("sentinel-scoring", {
16861
+ kind: "classify",
16862
+ items: [probe],
16863
+ categories: [...CATEGORY_VALUES]
16864
+ });
16865
+ if (response.body.kind !== "classify") return null;
16866
+ const top = response.body.results[0];
16867
+ if (!top || !isCategory(top.category) || top.confidence < 0.4) {
16868
+ return null;
16869
+ }
16870
+ return {
16871
+ handoff_entry_id: entry.entry_id,
16872
+ transferred: [
16873
+ {
16874
+ category: top.category,
16875
+ summary: truncate(
16876
+ `LLM-classified handoff ${entry.source_agent_id} -> ${entry.target_agent_id}: ${top.category} (confidence ${top.confidence.toFixed(2)})`,
16877
+ SUMMARY_MAX_CHARS
16878
+ ),
16879
+ size_hint: "minimal"
16880
+ }
16881
+ ],
16882
+ withheld: [],
16883
+ source: "llm-assist",
16884
+ confidence: 0.6
16885
+ };
16886
+ } catch {
16887
+ return null;
16888
+ }
16889
+ }
16890
+ function sourceDetails(audit) {
16891
+ return audit.details;
16892
+ }
16893
+ function optString2(details, key) {
16894
+ if (!details) return null;
16895
+ const value = details[key];
16896
+ if (typeof value !== "string" || value.length === 0) return null;
16897
+ return value;
16898
+ }
16899
+ function isCategory(value) {
16900
+ return CATEGORY_VALUES.includes(value);
16901
+ }
16902
+ function truncate(s, cap) {
16903
+ return s.length <= cap ? s : `${s.slice(0, cap - 3)}...`;
16904
+ }
16905
+ function parseExplicitContextItems(raw) {
16906
+ if (raw === null || raw === void 0) return [];
16907
+ if (Array.isArray(raw)) {
16908
+ const out = [];
16909
+ for (const entry of raw) {
16910
+ if (typeof entry === "string") {
16911
+ out.push({
16912
+ category: "other",
16913
+ summary: truncate(entry, SUMMARY_MAX_CHARS),
16914
+ size_hint: "minimal"
16915
+ });
16916
+ continue;
16917
+ }
16918
+ if (entry && typeof entry === "object") {
16919
+ const obj = entry;
16920
+ const category = isCategoryValue(obj["category"]) ? obj["category"] : "other";
16921
+ const summary = typeof obj["summary"] === "string" ? truncate(obj["summary"], SUMMARY_MAX_CHARS) : "(unspecified)";
16922
+ const sizeHint = isSizeHintValue(obj["size_hint"]) ? obj["size_hint"] : "minimal";
16923
+ out.push({ category, summary, size_hint: sizeHint });
16924
+ }
16925
+ }
16926
+ return out;
16927
+ }
16928
+ if (typeof raw === "object" && raw !== null) {
16929
+ const out = [];
16930
+ for (const [k, v] of Object.entries(raw)) {
16931
+ const category = isCategoryValue(k) ? k : "other";
16932
+ if (Array.isArray(v)) {
16933
+ for (const item of v) {
16934
+ if (typeof item === "string") {
16935
+ out.push({
16936
+ category,
16937
+ summary: truncate(item, SUMMARY_MAX_CHARS),
16938
+ size_hint: "minimal"
16939
+ });
16940
+ }
16941
+ }
16942
+ }
16943
+ }
16944
+ return out;
16945
+ }
16946
+ return [];
16947
+ }
16948
+ function isCategoryValue(v) {
16949
+ return typeof v === "string" && CATEGORY_VALUES.includes(v);
16950
+ }
16951
+ function isSizeHintValue(v) {
16952
+ return typeof v === "string" && (v === "minimal" || v === "small" || v === "medium" || v === "large");
16953
+ }
16954
+ function categoryFromPolicyRuleId(ruleId) {
16955
+ const lower = ruleId.toLowerCase();
16956
+ if (lower.includes("credential") || lower.includes("broker_secret")) {
16957
+ return "credentials";
16958
+ }
16959
+ if (lower.includes("memory") || lower.includes("state_read")) {
16960
+ return "memory";
16961
+ }
16962
+ if (lower.includes("plan")) {
16963
+ return "plans";
16964
+ }
16965
+ if (lower.includes("export") || lower.includes("output")) {
16966
+ return "outputs";
16967
+ }
16968
+ if (lower.includes("audit")) {
16969
+ return "audit-refs";
16970
+ }
16971
+ return "other";
16972
+ }
16973
+ var CONTEXT_TRANSFER_AUDIT_OPS = {
16974
+ DECODED: "operator_handoff_context_transfer_decoded"
16975
+ };
16976
+
16707
16977
  // src/coordination/handoff-routes.ts
16708
16978
  var COORDINATION_API_PREFIX = "/api/coordination";
16709
16979
  var COORDINATION_HANDOFFS_PREFIX = "/api/coordination/handoffs";
@@ -16847,7 +17117,29 @@ async function handleCoordinationRoute(deps, req, res) {
16847
17117
  target_agent_id: detail.entry.target_agent_id
16848
17118
  }
16849
17119
  );
16850
- writeJSON6(res, 200, { ok: true, data: detail });
17120
+ let breakdown = null;
17121
+ try {
17122
+ breakdown = await extractContextTransferBreakdown(
17123
+ detail,
17124
+ deps.contextTransfer ?? {}
17125
+ );
17126
+ deps.auditLog.append(
17127
+ "l2",
17128
+ CONTEXT_TRANSFER_AUDIT_OPS.DECODED,
17129
+ deps.operatorId,
17130
+ {
17131
+ fortress_id: deps.handoffLog.getFortressId(),
17132
+ entry_id: detail.entry.entry_id,
17133
+ extractor_path: breakdown.source,
17134
+ confidence: breakdown.confidence,
17135
+ transferred_count: breakdown.transferred.length,
17136
+ withheld_count: breakdown.withheld.length
17137
+ }
17138
+ );
17139
+ } catch {
17140
+ }
17141
+ const responseData = breakdown !== null ? { ...detail, context_transfer_breakdown: breakdown } : detail;
17142
+ writeJSON6(res, 200, { ok: true, data: responseData });
16851
17143
  return true;
16852
17144
  }
16853
17145
  writeJSON6(res, 404, { ok: false, error: "not_found", path });
@@ -21304,13 +21596,33 @@ var SentinelDispatcher = class {
21304
21596
  }
21305
21597
  }
21306
21598
  };
21599
+
21600
+ // src/anomaly-detection/classifier-state-store.ts
21601
+ init_encryption();
21602
+ init_encoding();
21603
+
21604
+ // src/anomaly-detection/classifiers/cusum.ts
21605
+ var CUSUM_CLASSIFIER_ID = "cusum";
21606
+
21607
+ // src/anomaly-detection/classifiers/psi.ts
21608
+ var PSI_CLASSIFIER_ID = "psi";
21609
+
21610
+ // src/anomaly-detection/anomaly-pipeline.ts
21307
21611
  var ANOMALY_AUDIT_OPS = {
21308
21612
  DETECTOR_REGISTERED: "anomaly_detector_registered",
21309
21613
  DETECTOR_UNREGISTERED: "anomaly_detector_unregistered",
21310
21614
  FINDING_EMITTED: "anomaly_finding_emitted",
21311
21615
  EVALUATION_FAILED: "anomaly_evaluation_failed",
21312
21616
  TRAINING_COMPLETED: "anomaly_training_completed",
21313
- TRAINING_FAILED: "anomaly_training_failed"
21617
+ TRAINING_FAILED: "anomaly_training_failed",
21618
+ /** Chi-2: a classifier was attached to an existing detector. */
21619
+ CLASSIFIER_SUBSCRIBED: "anomaly_classifier_subscribed",
21620
+ /** Chi-2: a classifier was detached from an existing detector. */
21621
+ CLASSIFIER_UNSUBSCRIBED: "anomaly_classifier_unsubscribed",
21622
+ /** Chi-2: CUSUM-flagged mean-shift drift on a per-agent feature. */
21623
+ CUSUM_DRIFT_DETECTED: "anomaly_cusum_drift_detected",
21624
+ /** Chi-2: PSI-flagged distribution shift on a per-agent feature. */
21625
+ PSI_DISTRIBUTION_SHIFT_DETECTED: "anomaly_psi_distribution_shift_detected"
21314
21626
  };
21315
21627
  var DEFAULT_TICK_INTERVAL_MS2 = 6e4;
21316
21628
  var AnomalyPipelineDispatcher = class {
@@ -21401,34 +21713,37 @@ var AnomalyPipelineDispatcher = class {
21401
21713
  const stamped = await this.routeFinding(detectorId, raw);
21402
21714
  findings.push(stamped);
21403
21715
  }
21404
- try {
21405
- const trainingResult = await detector.classifier.train();
21406
- this.auditLog.append(
21407
- "l2",
21408
- ANOMALY_AUDIT_OPS.TRAINING_COMPLETED,
21409
- this.identityId,
21410
- {
21411
- detector_id: detectorId,
21412
- classifier_id: detector.classifier.classifierId,
21413
- trained_at: trainingResult.trained_at,
21414
- sample_count: trainingResult.sample_count,
21415
- agent_count: trainingResult.agent_count,
21416
- fortress_id: this.fortressId
21417
- }
21418
- );
21419
- } catch (trainErr) {
21420
- const message = trainErr instanceof Error ? trainErr.message : String(trainErr);
21421
- this.auditLog.append(
21422
- "l2",
21423
- ANOMALY_AUDIT_OPS.TRAINING_FAILED,
21424
- this.identityId,
21425
- {
21426
- detector_id: detectorId,
21427
- error_message: message,
21428
- fortress_id: this.fortressId
21429
- },
21430
- "failure"
21431
- );
21716
+ for (const classifier of detector.getAllClassifiers()) {
21717
+ try {
21718
+ const trainingResult = await classifier.train();
21719
+ this.auditLog.append(
21720
+ "l2",
21721
+ ANOMALY_AUDIT_OPS.TRAINING_COMPLETED,
21722
+ this.identityId,
21723
+ {
21724
+ detector_id: detectorId,
21725
+ classifier_id: classifier.classifierId,
21726
+ trained_at: trainingResult.trained_at,
21727
+ sample_count: trainingResult.sample_count,
21728
+ agent_count: trainingResult.agent_count,
21729
+ fortress_id: this.fortressId
21730
+ }
21731
+ );
21732
+ } catch (trainErr) {
21733
+ const message = trainErr instanceof Error ? trainErr.message : String(trainErr);
21734
+ this.auditLog.append(
21735
+ "l2",
21736
+ ANOMALY_AUDIT_OPS.TRAINING_FAILED,
21737
+ this.identityId,
21738
+ {
21739
+ detector_id: detectorId,
21740
+ classifier_id: classifier.classifierId,
21741
+ error_message: message,
21742
+ fortress_id: this.fortressId
21743
+ },
21744
+ "failure"
21745
+ );
21746
+ }
21432
21747
  }
21433
21748
  } catch (err) {
21434
21749
  const message = err instanceof Error ? err.message : String(err);
@@ -21491,6 +21806,7 @@ var AnomalyPipelineDispatcher = class {
21491
21806
  observed_at: raw.observed_at || this.now().toISOString()
21492
21807
  };
21493
21808
  await this.findingStore.saveFinding(stamped);
21809
+ const classifierId = stamped.details["classifier_id"] ?? null;
21494
21810
  this.auditLog.append(
21495
21811
  "l2",
21496
21812
  ANOMALY_AUDIT_OPS.FINDING_EMITTED,
@@ -21500,13 +21816,79 @@ var AnomalyPipelineDispatcher = class {
21500
21816
  finding_id: stamped.finding_id,
21501
21817
  severity: stamped.severity,
21502
21818
  anomaly_score: stamped.details["anomaly_score"] ?? null,
21819
+ ...classifierId !== null ? { classifier_id: classifierId } : {},
21503
21820
  ...stamped.agent_id !== void 0 ? { agent_id: stamped.agent_id } : {},
21504
21821
  fortress_id: this.fortressId
21505
21822
  }
21506
21823
  );
21824
+ const specificOp = classifierSpecificAuditOp(classifierId);
21825
+ if (specificOp !== null) {
21826
+ this.auditLog.append("l2", specificOp, this.identityId, {
21827
+ detector_id: detectorId,
21828
+ finding_id: stamped.finding_id,
21829
+ severity: stamped.severity,
21830
+ anomaly_score: stamped.details["anomaly_score"] ?? null,
21831
+ ...stamped.agent_id !== void 0 ? { agent_id: stamped.agent_id } : {},
21832
+ fortress_id: this.fortressId
21833
+ });
21834
+ }
21507
21835
  this.emit({ type: "finding", finding: stamped });
21508
21836
  return stamped;
21509
21837
  }
21838
+ /**
21839
+ * Chi-2: attach an additional classifier to an already-registered
21840
+ * detector. Emits ANOMALY_CLASSIFIER_SUBSCRIBED on success. The
21841
+ * factory is called with the fortress AnomalyContext so the
21842
+ * classifier can build its own state-store binding. Idempotent: a
21843
+ * second call with the same classifierId returns false.
21844
+ */
21845
+ async addClassifierToDetector(detectorId, factory) {
21846
+ const detector = this.detectors.get(detectorId);
21847
+ if (!detector) return false;
21848
+ const context = {
21849
+ fortressId: this.fortressId,
21850
+ auditLog: this.auditLog,
21851
+ storage: this.storage,
21852
+ masterKey: this.masterKey,
21853
+ now: this.now
21854
+ };
21855
+ const classifier = factory(context);
21856
+ const added = detector.addClassifier(classifier);
21857
+ if (!added) return false;
21858
+ this.auditLog.append(
21859
+ "l2",
21860
+ ANOMALY_AUDIT_OPS.CLASSIFIER_SUBSCRIBED,
21861
+ this.identityId,
21862
+ {
21863
+ detector_id: detectorId,
21864
+ classifier_id: classifier.classifierId,
21865
+ fortress_id: this.fortressId
21866
+ }
21867
+ );
21868
+ return true;
21869
+ }
21870
+ /**
21871
+ * Chi-2: detach an additional classifier from an already-registered
21872
+ * detector. Emits ANOMALY_CLASSIFIER_UNSUBSCRIBED on success. The
21873
+ * primary classifier cannot be detached (returns false).
21874
+ */
21875
+ async removeClassifierFromDetector(detectorId, classifierId) {
21876
+ const detector = this.detectors.get(detectorId);
21877
+ if (!detector) return false;
21878
+ const removed = detector.removeClassifier(classifierId);
21879
+ if (!removed) return false;
21880
+ this.auditLog.append(
21881
+ "l2",
21882
+ ANOMALY_AUDIT_OPS.CLASSIFIER_UNSUBSCRIBED,
21883
+ this.identityId,
21884
+ {
21885
+ detector_id: detectorId,
21886
+ classifier_id: classifierId,
21887
+ fortress_id: this.fortressId
21888
+ }
21889
+ );
21890
+ return true;
21891
+ }
21510
21892
  emit(event) {
21511
21893
  for (const listener of this.listeners) {
21512
21894
  try {
@@ -21516,6 +21898,16 @@ var AnomalyPipelineDispatcher = class {
21516
21898
  }
21517
21899
  }
21518
21900
  };
21901
+ function classifierSpecificAuditOp(classifierId) {
21902
+ if (classifierId === null) return null;
21903
+ if (classifierId === CUSUM_CLASSIFIER_ID) {
21904
+ return ANOMALY_AUDIT_OPS.CUSUM_DRIFT_DETECTED;
21905
+ }
21906
+ if (classifierId === PSI_CLASSIFIER_ID) {
21907
+ return ANOMALY_AUDIT_OPS.PSI_DISTRIBUTION_SHIFT_DETECTED;
21908
+ }
21909
+ return null;
21910
+ }
21519
21911
 
21520
21912
  // src/sentinel/sentinel.ts
21521
21913
  var Sentinel = class {
@@ -38195,6 +38587,136 @@ function tryParseClassification3(text) {
38195
38587
  }
38196
38588
  }
38197
38589
 
38590
+ // src/query-anonymity/header-strip.ts
38591
+ var QUERY_ANONYMITY_AUDIT_OPS = {
38592
+ HEADERS_STRIPPED: "query_anonymity_headers_stripped"
38593
+ };
38594
+ var CANONICAL_STRIP_LIST = [
38595
+ // Browser / runtime fingerprinting.
38596
+ { name: "user-agent", reason: "user-agent" },
38597
+ { name: "sec-ch-ua", reason: "fingerprintable-extension" },
38598
+ { name: "sec-ch-ua-mobile", reason: "fingerprintable-extension" },
38599
+ { name: "sec-ch-ua-platform", reason: "fingerprintable-extension" },
38600
+ { name: "sec-ch-ua-platform-version", reason: "fingerprintable-extension" },
38601
+ { name: "sec-ch-ua-arch", reason: "fingerprintable-extension" },
38602
+ { name: "sec-ch-ua-bitness", reason: "fingerprintable-extension" },
38603
+ { name: "sec-ch-ua-model", reason: "fingerprintable-extension" },
38604
+ { name: "sec-ch-ua-full-version-list", reason: "fingerprintable-extension" },
38605
+ // Locale fingerprint.
38606
+ { name: "accept-language", reason: "locale-fingerprint" },
38607
+ // Request-origin leak.
38608
+ { name: "referer", reason: "leaking-network-info" },
38609
+ { name: "referrer-policy", reason: "leaking-network-info" },
38610
+ { name: "origin", reason: "leaking-network-info" },
38611
+ // Forwarded-by / IP-derived network info.
38612
+ { name: "via", reason: "leaking-network-info" },
38613
+ { name: "forwarded", reason: "leaking-network-info" },
38614
+ { name: "x-forwarded-for", reason: "leaking-network-info" },
38615
+ { name: "x-real-ip", reason: "leaking-network-info" },
38616
+ { name: "x-client-ip", reason: "leaking-network-info" },
38617
+ // DNT / GPC are technically anti-tracking signals but they
38618
+ // themselves form a fingerprint (operators who set DNT=1 are a
38619
+ // smaller subset). Strip to keep the substrate ignorant of
38620
+ // operator preferences.
38621
+ { name: "dnt", reason: "unnecessary-metadata" },
38622
+ { name: "sec-gpc", reason: "unnecessary-metadata" }
38623
+ ];
38624
+ var REQUIRED_HEADERS = [
38625
+ "authorization",
38626
+ "content-type",
38627
+ "content-length",
38628
+ "host",
38629
+ "accept",
38630
+ "x-api-key",
38631
+ // Anthropic API auth
38632
+ "anthropic-version",
38633
+ // Anthropic API contract version
38634
+ "anthropic-beta",
38635
+ // optional Anthropic beta opt-in
38636
+ "openai-organization",
38637
+ // optional OpenAI org id
38638
+ "x-stainless-package-version",
38639
+ // allowed for Anthropic + OpenAI SDK contract compat
38640
+ "x-goog-api-key",
38641
+ // Google AI Studio
38642
+ "x-goog-user-project"
38643
+ // Google AI Studio
38644
+ ];
38645
+ var REQUIRED_HEADER_SET = new Set(
38646
+ REQUIRED_HEADERS.map((h) => h.toLowerCase())
38647
+ );
38648
+ var STRIP_REASON_BY_NAME = new Map(
38649
+ CANONICAL_STRIP_LIST.map((h) => [h.name.toLowerCase(), h.reason])
38650
+ );
38651
+ function stripHeaders(headers) {
38652
+ const stripped = {};
38653
+ const removed = [];
38654
+ for (const [name, value] of Object.entries(headers)) {
38655
+ const lower = name.toLowerCase();
38656
+ if (REQUIRED_HEADER_SET.has(lower)) {
38657
+ stripped[name] = value;
38658
+ continue;
38659
+ }
38660
+ const reason = STRIP_REASON_BY_NAME.get(lower);
38661
+ if (reason !== void 0) {
38662
+ removed.push({ name, reason });
38663
+ continue;
38664
+ }
38665
+ stripped[name] = value;
38666
+ }
38667
+ return { stripped, removed };
38668
+ }
38669
+ function defeatUndiciDefaultsInto(headers) {
38670
+ if (headers["user-agent"] === void 0 && headers["User-Agent"] === void 0) {
38671
+ headers["User-Agent"] = "";
38672
+ }
38673
+ if (headers["accept-language"] === void 0 && headers["Accept-Language"] === void 0) {
38674
+ headers["Accept-Language"] = "";
38675
+ }
38676
+ return headers;
38677
+ }
38678
+ function createAnonymizedFetch(baseFetch, onAudit) {
38679
+ const wrapped = async (input, init) => {
38680
+ const headers = normalizeHeadersInit(init?.headers);
38681
+ const result = stripHeaders(headers);
38682
+ defeatUndiciDefaultsInto(result.stripped);
38683
+ const preservedRequired = Object.keys(result.stripped).filter(
38684
+ (k) => REQUIRED_HEADER_SET.has(k.toLowerCase())
38685
+ );
38686
+ const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
38687
+ const method = init?.method ?? (input instanceof Request ? input.method : "GET");
38688
+ if (onAudit) {
38689
+ onAudit({
38690
+ url,
38691
+ method,
38692
+ stripped_count: result.removed.length,
38693
+ removed: result.removed,
38694
+ required_preserved: preservedRequired
38695
+ });
38696
+ }
38697
+ return baseFetch(input, { ...init, headers: result.stripped });
38698
+ };
38699
+ return wrapped;
38700
+ }
38701
+ function normalizeHeadersInit(raw) {
38702
+ if (raw === void 0) return {};
38703
+ if (typeof Headers !== "undefined" && raw instanceof Headers) {
38704
+ const out = {};
38705
+ raw.forEach((value, key) => {
38706
+ out[key] = value;
38707
+ });
38708
+ return out;
38709
+ }
38710
+ if (Array.isArray(raw)) {
38711
+ const out = {};
38712
+ for (const [k, v] of raw) {
38713
+ if (k !== void 0 && v !== void 0) out[k] = v;
38714
+ }
38715
+ return out;
38716
+ }
38717
+ return { ...raw };
38718
+ }
38719
+
38198
38720
  // src/intelligence/substrates/hybrid/per-surface-router.ts
38199
38721
  function resolveHybridChoice(rules, surface) {
38200
38722
  if (!rules) return null;
@@ -38255,7 +38777,21 @@ var SubstrateSelector = class {
38255
38777
  this.auditLog = cfg.auditLog;
38256
38778
  this.identityId = cfg.identityId;
38257
38779
  this.redactor = cfg.redactor ?? IDENTITY_REDACTOR;
38258
- this.fetchImpl = cfg.fetchImpl;
38780
+ const baseFetch = cfg.fetchImpl ?? globalThis.fetch;
38781
+ this.fetchImpl = createAnonymizedFetch(baseFetch, (event) => {
38782
+ this.auditLog.append(
38783
+ "l2",
38784
+ QUERY_ANONYMITY_AUDIT_OPS.HEADERS_STRIPPED,
38785
+ this.identityId,
38786
+ {
38787
+ url: event.url,
38788
+ method: event.method,
38789
+ stripped_count: event.stripped_count,
38790
+ removed: event.removed,
38791
+ required_preserved: event.required_preserved
38792
+ }
38793
+ );
38794
+ });
38259
38795
  this.config = buildDefaultConfig();
38260
38796
  }
38261
38797
  /**