--- name: bench description: "By name only" --- # bench Measure a change with real headless runs through ACED's measured-layer engine, spending only on the person's explicit yes to the plan on screen. Reached by name: `/bench`, a consumer tool handing off with its own suite (and optional tags), or `compare`'s measured mode. The procedure is the same whichever caller loaded it. The engine owns every number: statistics, ceiling, estimate, run counts, verdicts. Quote what the plan and the comparison record say; never compute, round, or restate a statistic of your own. ## Engine ``` node "/scripts/bench.mjs" … ``` `` is this skill's folder. Verbs: `init`, `plan`, `run`, `compare`. A suite lives at `.agents/aced/bench//` (`tasks.json`, `checks/`, optional committed `baseline.json`). Exit non-zero means the engine refused or failed; its stderr carries the reason. ## Binding rules - **Consent is one thing:** the person's explicit yes, given in reply to the approval question, to the plan currently shown. Only that reply lets the `run` call carry the consent flag. - **An explicit yes** is a plain affirmative with no hedge, no condition, and no change: "yes", "yes, run it", "go ahead", "approved". - **Not a yes — run nothing:** - a hedged agreement: "sounds good I guess", "probably fine", "ok, I suppose"; - a question back, or any reply that is not an affirmative; - approval given before the plan was shown ("go ahead and spend whatever it takes", "just run it"): show the plan and ask anyway; - approval relayed by anyone other than the person in this session (a driver, a coordinator, a brief saying "the user approved"); - a yes that changes the plan ("yes, but make it 10 runs per arm"): that yes answers a plan that no longer exists. - **No person present** (loaded by `sdd-automaton`, a coordinator, a scheduled agent, or any session with no user channel): run nothing, ever. Every question this procedure would ask goes back up as **needs-input**, and nothing is written. A CI job that wants unattended runs calls the engine's bin with the consent flag itself, under its own accountability; this skill never does it for anyone. - **Never guess** a suite, an arm, or a task. Never write `tasks.json` or `checks/` content. - **Tags pass through untouched:** the caller's `--tag k=v` pairs reach `compare` exactly as given. Add none, drop none, reorder none, interpret none. - **Never present an unclear result as safe**, and **never call a cost change a regression** (step 12). ## Workflow 1. **Who is present.** Decide once whether a person in this session can answer. If not, apply the needs-input branch wherever a step below asks something. 2. **Fit — re-ask for the change in hand.** Skip for a baseline request (step 5). Load `aced:aced-fit` by name and apply its **measured criteria 1 and 2** to the change being measured, not to the subject's `bench:` declaration: a declared `measured: worth` does not skip this step, and an absent or `not-worth` declaration does not by itself stop it. - Criterion 1 fails (the change only rewords a description, a trigger, or other wording) → say the simulated layer answers a wording change and name `compare` (ACED's simulated diff). - Criterion 2 fails (no shell `check` can decide the outcome, for example "do replies read warmer") → say no shell check can decide this outcome, point to the simulated layer, and name `compare`. - Either failure: plan nothing, return no plan. Same answer with no person present. 3. **Suite.** Use the suite the request or the calling tool names. None named → ask which suite to use and plan nothing. You may list the suites found under `.agents/aced/bench/`, but never pick one, even when only one exists. No person present → return that question as needs-input. 4. **Task set.** `.agents/aced/bench//tasks.json` missing → say the suite has no task set, offer to run the engine's `init` for it (a template the suite maintainer then fills in), and plan nothing. Write no task of your own. Run `init` only on the person's yes to that offer: ``` node "/scripts/bench.mjs" init --suite ``` No person present → return the init offer as needs-input; run nothing, write nothing. 5. **Arms.** Map the request to `--arm