In your tests
The first place to check a property is the test suite you already have.
const verdicts = checkTrace(SPEC, events)const broken = verdicts.filter((verdict) => verdict.status === 'violated')
expect(broken).toEqual([])events is whatever your integration test collected from onEvent. checkTrace folds the same monitor over them and
hands back the verdicts — the same fold a live run uses, so a test failure and a runtime verdict mean the same thing.
This is the smaller path and it is the one most projects want. No file on disk, no CLI, no corpus to maintain.
Collecting the events
Section titled “Collecting the events”const collected: TraceEvent[] = []const tools = guardTools(monitor, allTools, { source, onEvent: (event) => collected.push(event) })That is the whole setup. Run your agent against it, then assert.
What to assert
Section titled “What to assert”That the rules you have written pass on a run you believe is good. This catches the rule that is stricter than you meant it, which is the common failure and the one that shows up as a support ticket rather than as a test failure.
That a rule fires on a run you have engineered to break it. A rule nothing has ever broken is a rule you have not
tested; ltl analyze witness will synthesise the shortest trace that breaks it if you would rather
not write one by hand.
Sequence integrity. events.map((event) => event.seq) equals [0, 1, 2, …], on every trace your tests produce,
including runs where calls were refused. Holes and repeats are the failure mode this model is most sensitive to and the
easiest to introduce.
That the rules are about tools you actually have.
expect(lintNames(SPEC, { tools })).toEqual([])A rule naming a tool nothing provides can never fire, and it does not announce itself — it reports satisfied forever,
which reads exactly like a rule that is working. lintNames is a warning
rather than an error precisely so that you get to decide where it bites, and this is the place: one line, run against the
tools your test already built.
When to reach past this
Section titled “When to reach past this”When the traces outlive the test that produced them. A rule set that is edited often wants a corpus of runs it is checked against — not to find out what your agent did, but to find out whether this edit still catches what it caught. That is the corpus, and it is a different question from the one this page answers.