@emseepea/testing 0.5.1 → 0.5.2

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/README.md CHANGED
@@ -38,8 +38,9 @@ meanings, and judge reasons. It also keeps hashes for comparison. A failed
38
38
  meaning assertion runs and records all nine judgments, so disagreement is
39
39
  visible without a rerun.
40
40
 
41
- Failed judge invocations record a safe cause such as a
42
- timeout, process exit code, missing result event, or fixed provider error category.
41
+ Failed answer and judge invocations record a safe cause such as a timeout,
42
+ process exit code, missing result event, or fixed provider error category. The
43
+ failed answer trial is identified even when earlier trials completed.
43
44
 
44
45
  Treat test conversations as publishable artifact content. Use synthetic,
45
46
  non-sensitive fixtures and never put credentials or production data in prompts,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emseepea/testing",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "MCP integration and semantic testing helpers",
5
5
  "license": "MIT",
6
6
  "repository": {
package/semantic/test.mjs CHANGED
@@ -83,8 +83,10 @@ export async function createConversation(testContext, options) {
83
83
  if (typeof prompt !== "string" || !prompt.trim()) throw new Error("send needs a user prompt");
84
84
  ensureOpen(state);
85
85
  const trials = [];
86
+ let activeTrial;
86
87
  try {
87
88
  for (const trial of state.trials) {
89
+ activeTrial = trial;
88
90
  trial.model ??= startModelConversation(
89
91
  provider,
90
92
  trial.directory,
@@ -135,7 +137,8 @@ export async function createConversation(testContext, options) {
135
137
  history: Object.freeze([...trial.history]),
136
138
  });
137
139
  }
138
- } catch {
140
+ } catch (error) {
141
+ if (activeTrial) activeTrial.record.error = safeModelFailure(error);
139
142
  state.failed = true;
140
143
  evidence.failedPhase = "conversation turn";
141
144
  throw new Error(`Semantic test failed during conversation turn: ${name}`);
@@ -235,7 +238,7 @@ export async function assertResponseMeaning(turn, expectation) {
235
238
  } catch (error) {
236
239
  record.error = error instanceof SyntaxError || error.message === "Judge returned an invalid verdict"
237
240
  ? "invalid judge verdict"
238
- : safeJudgeFailure(error);
241
+ : safeModelFailure(error);
239
242
  failed = true;
240
243
  }
241
244
  trial.evidence.judgeVerdicts.push(record);
@@ -249,7 +252,7 @@ export async function assertResponseMeaning(turn, expectation) {
249
252
  }
250
253
  }
251
254
 
252
- function safeJudgeFailure(error) {
255
+ function safeModelFailure(error) {
253
256
  const message = error instanceof Error ? error.message : "";
254
257
  const safeMessages = new Set([
255
258
  "Claude subscription authentication is unavailable",
@@ -270,11 +273,19 @@ function safeJudgeFailure(error) {
270
273
  "Model command used an unexpected number of turns",
271
274
  "Model command was cancelled",
272
275
  "Model command did not use the required model",
276
+ "Model command omitted MCP initialization evidence",
277
+ "Model command omitted an MCP tool result",
278
+ "Model command returned no answer",
279
+ "Model command used more than three tools",
280
+ "Model conversation already has a pending turn",
281
+ "Model conversation could not start",
282
+ "Model conversation is closed",
283
+ "Model conversation was cancelled",
273
284
  ]);
274
- if (safeMessages.has(message) || /^Model command exited \d{1,3}$/.test(message)) {
285
+ if (safeMessages.has(message) || /^Model (?:command|conversation) exited \d{1,3}$/.test(message)) {
275
286
  return message.replace(/^./, (character) => character.toLowerCase());
276
287
  }
277
- return "judge invocation failed";
288
+ return "model invocation failed";
278
289
  }
279
290
 
280
291
  async function isolatedModel(provider, prompt, prefix, signal) {