diff --git a/docs/scripts.md b/docs/scripts.md index 8afac25..4b478e5 100644 --- a/docs/scripts.md +++ b/docs/scripts.md @@ -23,7 +23,7 @@ Run scripts from the repository root. PowerShell and Bash commands have equivale | `commands/doctor.ps1`, `commands/doctor.sh` | Check generated output and installed configuration. | | `commands/prompt-budget.ps1`, `commands/prompt-budget.sh` | Track permanent context, skill metadata, the rule catalog, and agent metadata; warn above 10,000 permanent-context tokens, fail when any token estimate exceeds its baseline by 10%, or permanent context exceeds 15,000 tokens. | | `commands/context-report.ps1`, `commands/context-report.sh` | Report the context installed Claude and Codex actually load, from Claude `/context`, `/skill-doctor`, and its init event, and Codex `debug prompt-input`: categories, active plugins, listed skills, installed skills missing from the listing, and skills listed without description context. `--check` fails on missing or description-less skills. No model request is made. | -| `commands/benchmark.ps1`, `commands/benchmark.sh` | Run the Python, C#/ASP.NET, and TypeScript tasks under `scripts/benchmarks/tasks/` with and without the installed setup. Both arms of a client use one pinned model and reasoning effort; a preflight records what each arm actually loads in `provenance.json` and stops when the arms are not comparable; `--arms setup setup-no-search --tasks 11-* 12-* 13-* --warm-index` compares Claude with and without semantic search on concept-search tasks in a large generated repository, and compare pass rate, rework turns, duration, tokens, tool calls, cost, and workflow checks (no planning ceremony for a small change, targeted verification for a bugfix, bounded delegation for a larger change). Starts real model sessions; use `--dry-run` to list runs. The Codex baseline needs one `codex login` with `CODEX_HOME` set to `--codex-baseline-home`. | +| `commands/benchmark.ps1`, `commands/benchmark.sh` | Run the Python, C#/ASP.NET, and TypeScript tasks under `scripts/benchmarks/tasks/` with and without the installed setup. Both arms of a client use one pinned model and reasoning effort; a preflight records what each arm actually loads in `provenance.json` and stops when the arms are not comparable; `--arms setup setup-no-search --tasks 11-* 12-* 13-* --warm-index` compares Claude with and without semantic search on concept-search tasks in a large generated repository, and compare pass rate, rework turns, duration, tokens, tool calls, cost, and workflow checks per task category (`category` in `task.json`: small change, larger implementation, search) (no planning ceremony for a small change, targeted verification for a bugfix, bounded delegation for a larger change). Starts real model sessions; use `--dry-run` to list runs. The Codex baseline needs one `codex login` with `CODEX_HOME` set to `--codex-baseline-home`. | | `commands/repository-context.ps1`, `commands/repository-context.sh` | Refresh the local repository-context cache. | | `commands/session-state.ps1`, `commands/session-state.sh` | Read or update the local agent session state. | | `commands/telemetry.ps1`, `commands/telemetry.sh` | Append a local telemetry event. | diff --git a/scripts/benchmarks/ab.py b/scripts/benchmarks/ab.py index 2587677..024a3e8 100644 --- a/scripts/benchmarks/ab.py +++ b/scripts/benchmarks/ab.py @@ -382,14 +382,18 @@ def run_one(job, args): def summarize(results): errors = [result for result in results if result.get('error')] results = [result for result in results if not result.get('error')] - lines = [f'Excluded {len(errors)} runs that ended with a client or API error (for example a usage limit).', '','| client | arm | runs | pass | first try | rework turns | median s | median input tok | median output tok | median tool calls | cost USD | workflow ok |', - '|---|---|---|---|---|---|---|---|---|---|---|---|'] + lines = [f'Excluded {len(errors)} runs that ended with a client or API error (for example a usage limit).', + 'Rows are per task category; an overall average would hide a category where one arm is worse.', '', + '| category | client | arm | runs | pass | first try | rework turns | median s | median input tok | median output tok | median tool calls | cost USD | workflow ok |', + '|---|---|---|---|---|---|---|---|---|---|---|---|---|'] groups = {} for result in results: - groups.setdefault((result['client'], result['arm']), []).append(result) - for (client, arm), runs in sorted(groups.items()): + spec = TASKS / result['task'] / 'task.json' + category = json.loads(spec.read_text(encoding='utf-8')).get('category', '?') if spec.is_file() else '?' + groups.setdefault((category, result['client'], result['arm']), []).append(result) + for (category, client, arm), runs in sorted(groups.items()): median = lambda key: statistics.median(run[key] for run in runs) - lines.append(f'| {client} | {arm} | {len(runs)} | {sum(run["passed"] for run in runs) / len(runs):.0%} | ' + lines.append(f'| {category} | {client} | {arm} | {len(runs)} | {sum(run["passed"] for run in runs) / len(runs):.0%} | ' f'{sum(run["first_try"] for run in runs) / len(runs):.0%} | {sum(run["rework_turns"] for run in runs)} | ' f'{median("seconds"):.0f} | {median("input_tokens"):.0f} | {median("output_tokens"):.0f} | {median("tool_calls"):.0f} | ' f'{sum(run["cost_usd"] for run in runs):.2f} | {sum(not run["workflow_violations"] for run in runs) / len(runs):.0%} |')