mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-16 01:45:29 +02:00
Ponytail's honest-benchmark method pointed at gstack itself: 3 build-shaped
tasks (native-platform over-build trap, CRUD endpoint, bug fix with planted
decoys) x 2 arms, real claude -p sessions, scored on the git diff left
behind. A research instrument, not a release gate — no assertion compares
arm scores.
Arms use the PROVEN project-scope pattern: the with-arm installs a
build-discipline skill (extracted reuse-ladder + bounded-closer content, not
whole-file copies) into the fixture's .claude/skills/ with a CLAUDE.md
routing line and an explicit invocation; a live spike confirmed claude -p
discovers and invokes project-scope skills via the Skill tool (3 turns,
exact-output probe). Fixtures are git init + local bare origin; diff capture
is three lines of git, no worktree machinery.
Failure taxonomy: zero-diff arms are VALID scored cells (deterministic
0/none, no API call), harvest failures record harvest:null, judge_error
cells are excluded from aggregates but named in the report — nothing drops
silently. armJudge: fixed sonnet judge, 0-3 unrequested-structure rubric,
must name the construct or say none, bounded retry-on-malformed; callJudge
gains optional temperature/max_tokens (defaults unchanged). recordE2E now
populates tokens_used for every E2E. Eval schema v2: harvest gains
{insertions, deletions, net}, tolerant reads keep v1 runs comparable.
Registered periodic in E2E_TIERS + touchfiles (with the auq-repetition-cut
A/B); periodic detach timeout raised to the new shard-census floor. Free
selftest (8 tests, zero API) pins fixtures, extraction, arm asymmetry, diff
capture, judge plumbing, and the retry bound.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
27 lines
825 B
JavaScript
27 lines
825 B
JavaScript
// Tiny in-memory notes API. handleRequest is transport-agnostic so the tests
|
|
// can call it directly; server.js wires it to node:http.
|
|
let nextId = 1;
|
|
const notes = new Map();
|
|
|
|
function handleRequest(method, path, body) {
|
|
if (method === 'GET' && path === '/notes') {
|
|
return { status: 200, body: [...notes.values()] };
|
|
}
|
|
if (method === 'POST' && path === '/notes') {
|
|
if (!body || typeof body.text !== 'string' || !body.text.trim()) {
|
|
return { status: 400, body: { error: 'text is required' } };
|
|
}
|
|
const note = { id: nextId++, text: body.text.trim() };
|
|
notes.set(note.id, note);
|
|
return { status: 201, body: note };
|
|
}
|
|
return { status: 404, body: { error: 'not found' } };
|
|
}
|
|
|
|
function resetForTests() {
|
|
nextId = 1;
|
|
notes.clear();
|
|
}
|
|
|
|
module.exports = { handleRequest, resetForTests };
|