snifftest 0.1.0
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/LICENSE +21 -0
- package/README.md +372 -0
- package/SECURITY.md +165 -0
- package/bench/panel-direct.yaml +97 -0
- package/bench/panel.yaml +136 -0
- package/bench/prices/anthropic-2026-09-17.yaml +33 -0
- package/bench/prices/openai-2026-09-17.yaml +27 -0
- package/dist/snifftest.js +12217 -0
- package/examples/CORPUS.md +54 -0
- package/examples/corpus/cold-email.md +5 -0
- package/examples/corpus/editing-by-ear.md +5 -0
- package/examples/corpus/field-notes-app.md +5 -0
- package/examples/corpus/franklin-the-printer.md +3 -0
- package/examples/corpus/franklin-the-socratic-method.md +3 -0
- package/examples/corpus/franklin-the-spectator.md +1 -0
- package/examples/corpus/on-checklists.md +5 -0
- package/examples/corpus/release-note.md +5 -0
- package/examples/corpus/station-routes.md +5 -0
- package/examples/corpus/strunk-introduction.md +1 -0
- package/examples/replays/bench-2026-09-17.json +104 -0
- package/examples/replays/drafts/clean.md +1 -0
- package/examples/replays/drafts/faulty.md +1 -0
- package/examples/replays/example.json +79 -0
- package/examples/seeds/bank.json +196 -0
- package/package.json +46 -0
- package/rules/default.yaml +458 -0
package/bench/panel.yaml
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# The panel `snifftest bench` asks the same questions as the judgment rules.
|
|
2
|
+
#
|
|
3
|
+
# Nothing here is a claim that a model exists. Each entry carries a pattern and
|
|
4
|
+
# a preference; on the day of the run every entry is matched against the
|
|
5
|
+
# provider's own model list and the exact slug, its published prices and
|
|
6
|
+
# whether it takes a JSON mode are written into the raw output. A model the
|
|
7
|
+
# provider does not list becomes a row that says "not available on <date>" and
|
|
8
|
+
# is never swapped for a near neighbour.
|
|
9
|
+
#
|
|
10
|
+
# Most of the panel is routed through OpenRouter so that one key reproduces the
|
|
11
|
+
# whole bench and every row carries the same proxy hop. The last entry calls one
|
|
12
|
+
# of those models directly, which is what makes that hop measurable rather than
|
|
13
|
+
# an asterisk.
|
|
14
|
+
#
|
|
15
|
+
# Jev is in the rotation, as the last row. Its accuracy still comes from
|
|
16
|
+
# `snifftest eval`, where arm C is scored against arms A and B over the same
|
|
17
|
+
# seeded corpus and joined into the headline table with `--eval`; what the row
|
|
18
|
+
# below adds is a latency measured in the same interleaved rotation, with the
|
|
19
|
+
# same repeats, as every other row. Two latency numbers in one column measured
|
|
20
|
+
# two different ways is not a comparison.
|
|
21
|
+
#
|
|
22
|
+
# A row may also name `alternates`. A preferred slug the provider has stopped
|
|
23
|
+
# listing then falls to a substitute the panel file named, and the tables print
|
|
24
|
+
# which one was taken; a row with no alternates says "not available" instead of
|
|
25
|
+
# quietly measuring a neighbour.
|
|
26
|
+
#
|
|
27
|
+
# A row may also declare `max_tokens` and `reasoning`. Those two settings are
|
|
28
|
+
# the only way the rows differ, they are there because a reasoning model spends
|
|
29
|
+
# its internal tokens out of the same completion budget as its answer, and both
|
|
30
|
+
# are printed under the tables so the difference is declared rather than hidden.
|
|
31
|
+
|
|
32
|
+
version: 1
|
|
33
|
+
|
|
34
|
+
prices:
|
|
35
|
+
# OpenRouter publishes a price per model, so only the direct row needs a file.
|
|
36
|
+
anthropic: prices/anthropic-2026-09-17.yaml
|
|
37
|
+
# No dated published price has been recorded for the judgment service, so no
|
|
38
|
+
# file is named here and its row prints its cost as unknown. A constant in
|
|
39
|
+
# this repo's source is not a source. When a dated one exists it goes in
|
|
40
|
+
# `prices/` beside the Anthropic file and this line points at it.
|
|
41
|
+
|
|
42
|
+
models:
|
|
43
|
+
- id: haiku
|
|
44
|
+
label: Claude Haiku 4.5
|
|
45
|
+
tier: fast
|
|
46
|
+
provider: openrouter
|
|
47
|
+
match: "^anthropic/claude-haiku-4"
|
|
48
|
+
prefer:
|
|
49
|
+
- anthropic/claude-haiku-4.5
|
|
50
|
+
|
|
51
|
+
- id: sonnet
|
|
52
|
+
label: Claude Sonnet 5
|
|
53
|
+
tier: mid
|
|
54
|
+
provider: openrouter
|
|
55
|
+
match: "^anthropic/claude-sonnet-5"
|
|
56
|
+
prefer:
|
|
57
|
+
- anthropic/claude-sonnet-5
|
|
58
|
+
|
|
59
|
+
- id: opus
|
|
60
|
+
label: Claude Opus 5
|
|
61
|
+
tier: deep
|
|
62
|
+
provider: openrouter
|
|
63
|
+
match: "^anthropic/claude-opus-5"
|
|
64
|
+
prefer:
|
|
65
|
+
- anthropic/claude-opus-5
|
|
66
|
+
|
|
67
|
+
- id: openai-fast
|
|
68
|
+
label: OpenAI, fast tier
|
|
69
|
+
tier: fast
|
|
70
|
+
provider: openrouter
|
|
71
|
+
match: "^openai/gpt-5[^/]*mini$"
|
|
72
|
+
prefer:
|
|
73
|
+
- openai/gpt-5-mini
|
|
74
|
+
|
|
75
|
+
- id: gemini-flash
|
|
76
|
+
label: Gemini Flash
|
|
77
|
+
tier: fast
|
|
78
|
+
provider: openrouter
|
|
79
|
+
match: "^google/gemini-[0-9.]+-flash$"
|
|
80
|
+
prefer:
|
|
81
|
+
- google/gemini-2.5-flash
|
|
82
|
+
|
|
83
|
+
- id: deepseek
|
|
84
|
+
label: DeepSeek, chat tier
|
|
85
|
+
tier: fast
|
|
86
|
+
provider: openrouter
|
|
87
|
+
match: "^deepseek/deepseek-chat"
|
|
88
|
+
prefer:
|
|
89
|
+
- deepseek/deepseek-chat-v3
|
|
90
|
+
note: >
|
|
91
|
+
DeepSeek publishes no model called Flash; this is its chat tier, which is
|
|
92
|
+
the cheap-and-quick row the panel wanted.
|
|
93
|
+
|
|
94
|
+
- id: openai-deep
|
|
95
|
+
label: OpenAI, deep tier
|
|
96
|
+
tier: deep
|
|
97
|
+
provider: openrouter
|
|
98
|
+
match: "^openai/gpt-5(\\.[0-9]+)?$"
|
|
99
|
+
prefer:
|
|
100
|
+
- openai/gpt-5
|
|
101
|
+
# This row reasons, and on OpenRouter the reasoning tokens come out of the
|
|
102
|
+
# same completion budget as the answer. On the default budget it can spend
|
|
103
|
+
# the whole of it thinking and stop before it writes the JSON object, which
|
|
104
|
+
# lands in the table as a parse failure and reads as a verdict on the model
|
|
105
|
+
# rather than on the request. So the budget is raised and the effort is
|
|
106
|
+
# declared: low keeps the row affordable, and the footnote prints both, so
|
|
107
|
+
# nobody reads this row as the model's best.
|
|
108
|
+
max_tokens: 4000
|
|
109
|
+
reasoning:
|
|
110
|
+
effort: low
|
|
111
|
+
|
|
112
|
+
- id: sonnet-direct
|
|
113
|
+
label: Claude Sonnet 5, direct
|
|
114
|
+
tier: control
|
|
115
|
+
provider: anthropic
|
|
116
|
+
match: "^claude-sonnet-5"
|
|
117
|
+
prefer:
|
|
118
|
+
- claude-sonnet-5
|
|
119
|
+
note: >
|
|
120
|
+
The overhead control. Same model as the sonnet row, called without the
|
|
121
|
+
OpenRouter hop, so the pair measures the hop.
|
|
122
|
+
|
|
123
|
+
- id: jev
|
|
124
|
+
label: Jev, the judgment arm
|
|
125
|
+
tier: judgment
|
|
126
|
+
provider: jev
|
|
127
|
+
match: "^jev-"
|
|
128
|
+
prefer:
|
|
129
|
+
- jev-latest
|
|
130
|
+
note: >
|
|
131
|
+
Asked its own way, one request per paragraph carrying every rule as a
|
|
132
|
+
separate question, which is the shape the service documents and the shape
|
|
133
|
+
arm C uses. The request count matches the other rows; the request shape
|
|
134
|
+
does not. It returns a probability and no boolean, so its flag column is
|
|
135
|
+
that probability against the shipped threshold rather than a decision the
|
|
136
|
+
service made.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Published list prices for the Anthropic direct row, in US dollars per million
|
|
2
|
+
# tokens.
|
|
3
|
+
#
|
|
4
|
+
# This file exists because the Messages API returns token counts and no prices,
|
|
5
|
+
# and because a price written into source code is a number with no provenance
|
|
6
|
+
# and no expiry. Every table that uses these numbers cites this file, its
|
|
7
|
+
# source and the date below.
|
|
8
|
+
#
|
|
9
|
+
# `match` is a substring of the served model id, so a dated id such as
|
|
10
|
+
# `claude-sonnet-5-20260101` lands on its family. A served model that matches no
|
|
11
|
+
# row here has no cost at all in the report. It is never a zero, which would
|
|
12
|
+
# read as "this call was free".
|
|
13
|
+
#
|
|
14
|
+
# Re-verify on the run date and write a new dated file rather than editing this
|
|
15
|
+
# one; the run that used the old numbers should keep pointing at them.
|
|
16
|
+
|
|
17
|
+
version: 1
|
|
18
|
+
source: >-
|
|
19
|
+
Anthropic published list prices, transcribed on 2026-09-17; re-verify against
|
|
20
|
+
the published price list on the run date before quoting these figures.
|
|
21
|
+
verified_on: 2026-09-17
|
|
22
|
+
currency: usd_per_million_tokens
|
|
23
|
+
|
|
24
|
+
models:
|
|
25
|
+
- match: haiku-4-5
|
|
26
|
+
input: 1
|
|
27
|
+
output: 5
|
|
28
|
+
- match: sonnet-5
|
|
29
|
+
input: 2
|
|
30
|
+
output: 10
|
|
31
|
+
- match: opus-5
|
|
32
|
+
input: 5
|
|
33
|
+
output: 25
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Published list prices for the OpenAI direct rows, in US dollars per million
|
|
2
|
+
# tokens.
|
|
3
|
+
#
|
|
4
|
+
# This file exists because the models endpoint returns ids and nothing else: no
|
|
5
|
+
# prices, and no list of the parameters each model takes. A price written into
|
|
6
|
+
# source code is a number with no provenance and no expiry, so it lives here
|
|
7
|
+
# instead, and every table that uses these numbers cites this file, its source
|
|
8
|
+
# and the date below.
|
|
9
|
+
#
|
|
10
|
+
# `match` is a substring of the served model id, so a dated id lands on its
|
|
11
|
+
# family. A served model that matches no row here has no cost at all in the
|
|
12
|
+
# report. It is never a zero, which would read as "this call was free".
|
|
13
|
+
#
|
|
14
|
+
# Re-verify on the run date and write a new dated file rather than editing this
|
|
15
|
+
# one; the run that used the old numbers should keep pointing at them.
|
|
16
|
+
|
|
17
|
+
version: 1
|
|
18
|
+
source: >-
|
|
19
|
+
OpenAI published list prices (developers.openai.com/api/docs/pricing),
|
|
20
|
+
transcribed on 2026-09-17
|
|
21
|
+
verified_on: 2026-09-17
|
|
22
|
+
currency: usd_per_million_tokens
|
|
23
|
+
|
|
24
|
+
models:
|
|
25
|
+
- match: gpt-5.6-sol
|
|
26
|
+
input: 4
|
|
27
|
+
output: 20
|