@danceiny/gotry 0.0.1-rc.18 → 0.0.1-rc.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +42 -16
  2. package/README.zh-CN.md +37 -15
  3. package/bin/gotry-bootstrap.js +309 -30
  4. package/bin/gotry-inner.js +74 -23
  5. package/bin/gotry-runtime-resolution.d.ts +1 -1
  6. package/bin/gotry-runtime-resolution.js +7 -8
  7. package/cordis.gotry-patch.yml +22 -8
  8. package/data/stations-12306-verify.json +524 -0
  9. package/dist/capabilities/agent-reach.js +4 -4
  10. package/dist/capabilities/anything.js +62 -29
  11. package/dist/capabilities/channel-health.js +103 -0
  12. package/dist/capabilities/channel-registry.js +213 -0
  13. package/dist/capabilities/doctor.js +307 -0
  14. package/dist/capabilities/effect.js +178 -5
  15. package/dist/capabilities/flyai.js +13 -0
  16. package/dist/capabilities/hbcli.js +28 -2
  17. package/dist/capabilities/session/adapters/ctrip-hotel.js +207 -0
  18. package/dist/capabilities/session/adapters/rail-12306.js +285 -0
  19. package/dist/capabilities/session/extension-bridge.js +14 -1
  20. package/dist/capabilities/session/extension-channel.js +4 -2
  21. package/dist/capabilities/session/extension-distribution.js +1 -1
  22. package/dist/capabilities/session-search.js +311 -0
  23. package/dist/capabilities/visa-policy.js +126 -0
  24. package/dist/scripts/agent-planning-turn-deadline-e2e.js +305 -0
  25. package/dist/scripts/agent-planning-turn-deadline-tests.js +281 -0
  26. package/dist/scripts/anything-tests.js +70 -21
  27. package/dist/scripts/benchmark-environment-bridge-e2e.js +139 -37
  28. package/dist/scripts/benchmark-environment-bridge-tests.js +1099 -306
  29. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +26 -26
  30. package/dist/scripts/{booking-copilot-availability-policy-v2-tests.js → booking-copilot-availability-policy-tests.js} +115 -115
  31. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +41 -1
  32. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +75 -120
  33. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +370 -61
  34. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +2 -2
  35. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +7 -3
  36. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +15 -9
  37. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +19 -11
  38. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +16 -52
  39. package/dist/scripts/booking-copilot-runtime-proof-tests.js +3953 -155
  40. package/dist/scripts/booking-copilot-server-proof-tests.js +58 -23
  41. package/dist/scripts/booking-copilot-startup-proof-tests.js +10 -119
  42. package/dist/scripts/booking-surface-contract-proof-tests.js +1154 -326
  43. package/dist/scripts/bootstrap-tests.js +113 -2
  44. package/dist/scripts/build-metrics-report.js +339 -0
  45. package/dist/scripts/channel-probe-tests.js +148 -0
  46. package/dist/scripts/channel-probe.js +252 -0
  47. package/dist/scripts/channel-registry-tests.js +262 -0
  48. package/dist/scripts/doctor-tests.js +175 -0
  49. package/dist/scripts/effect-tests.js +274 -1
  50. package/dist/scripts/extension-tests.js +129 -11
  51. package/dist/scripts/fact-gate-tests.js +91 -2
  52. package/dist/scripts/flyai-tests.js +17 -1
  53. package/dist/scripts/hbcli-e2e-tests.js +1 -3
  54. package/dist/scripts/hbcli-tests.js +38 -1
  55. package/dist/scripts/metrics-report-tests.js +288 -0
  56. package/dist/scripts/persona-surface-guard-tests.js +19 -0
  57. package/dist/scripts/session-tests.js +401 -1
  58. package/dist/scripts/smoke.js +100 -83
  59. package/dist/scripts/turn-handoff-collect-tests.js +216 -0
  60. package/dist/scripts/turn-handoff-collect.js +189 -0
  61. package/dist/scripts/turn-policy-tests.js +56 -0
  62. package/dist/scripts/typed-contract-canary.js +261 -0
  63. package/dist/scripts/visa-policy-tests.js +75 -0
  64. package/dist/scripts/wish-channel-gate-tests.js +111 -0
  65. package/dist/src/artifact-gate.js +91 -3
  66. package/dist/src/benchmark-agent-conformance.js +39 -16
  67. package/dist/src/benchmark-environment-bridge.js +316 -52
  68. package/dist/src/bookable-facts.js +62 -3
  69. package/dist/src/booking-surface/{availability-policy-v2.js → availability-policy.js} +89 -89
  70. package/dist/src/booking-surface/canonical-schema.js +8 -22
  71. package/dist/src/booking-surface/contracts.js +70 -19
  72. package/dist/src/booking-surface/dsh-planner.js +310 -177
  73. package/dist/src/booking-surface/dsh-plugin.js +3 -3
  74. package/dist/src/booking-surface/index.js +1 -5
  75. package/dist/src/booking-surface/profile.js +1 -1
  76. package/dist/src/booking-surface/runtime.js +1682 -247
  77. package/dist/src/booking-surface/server.js +371 -185
  78. package/dist/src/booking-surface/startup.js +17 -27
  79. package/dist/src/booking-surface/validation.js +270 -760
  80. package/dist/src/index.js +739 -150
  81. package/dist/src/turn-deadline.js +292 -0
  82. package/dist/src/turn-policy.js +146 -0
  83. package/dist/src/wish-pool.js +5 -0
  84. package/extension/background.js +23 -4
  85. package/extension/content-main.js +47 -9
  86. package/extension/manifest.json +27 -9
  87. package/package.json +7 -26
  88. package/schemas/booking.surface.schema.json +2593 -0
  89. package/ts/capabilities/agent-reach.ts +4 -4
  90. package/ts/capabilities/anything.ts +89 -38
  91. package/ts/capabilities/flyai.ts +21 -3
  92. package/ts/capabilities/hbcli.ts +53 -4
  93. package/ts/capabilities/session/action-cache.ts +1 -1
  94. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  95. package/ts/capabilities/session/adapters/rail-12306.ts +293 -0
  96. package/ts/capabilities/session/extension-bridge.ts +32 -2
  97. package/ts/capabilities/session/extension-channel.ts +9 -8
  98. package/ts/capabilities/session/extension-distribution.ts +3 -1
  99. package/ts/capabilities/session/health-watch.ts +1 -1
  100. package/ts/capabilities/session/read-guard.ts +1 -1
  101. package/ts/capabilities/session/wizard.ts +1 -1
  102. package/ts/capabilities/session-search.ts +323 -1
  103. package/ts/dsh-runtime/vendor/README.md +60 -0
  104. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  105. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +200 -0
  106. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +202 -0
  107. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +216 -0
  108. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  109. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +371 -0
  110. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  111. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +56 -0
  112. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  113. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  114. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +126 -0
  115. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  116. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +109 -0
  117. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +27 -0
  118. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  119. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  120. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +170 -0
  121. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +53 -0
  122. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  123. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  124. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  125. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  126. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +20 -0
  127. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  128. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  129. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  130. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  131. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  132. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +16 -0
  133. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +55 -0
  134. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  135. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +91 -0
  136. package/ts/package.json +9 -0
  137. package/ts/scripts/turn-handoff-collect.ts +178 -0
  138. package/ts/src/artifact-gate.ts +82 -2
  139. package/ts/src/benchmark-agent-conformance.ts +54 -15
  140. package/ts/src/benchmark-environment-bridge.ts +234 -46
  141. package/ts/src/bookable-facts.ts +109 -5
  142. package/ts/src/booking-saga.ts +1 -1
  143. package/ts/src/booking-surface/{availability-policy-v2.ts → availability-policy.ts} +124 -125
  144. package/ts/src/booking-surface/canonical-schema.js +8 -22
  145. package/ts/src/booking-surface/contracts.ts +278 -239
  146. package/ts/src/booking-surface/dsh-planner.ts +333 -194
  147. package/ts/src/booking-surface/dsh-plugin.js +3 -3
  148. package/ts/src/booking-surface/index.ts +1 -5
  149. package/ts/src/booking-surface/profile.ts +11 -11
  150. package/ts/src/booking-surface/runtime.ts +1351 -351
  151. package/ts/src/booking-surface/server.ts +282 -175
  152. package/ts/src/booking-surface/startup.ts +36 -48
  153. package/ts/src/booking-surface/validation.ts +194 -442
  154. package/ts/src/contracts.ts +1 -1
  155. package/ts/src/index.ts +492 -172
  156. package/ts/src/loop.ts +1 -1
  157. package/ts/src/state-ledger.ts +1 -1
  158. package/ts/src/turn-deadline.ts +365 -0
  159. package/ts/src/turn-policy.ts +154 -0
  160. package/ts/src/wish-pool.ts +17 -4
  161. package/dist/scripts/agent-planning-budget-e2e.js +0 -227
  162. package/dist/scripts/agent-planning-budget-tests.js +0 -173
  163. package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +0 -3935
  164. package/dist/scripts/booking-surface-v2-contract-proof-tests.js +0 -1174
  165. package/dist/src/booking-surface/contracts-v2.js +0 -89
  166. package/dist/src/booking-surface/runtime-v2.js +0 -1771
  167. package/dist/src/booking-surface/server-v2.js +0 -334
  168. package/dist/src/booking-surface/validation-v2.js +0 -319
  169. package/dist/src/tool-budget.js +0 -136
  170. package/schemas/booking.surface.v1.schema.json +0 -927
  171. package/schemas/booking.surface.v2.schema.json +0 -61
  172. package/ts/src/booking-surface/contracts-v2.ts +0 -118
  173. package/ts/src/booking-surface/runtime-v2.ts +0 -1466
  174. package/ts/src/booking-surface/server-v2.ts +0 -247
  175. package/ts/src/booking-surface/validation-v2.ts +0 -205
  176. package/ts/src/tool-budget.ts +0 -165
@@ -86,7 +86,44 @@ await writeFile(fallback, JSON.stringify({
86
86
  if (!argLine.includes('destination-name') || !argLine.includes('room-occupancies')) {
87
87
  throw new Error(`FAIL: v0.3.0 旗标未对齐,实际 ${argLine.slice(0, 200)}`);
88
88
  }
89
- console.log('5. v0.3.0 旗标(--destination-name/--room-occupancies)对齐 OK');
89
+ const rd = await searchHotels({
90
+ destination: '普吉',
91
+ checkIn: '2026-09-18',
92
+ checkOut: '2026-09-20'
93
+ }, {
94
+ hbcliBin: echoBin
95
+ });
96
+ const dateLine = JSON.stringify(rd);
97
+ if (!dateLine.includes('check-in') || !dateLine.includes('2026-09-18') || !dateLine.includes('check-out')) {
98
+ throw new Error(`FAIL: 日期旗标未传上游,实际 ${dateLine.slice(0, 240)}`);
99
+ }
100
+ assert.ok(rd.summary.includes('入住 2026-09-18 → 退房 2026-09-20'), 'summary 应回显日期槽位');
101
+ console.log('5. 旗标对齐(--destination-name/--room-occupancies/--check-in/--check-out)OK');
102
+ }{
103
+ const { writeFileSync, chmodSync } = await import('node:fs');
104
+ const listBin = join(tmp, 'hbcli-list');
105
+ writeFileSync(listBin, `#!/bin/sh
106
+ cat <<'JSON'
107
+ {"list":[{"id":461850557,"name":{"en":"Jumeirah Beach Hotel","zh":"朱美拉海滩酒店"},"star":5,"minPrice":{"amount":100,"currency":"USD"}}],"basic":{"sessionId":"s1"}}
108
+ JSON
109
+ `);
110
+ chmodSync(listBin, 0o755);
111
+ const rl = await searchHotels({
112
+ destination: '迪拜',
113
+ checkIn: '2026-09-18',
114
+ checkOut: '2026-09-20'
115
+ }, {
116
+ hbcliBin: listBin
117
+ });
118
+ assert.equal(rl.via, 'hbcli-realtime');
119
+ assert.ok(rl.summary.includes('实时 1 家'), 'summary 应带家数');
120
+ assert.ok(rl.summary.includes('id=461850557'), '数据行应带 hotelId(hotel-rates 入参来源)');
121
+ assert.ok(rl.summary.includes('朱美拉海滩酒店'), '数据行应带 zh 名称');
122
+ assert.ok(rl.summary.includes('5★'), '数据行应带星级');
123
+ assert.ok(rl.summary.includes('100 USD'), '数据行应带最低价');
124
+ assert.match(rl.summary, /\[实时API:hbcli@/, 'summary 应带证据链时间戳');
125
+ assert.ok(rl.hotels !== null, 'hotels 结构化产物保留(UI/程序消费)');
126
+ console.log(`5b. 实时 summary 数据行 OK:${rl.summary.split('\n')[1]}`);
90
127
  }const r4 = await searchHotels({
91
128
  destination: '普吉岛'
92
129
  }, {
@@ -0,0 +1,288 @@
1
+ import { strict as assert } from 'node:assert';
2
+ import { mkdtempSync, rmSync, mkdirSync, writeFileSync, readdirSync, readFileSync, existsSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { aggregateFacts, aggregateChannels, aggregateIncidents, aggregateLatency, collectMetrics, renderMetricsReport, main } from './build-metrics-report.js';
6
+ const NOW = new Date('2026-09-05T12:00:00Z');
7
+ const DAY = 86_400_000;
8
+ const iso = (daysAgo)=>new Date(NOW.getTime() - daysAgo * DAY).toISOString();
9
+ let checkCount = 0;
10
+ function check(name, fn) {
11
+ fn();
12
+ checkCount += 1;
13
+ console.log(` ok ${checkCount} ${name}`);
14
+ }
15
+ async function withRoot(fn) {
16
+ const root = mkdtempSync(join(tmpdir(), 'gotry-metrics-'));
17
+ const stateDir = join(root, 'gotry-state');
18
+ mkdirSync(stateDir, {
19
+ recursive: true
20
+ });
21
+ try {
22
+ return await fn(root, stateDir);
23
+ } finally{
24
+ rmSync(root, {
25
+ recursive: true,
26
+ force: true
27
+ });
28
+ }
29
+ }
30
+ function writeJsonl(dir, name, lines) {
31
+ writeFileSync(join(dir, name), lines.map((l)=>typeof l === 'string' ? l : JSON.stringify(l)).join('\n') + '\n', 'utf-8');
32
+ }
33
+ check('事实闸聚合:去重/blocked 率/坏行容忍', ()=>{
34
+ const stats = aggregateFacts([
35
+ {
36
+ schema: 'gotry_bookable_fact.v1',
37
+ fact_id: 'f1',
38
+ kind: 'flight_like',
39
+ verdict: 'hit'
40
+ },
41
+ 'NOT JSON',
42
+ {
43
+ schema: 'gotry_bookable_fact.v1',
44
+ fact_id: 'f1',
45
+ kind: 'flight_like',
46
+ verdict: 'error'
47
+ },
48
+ {
49
+ schema: 'gotry_bookable_fact.v1',
50
+ fact_id: 'f2',
51
+ kind: 'flight_like',
52
+ verdict: 'hit'
53
+ },
54
+ {
55
+ schema: 'gotry_bookable_fact.v1',
56
+ fact_id: 'f3',
57
+ kind: 'hotel',
58
+ verdict: 'needs-setup'
59
+ },
60
+ {
61
+ schema: 'gotry_bookable_fact.v1',
62
+ fact_id: 'f4',
63
+ kind: 'hotel',
64
+ verdict: 'miss'
65
+ },
66
+ {
67
+ fact_id: 'f5',
68
+ kind: 'hotel'
69
+ }
70
+ ]);
71
+ assert.equal(stats.lines, 7);
72
+ assert.equal(stats.deduped, 5);
73
+ const flight = stats.byKind.flight_like;
74
+ assert.equal(flight.total, 2);
75
+ assert.equal(flight.verdicts.error, 1);
76
+ assert.equal(flight.verdicts.hit, 1);
77
+ assert.equal(flight.blocked, 1);
78
+ const hotel = stats.byKind.hotel;
79
+ assert.equal(hotel.total, 3);
80
+ assert.equal(hotel.blocked, 1);
81
+ assert.equal(hotel.verdicts['n/a'], 1);
82
+ });
83
+ check('通道健康聚合:30 天窗/最新事件/计数', ()=>{
84
+ const stats = aggregateChannels([
85
+ {
86
+ channel: 'flyai',
87
+ state: 'down',
88
+ reason: 'trial-exhausted',
89
+ at: iso(40)
90
+ },
91
+ {
92
+ channel: 'flyai',
93
+ state: 'down',
94
+ reason: '429',
95
+ at: iso(2)
96
+ },
97
+ {
98
+ channel: 'flyai',
99
+ state: 'cooldown',
100
+ reason: 'retry-after',
101
+ at: iso(1)
102
+ },
103
+ {
104
+ channel: 'session:ctrip-hotel',
105
+ state: 'down',
106
+ reason: 'needs-login',
107
+ at: iso(5)
108
+ },
109
+ 'BROKEN'
110
+ ], {
111
+ now: NOW
112
+ });
113
+ assert.equal(stats.latest.length, 2);
114
+ const flyai = stats.latest.find((c)=>c.channel === 'flyai');
115
+ assert.equal(flyai?.state, 'cooldown');
116
+ assert.equal(flyai?.events, 2);
117
+ const ctrip = stats.latest.find((c)=>c.channel === 'session:ctrip-hotel');
118
+ assert.equal(ctrip?.events, 1);
119
+ });
120
+ check('事故面聚合:窗口/kind 计数/最近一条/top 来源', ()=>{
121
+ const stats = aggregateIncidents([
122
+ {
123
+ ts: iso(10),
124
+ kind: 'uncaughtException',
125
+ message: '太旧不计',
126
+ source: 'old-plugin'
127
+ },
128
+ {
129
+ ts: iso(1),
130
+ kind: 'plugin_error',
131
+ message: 'z3 wasm boom',
132
+ source: 'z3'
133
+ },
134
+ {
135
+ ts: iso(0.2),
136
+ kind: 'plugin_error',
137
+ message: 'second boom',
138
+ source: 'z3'
139
+ },
140
+ {
141
+ ts: iso(0.1),
142
+ kind: 'tool_execute_error',
143
+ message: 'flyai 429',
144
+ source: 'flyai'
145
+ }
146
+ ], {
147
+ now: NOW,
148
+ windowDays: 7
149
+ });
150
+ assert.equal(stats.totalInWindow, 3);
151
+ assert.equal(stats.byKind.plugin_error.count, 2);
152
+ assert.equal(stats.byKind.plugin_error.lastMessage, 'second boom');
153
+ assert.deepEqual(stats.topSources[0], {
154
+ source: 'z3',
155
+ count: 2
156
+ });
157
+ });
158
+ check('桥延迟聚合:p50/p95/max/超预算', ()=>{
159
+ const stats = aggregateLatency([
160
+ {
161
+ ts: iso(1),
162
+ kind: 'hotel_search:hbcli',
163
+ latencyMs: 100
164
+ },
165
+ {
166
+ ts: iso(1),
167
+ kind: 'hotel_search:hbcli',
168
+ latencyMs: 200
169
+ },
170
+ {
171
+ ts: iso(0.5),
172
+ kind: 'weather:open-meteo',
173
+ latencyMs: 300
174
+ },
175
+ {
176
+ ts: iso(0.4),
177
+ kind: 'weather:open-meteo',
178
+ latencyMs: 400
179
+ },
180
+ {
181
+ ts: iso(0.3),
182
+ kind: 'hotel_search:session',
183
+ latencyMs: 501
184
+ },
185
+ {
186
+ ts: iso(9),
187
+ kind: 'old',
188
+ latencyMs: 999_999
189
+ },
190
+ {
191
+ ts: iso(0.2),
192
+ kind: 'bad',
193
+ latencyMs: Number.NaN
194
+ }
195
+ ], {
196
+ now: NOW,
197
+ windowDays: 7
198
+ });
199
+ assert.equal(stats.count, 5);
200
+ assert.equal(stats.p50, 300);
201
+ assert.equal(stats.p95, 501);
202
+ assert.equal(stats.max, 501);
203
+ assert.equal(stats.overBudget, 1);
204
+ assert.deepEqual(stats.topKinds[0], {
205
+ kind: 'hotel_search:hbcli',
206
+ count: 2
207
+ });
208
+ });
209
+ await withRoot(async (root)=>{
210
+ const before = readdirSync(root).sort();
211
+ const snap = await collectMetrics(root, {
212
+ now: NOW
213
+ });
214
+ const md = renderMetricsReport(snap);
215
+ assert.match(md, /事实闸 verdict 分布/);
216
+ assert.match(md, /通道健康/);
217
+ assert.match(md, /事故面/);
218
+ assert.match(md, /桥延迟/);
219
+ assert.match(md, /\(空:窗口内无事故\)/);
220
+ assert.match(md, /不存在\(该 stateRoot 无账本\)/);
221
+ assert.deepEqual(readdirSync(root).sort(), before, 'collect 不得在 stateRoot 新建任何文件');
222
+ checkCount += 1;
223
+ console.log(` ok ${checkCount} 空 stateRoot:报告成型且零写入`);
224
+ });
225
+ await withRoot(async (root, stateDir)=>{
226
+ writeJsonl(stateDir, 'bookable-facts.jsonl', [
227
+ {
228
+ schema: 'gotry_bookable_fact.v1',
229
+ fact_id: 'a',
230
+ kind: 'hotel',
231
+ verdict: 'hit'
232
+ },
233
+ {
234
+ schema: 'gotry_bookable_fact.v1',
235
+ fact_id: 'b',
236
+ kind: 'hotel',
237
+ verdict: 'error'
238
+ }
239
+ ]);
240
+ writeJsonl(stateDir, 'channel-health.jsonl', [
241
+ {
242
+ channel: 'flyai',
243
+ state: 'down',
244
+ reason: 'trial-exhausted',
245
+ at: iso(1)
246
+ }
247
+ ]);
248
+ writeJsonl(stateDir, 'incidents.jsonl', [
249
+ {
250
+ ts: iso(1),
251
+ kind: 'plugin_error',
252
+ message: 'boom',
253
+ source: 'z3'
254
+ }
255
+ ]);
256
+ writeJsonl(stateDir, 'bridge-latency.jsonl', [
257
+ {
258
+ ts: iso(1),
259
+ kind: 'hotel_search:hbcli',
260
+ latencyMs: 120
261
+ }
262
+ ]);
263
+ writeFileSync(join(stateDir, 'doctor-report.md'), '# doctor\n', 'utf-8');
264
+ const before = readdirSync(stateDir).sort();
265
+ const outPath = join(root, 'report.md');
266
+ await main([
267
+ '--state-root',
268
+ root,
269
+ '--out',
270
+ outPath,
271
+ '--days',
272
+ '7'
273
+ ]);
274
+ const md = readFileSync(outPath, 'utf-8');
275
+ assert.match(md, /hotel \| 2 \| hit:1 \/ error:1 \| 1\/2\(50%\)/);
276
+ assert.match(md, /\| flyai \| down \| trial-exhausted \|/);
277
+ assert.match(md, /plugin_error \| 1 /);
278
+ assert.match(md, /p50=120ms/);
279
+ assert.match(md, /doctor 报告 doctor-report\.md:存在/);
280
+ assert.deepEqual(readdirSync(stateDir).sort(), before, '报告生成不得改动 gotry-state 目录');
281
+ assert.ok(existsSync(outPath));
282
+ checkCount += 1;
283
+ console.log(` ok ${checkCount} 端到端:侧车聚合→--out 落盘,stateRoot 只读`);
284
+ });
285
+ console.log(`\nMETRICS REPORT TESTS OK(${checkCount} checks)`);
286
+
287
+
288
+ //# sourceURL=ts/scripts/metrics-report-tests.ts
@@ -0,0 +1,19 @@
1
+ import assert from 'node:assert/strict';
2
+ import { readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ const patch = readFileSync(join(process.cwd(), '..', 'cordis.gotry-patch.yml'), 'utf-8');
5
+ const guard = '表层规则:gotry 的全部能力一律是【工具调用】';
6
+ assert.equal((patch.match(new RegExp(guard, 'g')) ?? []).length, 1, '表层规则句应恰好出现一次');
7
+ assert.ok(patch.includes('绝不把 gotry_* 名字传给 skill 加载器'), '应显式禁止 gotry_* 进 skill 加载器');
8
+ const markers = new Set([
9
+ ...patch.matchAll(/\((\d{1,2})\)/g)
10
+ ].map((m)=>Number(m[1])));
11
+ for(let i = 1; i <= 22; i += 1){
12
+ assert.ok(markers.has(i), `行为契约 (${i}) 应存在`);
13
+ }
14
+ assert.equal(markers.size, 22, `契约条目应恰为 22 条,实际 ${markers.size}`);
15
+ assert.ok(patch.includes('改回 tool call'), '应指引失败后改回 tool call');
16
+ console.log('PERSONA SURFACE GUARD TESTS: 3/3 OK(表层规则句 / 22 条契约完整 / skill 失败行为指引)');
17
+
18
+
19
+ //# sourceURL=ts/scripts/persona-surface-guard-tests.ts