File size: 8,799 Bytes
ff78003
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/**
 * adapter-coverage — 4 真适配器各自的 task-required 行为测试。
 *
 * 单元(无 DB):
 *   - causal extractCI / extractScore — pooled_estimate JSON 多种约定
 *
 * 集成(真 DB,自动 skip 当 DATABASE_URL 未设):
 *   - causal bucket_key 不匹配返空 + reason='bucket_key_no_match'
 *   - drug target_id-only 走 target → drugs 路径(可附带 2-hop outcomes)
 *   - internal-experience 默认排除 caller(sourceMetadata.excludedSelf=true)
 *   - internal-experience include_self=true 时不排除
 */
import test from "node:test";
import assert from "node:assert/strict";

import { extractCI, extractScore, causalAdapter } from "../causal.adapter.ts";
import { drugAdapter } from "../drug.adapter.ts";
import { internalExperienceAdapter } from "../internal-experience.adapter.ts";
import { _resetBudgetCounters } from "../index.ts";

const HAS_DB = Boolean(process.env["DATABASE_URL"]);

test.beforeEach(() => {
  _resetBudgetCounters();
});

// ---------- causal pure-function unit tests ----------

test("causal.extractCI — { ci: [lo, hi] } 数组形式", () => {
  assert.deepEqual(extractCI({ ci: [0.2, 0.8] }), [0.2, 0.8]);
});

test("causal.extractCI — { ci_low, ci_high } 形式", () => {
  assert.deepEqual(extractCI({ ci_low: -1.5, ci_high: 2.5 }), [-1.5, 2.5]);
});

test("causal.extractCI — { lo, hi } 简写形式", () => {
  assert.deepEqual(extractCI({ lo: 0, hi: 1 }), [0, 1]);
});

test("causal.extractCI — { lower, upper } 学术形式", () => {
  assert.deepEqual(extractCI({ lower: 0.1, upper: 0.9 }), [0.1, 0.9]);
});

test("causal.extractCI — 缺失 / 非对象 → null,不假装", () => {
  assert.equal(extractCI(null), null);
  assert.equal(extractCI(undefined), null);
  assert.equal(extractCI({}), null);
  assert.equal(extractCI({ ci: [1] }), null); // 长度不对
  assert.equal(extractCI({ ci: ["a", "b"] }), null); // 类型不对
  assert.equal(extractCI("not_an_object"), null);
});

test("causal.extractScore — value > estimate > mean > score 优先级", () => {
  assert.equal(extractScore({ value: 0.42, estimate: 0.99 }), 0.42);
  assert.equal(extractScore({ estimate: 0.7 }), 0.7);
  assert.equal(extractScore({ mean: -0.1 }), -0.1);
  assert.equal(extractScore({ score: 3.14 }), 3.14);
  assert.equal(extractScore({}), null);
  assert.equal(extractScore({ value: "not-a-number" }), null);
  assert.equal(extractScore({ value: NaN }), null);
});

// ---------- DB-backed integration tests (skip when no DATABASE_URL) ----------

test("causal — bucket_key 不匹配返空 + reason='bucket_key_no_match'", { skip: !HAS_DB }, async () => {
  // 用一个肯定不存在的 jsonb 做 key
  const r = await causalAdapter.query({
    kind: "causal_network",
    capabilityId: "cap_test_causal_bk",
    params: { bucket_key: { __test_marker__: "this_key_does_not_exist_xyzzy_42" } },
  });
  assert.equal(r.items.length, 0);
  assert.equal(
    (r.sourceMetadata as Record<string, unknown>)["reason"],
    "bucket_key_no_match",
  );
});

test("causal — score_min/max 入 SQL 不报错(空结果也 OK)", { skip: !HAS_DB }, async () => {
  const r = await causalAdapter.query({
    kind: "causal_network",
    capabilityId: "cap_test_causal_score",
    params: { score_min: -1e9, score_max: 1e9 },
    limit: 5,
  });
  // 不 throw 即通过(items 数随真 DB 状态)
  assert.ok(Array.isArray(r.items));
  assert.equal(r.kind, "causal_network");
});

test("drug — target_id-only 路径不 throw(走 target → drugs/outcomes)", { skip: !HAS_DB }, async () => {
  // 任意不存在的 target_id 也应该走完路径返空,不应该 throw
  const r = await drugAdapter.query({
    kind: "drug_network",
    capabilityId: "cap_test_drug_target",
    params: { target_id: "TARGET:nonexistent_xyzzy" },
    limit: 5,
  });
  assert.ok(Array.isArray(r.items));
  assert.equal(r.kind, "drug_network");
  assert.equal(
    ((r.sourceMetadata as Record<string, unknown>)["filters"] as Record<string, unknown>)[
      "target_id"
    ],
    "TARGET:nonexistent_xyzzy",
  );
});

test("internal-experience — 默认 sourceMetadata.excludedSelf=true", { skip: !HAS_DB }, async () => {
  const r = await internalExperienceAdapter.query({
    kind: "internal_experience",
    capabilityId: "cap_caller_self_test",
    params: {}, // no include_self
    limit: 5,
  });
  const meta = r.sourceMetadata as Record<string, unknown>;
  assert.equal(meta["excludedSelf"], true);
  assert.equal(meta["callerCapability"], "cap_caller_self_test");
});

test("internal-experience — include_self=true 时 excludedSelf=false", { skip: !HAS_DB }, async () => {
  const r = await internalExperienceAdapter.query({
    kind: "internal_experience",
    capabilityId: "cap_caller_self_test_2",
    params: { include_self: true },
    limit: 5,
  });
  const meta = r.sourceMetadata as Record<string, unknown>;
  assert.equal(meta["excludedSelf"], false);
});

test(
  "internal-experience — 不存在的 capability_id 参数返空 items 但 sourceMetadata 完整(空表语义)",
  { skip: !HAS_DB },
  async () => {
    // capability_data_foundation 在 B2 阶段 B7 才写入,所以本任务中绝大多数
    // capability_id 都查不到行。验证 adapter 在"空表"语义下不假装有数据,
    // sourceMetadata 仍如实返回 caller / kindFilter / excludedSelf。
    const bogus = `cap_does_not_exist_${Date.now()}_${Math.random().toString(36).slice(2)}`;
    const r = await internalExperienceAdapter.query({
      kind: "internal_experience",
      capabilityId: "cap_caller_empty_table",
      params: { capability_id: bogus },
      limit: 5,
    });
    assert.deepEqual(r.items, []);
    assert.equal(r.cursor, null);
    const meta = r.sourceMetadata as Record<string, unknown>;
    assert.equal(meta["callerCapability"], "cap_caller_empty_table");
    assert.equal(meta["filteredCapability"], bogus);
    // excludedSelf 默认 true,因为 caller != filteredCapability 时也保留语义
    assert.equal(meta["excludedSelf"], true);
  },
);

test(
  "internal-experience — kind 过滤进 SQL where 子句(不存在的 kind 返空)",
  { skip: !HAS_DB },
  async () => {
    const r = await internalExperienceAdapter.query({
      kind: "internal_experience",
      capabilityId: "cap_caller_kind_filter",
      params: { kind: `__nonexistent_kind_xyzzy_${Date.now()}__` },
      limit: 5,
    });
    assert.deepEqual(r.items, []);
    const meta = r.sourceMetadata as Record<string, unknown>;
    // adapter 把 kindFilter 透传到 sourceMetadata,证明 where 子句真的进了 SQL
    assert.ok(
      typeof meta["kindFilter"] === "string" &&
        (meta["kindFilter"] as string).startsWith("__nonexistent_kind_"),
      `expected kindFilter passthrough in sourceMetadata, got ${JSON.stringify(meta)}`,
    );
  },
);

test(
  "internal-experience — invalid since 字符串:sinceFilterApplied=false(反 metadata 撒谎)",
  { skip: !HAS_DB },
  async () => {
    // architect caveat #6 fix:caller 传了 since 但解析失败时,sourceMetadata
    // 必须老实告诉 caller "我没用",绝不能 echo 个 sinceFilter 假装应用了。
    const r = await internalExperienceAdapter.query({
      kind: "internal_experience",
      capabilityId: "cap_caller_invalid_since",
      params: { since: "this-is-not-a-date" },
      limit: 5,
    });
    const meta = r.sourceMetadata as Record<string, unknown>;
    assert.equal(meta["sinceProvided"], "this-is-not-a-date");
    assert.equal(
      meta["sinceFilterApplied"],
      false,
      "invalid since 必须 sinceFilterApplied=false,否则 metadata 撒谎",
    );
  },
);

test(
  "internal-experience — 合法 since 字符串:sinceFilterApplied=true",
  { skip: !HAS_DB },
  async () => {
    const r = await internalExperienceAdapter.query({
      kind: "internal_experience",
      capabilityId: "cap_caller_valid_since",
      params: { since: "2020-01-01T00:00:00Z" },
      limit: 5,
    });
    const meta = r.sourceMetadata as Record<string, unknown>;
    assert.equal(meta["sinceProvided"], "2020-01-01T00:00:00Z");
    assert.equal(meta["sinceFilterApplied"], true);
  },
);

test(
  "drug — drug_id-only 路径不 throw(走 drug → targets/outcomes/trials)",
  { skip: !HAS_DB },
  async () => {
    // 任意不存在的 drug_id 也应该走完路径返空,不应该 throw
    const r = await drugAdapter.query({
      kind: "drug_network",
      capabilityId: "cap_test_drug_only",
      params: { drug_id: "DRUG:nonexistent_xyzzy" },
      limit: 5,
    });
    assert.ok(Array.isArray(r.items));
    assert.equal(r.kind, "drug_network");
    assert.equal(
      ((r.sourceMetadata as Record<string, unknown>)["filters"] as Record<string, unknown>)[
        "drug_id"
      ],
      "DRUG:nonexistent_xyzzy",
    );
  },
);