Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .github/workflows/vouchbench-season.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# VouchBench season scoring — the GitHub-native retrieval competition.
#
# Two triggers:
# * pull_request: practice scoring on the PUBLIC practice seeds — instant,
# comparable feedback on every entry push. No secrets, no network beyond
# checkout; scores are a pure function of (seed, code).
# * workflow_dispatch: the SCORED run a maintainer triggers after the season
# cutoff. Seeds are supplied at dispatch time (derive them from the drand
# round at the cutoff — the commit-reveal step: entries are frozen before
# the seeds exist, so nobody can pre-fit). All entries and main are scored
# on the SAME seeds; paired comparison builds the margin band.
#
# See .superpowers/VOUCHBENCH-COMPETITION.md for the full season mechanics
# (cutoff rules, payout shares, first-seen tie protection, review gates).

name: vouchbench-season

on:
pull_request:
paths:
- "src/vouch/**"
- "tests/**"
workflow_dispatch:
inputs:
seeds:
description: >-
Comma-separated scored seeds (derive from the drand round at the
season cutoff; document the round number in the season issue).
required: true
budget_chars:
description: Context budget per query.
default: "2000"

env:
PRACTICE_SEEDS: "1,2,3,4,5,6"

jobs:
score:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install vouch
run: |
python -m venv .venv
.venv/bin/pip install -e '.[dev]'
- name: Score
env:
# dispatch inputs pass through env, never interpolated into the
# script body (workflow-injection hygiene); the python entrypoint
# then int()-parses every seed, rejecting anything shell-shaped.
INPUT_SEEDS: ${{ github.event.inputs.seeds }}
INPUT_BUDGET: ${{ github.event.inputs.budget_chars }}
run: |
SEEDS="${INPUT_SEEDS:-$PRACTICE_SEEDS}"
BUDGET="${INPUT_BUDGET:-2000}"
.venv/bin/python -m vouch.cli bench run \
--seeds "$SEEDS" --budget-chars "$BUDGET" --json \
| tee bench-report.json
- name: Summarize
run: |
.venv/bin/python - <<'PY'
import json
r = json.load(open("bench-report.json"))
lines = [
"## VouchBench",
"",
f"composite **{r['composite_mean']:.3f} ± {r['composite_se']:.3f}** "
f"(seeds {r['seeds']})",
"",
"| category | mean |",
"|---|---|",
]
lines += [f"| {k} | {v:.2f} |" for k, v in r["categories"].items()]
open("summary.md", "w").write("\n".join(lines) + "\n")
PY
cat summary.md >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-artifact@v4
with:
name: bench-report
path: |
bench-report.json
summary.md
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ All notable changes to vouch are documented here. Format follows
## [Unreleased]

### Added
- **session-mode answer memory** (`capture.answer_mode`, default `session`):
claims are extracted once at SessionEnd from the full transcript history
(`capture_session_answers`, wired into `capture finalize`) instead of on
every Stop hook. per-turn extraction saw one answer at a time, which is
where single-turn fragments like "… are noted at the end" came from; the
session document gives the extractor every turn at once, collapses
duplicate spans across turns, and spends one `max_claims` budget per
session rather than per turn. `capture.answer_mode: turn` restores the
legacy per-turn behaviour; the Stop hook stays wired either way (it defers
with `deferred-to-session-end` in session mode).
Comment on lines +10 to +19

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Changelog covers answer_mode only.

The Added section has no entry for the other user-visible features in this PR — session enrichment (capture.enrich), enrichment-driven supersession, vouch bench, or receipt coverage in vouch status. Please add them here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.md` around lines 10 - 19, Expand the changelog’s Added section to
document the other user-visible features introduced by this PR: session
enrichment via capture.enrich, enrichment-driven supersession, the vouch bench
command, and receipt coverage in vouch status. Keep the existing answer_mode
entry unchanged.

Source: Coding guidelines

- **an admission gate that filters knowledge-shaped garbage before it is
filed** (`admission:` config). every ingestion path funnels through
`proposals._file_proposal`, so a single provenance-keyed predicate there
Expand Down
63 changes: 63 additions & 0 deletions docs/vouchbench-seasons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# VouchBench Seasons — competition rules

A recurring, cash-bountied competition to improve vouch's retrieval engine,
scored by `vouch bench` — a seeded, judge-free benchmark whose score is a
pure function of (seed, code). Anyone can reproduce any score on any
machine; that reproducibility is the whole trust model.

## How a season runs

1. **Open.** A season issue announces: the pinned bench contract, the public
practice seeds, the bounty pool and split, and `main`'s current
per-category scores (the zeros are the levers — that table is the map of
where the money is).
2. **Enter.** An entry is a pull request labeled `season-N`. Every push gets
practice scores from CI automatically (the `vouchbench-season` workflow's
pull_request path — public seeds, instant feedback).
3. **Freeze.** At the announced cutoff timestamp, the last commit on each
entry is that entry. Pushing after the cutoff voids the entry for the
season (next season it can re-enter).
4. **Score.** A maintainer dispatches the scored run. The scored seeds are
derived from the public drand randomness round at the cutoff time and
recorded in the season issue — they did not exist while entries could
still change, so nothing can be pre-fit to them (commit-reveal). Every
entry and `main` run the same seeds; results are paired.
5. **Review.** Ranked entries get normal code review before any payout.
Grounds for disqualification: benchmark-keyed logic (lookup tables,
category-pattern dispatch, generator-template matching), bypassing the
review gate, or violating the repo's non-negotiables (no write path
around `proposals.approve()`, plaintext storage, no baked model deps).
Near-identical entries: the earlier-opened PR wins (first-seen).
6. **Pay and merge.** Every entry that beats `main`'s composite by the
margin band — `max(0.007, 1.64 x SE_paired)` over the scored seeds —
earns its rank share of the pool (65 / 14 / 10 / 7 / 4 while the field
is small). The winner merges and becomes the champion the next season
must dethrone.

## Two ladders

* **Ladder A — the score race** above.
* **Ladder B — flat bounties**: issues labeled `bounty:$X` for benchmark
hardening (new categories, better generators, anti-overfit work),
adapters, and bug fixes. Paid on merge after review. Ladder B is how the
benchmark itself keeps improving.

## Payment

Payouts go through a PR-native bounty platform (Polar.sh / Algora) or a
GitHub Sponsors one-time payment, at the maintainer's choice, within a week
of the season closing. The maintainer's decision on scores, bands, and
disqualifications is final; every input needed to re-derive a score
(seeds, commit, command) is public in the season issue.

## Local loop for contributors

```bash
pip install -e '.[dev]'
vouch bench run --seeds 1,2,3,4,5,6 # the public practice baseline
vouch bench gen --seed 1 # inspect a dataset + answer key
vouch bench run --seed 1 --json # full report with failures
```

The reference baseline and the current lever table live in
`src/vouch/bench.py`'s module docstring.
Loading
Loading