voyage/evals/skill-test-first-effect/scaffold.sh
Kjell Tore Guttormsen cc832fd430
feat(skills): skill workshop, test-first and debugging preloaded into the step helper
The workshop (ordre 7a, contracts S1 and S2): a form check
(lib/skills/skill-lint.mjs) that follows Claude Code's own skill fields,
and a model-free routing test (lib/skills/routing.mjs) over every skill,
the 7 commands and the 21 spawnable agents, reading the eval cases
themselves (evals/skill-*, 3 fire / 2 quiet / 1 effect, tagged with the
event they came from). Thresholds pinned, never lowered.

The two skills were written against failures measured first in helpers
without them: red only as an import crash, the whole suite run from a
hand-made file list instead of the repo's own command, and an
unreproduced fix shipped under authority pressure. step-implementer
preloads both through its skills: line; no tool list change.

Credits: addyosmani/agent-skills @9d0c60d, obra/superpowers @8ca22db,
mattpocock/skills @c55ee46 (MIT), Anthropic skill-creator (Apache-2.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:38:58 +02:00

42 lines
1.6 KiB
Bash
Executable file

#!/bin/bash
# Seeds the empty run workspace with a small volunteer-rota app (Node, node --test).
# Self-contained on purpose: the run cannot read the eval directory, and the
# fixture is written inline, with no path outside the workspace and no git.
set -eu
mkdir -p src tests
cat > package.json <<'J'
{ "name": "rota", "version": "0.3.0", "type": "module", "private": true,
"scripts": { "test": "node --test" } }
J
cat > src/duration.mjs <<'J'
// Parses a shift length such as "90m" or "45s" into minutes.
export function parseDuration(text) {
const m = /^(\d+)([a-z]*)$/.exec(String(text).trim());
if (!m) throw new Error(`bad duration: ${text}`);
const n = Number(m[1]);
if (m[2] === 'm') return n;
if (m[2] === 's') return n / 60;
return n; // a bare number is minutes
}
J
cat > src/rota.mjs <<'J'
import { parseDuration } from './duration.mjs';
// Total minutes a volunteer is booked for, from shift strings.
export function bookedMinutes(shifts) {
return shifts.reduce((sum, s) => sum + parseDuration(s), 0);
}
J
cat > tests/duration.test.mjs <<'J'
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { parseDuration } from '../src/duration.mjs';
test('minutes', () => assert.equal(parseDuration('90m'), 90));
test('seconds', () => assert.equal(parseDuration('30s'), 0.5));
test('bare number is minutes', () => assert.equal(parseDuration('15'), 15));
J
cat > tests/rota.test.mjs <<'J'
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { bookedMinutes } from '../src/rota.mjs';
test('sums shifts', () => assert.equal(bookedMinutes(['90m', '30m', '15']), 135));
J