version: 3
metadata:
name: error-shape
description: "Verifies the shape of error envelopes returned by tool calls."
authors: ["wallfacer-core"]
tags: [reliability, errors]
parameters:
error_witness_tool:
description: "A tool that the witness payload reliably forces into the error path."
type: string
default: "divide"
unknown_tool_name:
description: "A tool name that does NOT exist on the server."
type: string
default: "this_tool_does_not_exist"
invariants:
- name: "error.witness_returns_well_formed_envelope"
tool: "{{error_witness_tool}}"
fixed:
a: 1
b: 0
assert:
- kind: matches_schema
path: "$.response"
schema:
type: object
required: [isError, content]
properties:
isError: { type: boolean, enum: [true] }
content:
type: array
minItems: 1
items:
type: object
required: [type, text]
properties:
type: { type: string, enum: [text] }
text: { type: string, minLength: 1 }
test_fixtures:
- name: "passes with well-formed envelope"
response:
isError: true
content:
- { type: "text", text: "division by zero" }
expect: pass
- name: "fails when isError is false"
response:
isError: false
content:
- { type: "text", text: "ok" }
expect: fail
- name: "error.unknown_tool_returns_envelope_not_panic"
tool: "{{unknown_tool_name}}"
fixed: {}
assert:
- kind: equals
lhs: { path: "$.response.isError" }
rhs: { value: true }
test_fixtures:
- name: "passes when isError set"
response: { isError: true }
expect: pass
- name: "fails when isError absent / false"
response: { isError: false, content: [{ type: "text", text: "ok" }] }
expect: fail
- name: "error.text_messages_never_carry_internal_paths"
tool: "{{error_witness_tool}}"
fixed:
a: 1
b: 0
assert:
- kind: not
assertion:
kind: matches_regex
path: "$.response.content[0].text"
pattern: "(?:/Users/|/home/|C:\\\\\\\\)"
test_fixtures:
- name: "passes with sanitized message"
response: { content: [{ type: "text", text: "division by zero" }] }
expect: pass
- name: "fails when /Users/... leaks"
response:
content:
- { type: "text", text: "panic at /Users/alice/server.py:42" }
expect: fail
- name: "error.text_messages_never_carry_stack_traces"
tool: "{{error_witness_tool}}"
fixed:
a: 1
b: 0
assert:
- kind: not
assertion:
kind: matches_regex
path: "$.response.content[0].text"
pattern: "Traceback \\(most recent call last\\)|^\\s*at\\s+[A-Za-z0-9_<>$.]+\\("
test_fixtures:
- name: "passes with short message"
response: { content: [{ type: "text", text: "division by zero" }] }
expect: pass
- name: "fails when Python traceback leaks"
response:
content:
- { type: "text", text: "Traceback (most recent call last):\n File \"server.py\", line 1" }
expect: fail