What happens
A model spec without a slash resolves to the paid claude-cli backend with the whole string as the model name. The README's known-limits section documents the sharpest edge itself: --model mock does not reach the scripted double — it becomes model name mock on the subscription backend. Only the slash form (mock/anything) reaches the double. So the exact spelling a newcomer tries first, on the one backend that spends real subscription quota, is the one that silently does the wrong thing — while a mistyped backend with a slash is properly rejected with exit 2.
Why it matters
This inverts the project's own principle that the expensive path must be opt-in. Every other spend gate in the tree (Slack's --model opt-in, the budget gate, live tests behind -m live) fails closed; spec parsing is the one place that fails open, onto the paid backend. A typo'd demo command is a real charge and a confusing error from the Claude CLI instead of a clean refusal.
What to consider
- Make a bare spec an error (exit 2):
model spec 'mock' has no backend; write 'claude-cli/mock' if you meant the subscription backend — the same shape as the existing mistyped-backend refusal. This is a breaking change for anyone relying on the bare shorthand; the release note says so, loudly.
- Softer alternative: keep the default but require one-time acknowledgement (env var or config key) before a bare spec may resolve to a paid backend; refuse otherwise.
- Update the README limits bullet and the models cookbook page, both of which currently document the behaviour as a trap to memorise.
Acceptance criteria
grapharc run --model mock … (and models mock) refuse with a message naming the fix; the slash forms behave exactly as today; README/cookbook text describing the old behaviour is updated and its byte-compare tests pass.
What happens
A model spec without a slash resolves to the paid
claude-clibackend with the whole string as the model name. The README's known-limits section documents the sharpest edge itself:--model mockdoes not reach the scripted double — it becomes model namemockon the subscription backend. Only the slash form (mock/anything) reaches the double. So the exact spelling a newcomer tries first, on the one backend that spends real subscription quota, is the one that silently does the wrong thing — while a mistyped backend with a slash is properly rejected with exit 2.Why it matters
This inverts the project's own principle that the expensive path must be opt-in. Every other spend gate in the tree (Slack's
--modelopt-in, the budget gate, live tests behind-m live) fails closed; spec parsing is the one place that fails open, onto the paid backend. A typo'd demo command is a real charge and a confusing error from the Claude CLI instead of a clean refusal.What to consider
model spec 'mock' has no backend; write 'claude-cli/mock' if you meant the subscription backend— the same shape as the existing mistyped-backend refusal. This is a breaking change for anyone relying on the bare shorthand; the release note says so, loudly.Acceptance criteria
grapharc run --model mock …(andmodels mock) refuse with a message naming the fix; the slash forms behave exactly as today; README/cookbook text describing the old behaviour is updated and its byte-compare tests pass.