jp config set reports success for a clear it never records
- Status: Todo
- Kind: Bug
- Authors: jp
- Date: 2026-09-16
- Label: client=cli
- Label: domain=conversation
- Label: package=jp_cli
- Label: type=bug
jp config set --id <id> --cfg assistant.name:=null prints Set configuration in conversation <id> and records nothing. The same argument through jp query records a delta whose unsets holds assistant.name, and the option stays cleared for the rest of the conversation.
Why
Set::run builds its payload with config_pipeline::build_partial_from_cfg_args (crates/jp_cli/src/cmd/config/set.rs:28), which applies the arguments onto PartialAppConfig::empty() (config_pipeline.rs:578). A :=null assignment clears a field, so clearing a field of an already-empty partial produces an empty partial: the payload carries no trace of what the user asked to clear.
override_to_record then merges that empty partial onto the conversation's accumulated state, resolves both sides, finds them equal, and returns None (config_pipeline.rs:64-78), so no ConfigDelta is appended. The success line is printed unconditionally afterwards (set.rs:68-69).
The file target has the same hole: set_in_file merges the empty partial into the config file and writes it back unchanged (set.rs:85-90).
A partial cannot express "cleared" — that is what ApplyDelta::unsets exists for (RFD 070). The query path reaches it through turn_config_delta/delta_with_unsets (cmd/query.rs:2333-2351); the config set path has no equivalent.
Fix
Carry the cleared paths alongside the partial, the way the conversation layer now does: have build_partial_from_cfg_args report the paths its arguments cleared, and have set_in_conversations pass them to ApplyDelta::with_unsets so a clear becomes a recorded delta. For the file target, a clear means removing the key from the file, which ConfigFile's format-preserving edit already knows how to express.
Failing either, the command should refuse :=null with an error naming the working alternative, rather than reporting a change it did not make.
Verifying
A test asserting that jp config set --id <id> --cfg assistant.name:=null leaves the conversation resolving assistant.name to None on the next invocation, mirroring resolve_config_keeps_a_cleared_conversation_field_across_invocations in crates/jp_cli/src/cmd/query_tests.rs.