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