Found while re-reviewing #892.
With a user row work in config.json and a project row WORK in the workspace's .zero/config.json, zero providers use WORK prints Active provider set to work and points activeProvider at the user row. The user asked for the project row and got the other endpoint.
This predates #892: main's SetActiveProvider matches with EqualFold first-match, so it does the same. #892 narrows it (identity normalization, ambiguity is an error) but keeps the redirect, and the mutation guard added there covers remove and rename only. The TUI's switch path already handles this case through ProviderRowOwnership and says why config.json was not updated; providers use has no such step.
Repro:
- user config: activeProvider "work", providers [{name "work", provider_kind openai}]
- workspace
.zero/config.json: providers [{name "WORK", provider_kind openai}]
- run
zero providers use WORK from that workspace
Actual: exit 0, Active provider set to work, config.json activeProvider is work.
Expected: a refusal that names the layer, along the lines of "WORK is a project provider; select it with ZERO_PROVIDER=WORK or in the project's .zero/config.json", and no write.
Persisting the exact spelling WORK instead would be worse: outside that workspace Resolve would fail on an active provider that no longer exists. Refusing with the reason, the way the TUI does, seems right.
Found while re-reviewing #892.
With a user row
workin config.json and a project rowWORKin the workspace's.zero/config.json,zero providers use WORKprintsActive provider set to workand points activeProvider at the user row. The user asked for the project row and got the other endpoint.This predates #892: main's SetActiveProvider matches with EqualFold first-match, so it does the same. #892 narrows it (identity normalization, ambiguity is an error) but keeps the redirect, and the mutation guard added there covers remove and rename only. The TUI's switch path already handles this case through ProviderRowOwnership and says why config.json was not updated;
providers usehas no such step.Repro:
.zero/config.json: providers [{name "WORK", provider_kind openai}]zero providers use WORKfrom that workspaceActual: exit 0,
Active provider set to work, config.json activeProvider iswork.Expected: a refusal that names the layer, along the lines of "WORK is a project provider; select it with ZERO_PROVIDER=WORK or in the project's .zero/config.json", and no write.
Persisting the exact spelling
WORKinstead would be worse: outside that workspace Resolve would fail on an active provider that no longer exists. Refusing with the reason, the way the TUI does, seems right.