Conversation
Fix all 15 `ExSlop.Check.Warning.DualKeyAccess` findings, then enable the check by removing it from `ex_slop_backlog`. The check fires on `||` chains that read one map with both an atom key and a string key. Each site now reads one key type. Backend config keeps one shape. `config_encrypted` round-trips through JSON, so it holds string keys after a raw `Repo.get` and atom keys after `typecast_config_string_map_to_atom_map/1`. Both shapes reached `Adaptor.cast_config/2`. `Backend.validate_config/1` now atomizes the existing config once, which matches the contract `redact_config/1` already had. The atomize helper moves out of the `Jason.Encoder` impl so both callers share it. The webhook, sentry and postgres adaptors drop their string branches. `Alerting.create_alert_query/2`, `Alerting.update_alert_query/2`, `Backends.update_backend/2` and `KeyValues.bulk_upsert_key_values/2` take attrs from both API params and internal callers. They now stringify the top level keys once through the new `Utils.Map.stringify_top_level_keys/1`, which leaves values untouched. In `update_backend/2` that also collapses the dual `Map.has_key?/2` reads. `LogEvent.mapper/3` reads string keys and returns a string-keyed body, so the atom branch in `id/1` is dead. The same holds for the params in `log_event_factory/1`, which stringifies them first. Verified with `MIX_ENV=test mix ci` and the affected test files. `mix ci` needs `MIX_ENV=test`, because the reach baseline was written for that scope. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YQ8Y8zCvSKUFNPvkwH2WS4
`Backends.update_backend/2` read `alert_queries` after the stringify, so a
string key in an API request body reached `put_assoc`. The association is
`on_replace: :delete`, so `PATCH /api/backends/:token` with
`{"alert_queries": []}` deleted every join row for that backend. The function
now reads the atom key from the original attrs, which keeps the old semantics.
A regression test covers it.
`Backend.validate_config/1` called `String.to_existing_atom/1` on every
changeset, so a stored config key with no live atom raised instead of returning
a changeset error. It now normalizes the stored config through the adaptor's
own `cast_config/1`, the same way
`Backends.typecast_config_string_map_to_atom_map/1` does. That drops no atoms
into the table and ignores keys no adaptor declares. The `Jason.Encoder` helper
goes back to private.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YQ8Y8zCvSKUFNPvkwH2WS4
|
Pushed 1. 2. Verified with |
|
@claude please review this PR. |
|
Claude finished @chasers's task in 5m 5s —— View job ReviewWent through both commits (
First commit's core simplifications check out:
Minor observations (not blockers):
Verification note: I was not able to run No blocking issues found. Branch · |
Fixes all 15
ExSlop.Check.Warning.DualKeyAccessfindings, then enables the check by removing it fromex_slop_backloginconfig/.credo.exs. The backlog drops from 10 checks to 9.The check fires on
||chains that read one map with both an atom key and a string key. Each site now reads one key type.Backend config keeps one shape
config_encryptedround-trips through JSON, so it holds string keys after a rawRepo.getand atom keys aftertypecast_config_string_map_to_atom_map/1. Both shapes reachedAdaptor.cast_config/2, so the webhook adaptor read each field twice.Backend.validate_config/1now atomizes the existing config once. This matches the contractredact_config/1already had, documented on theJason.Encoderimpl. The atomize helper moves out of that impl so both callers share it. The webhook, sentry and postgres adaptors drop their string branches.Attrs normalize at the context boundary
Alerting.create_alert_query/2,Alerting.update_alert_query/2,Backends.update_backend/2andKeyValues.bulk_upsert_key_values/2take attrs from both API params and internal callers. They stringify the top level keys once through the newUtils.Map.stringify_top_level_keys/1, which leaves values untouched. A deep stringify would corrupt struct and payload values. Inupdate_backend/2this also collapses the dualMap.has_key?/2reads.Dead branches
LogEvent.mapper/3reads string keys and returns a string-keyed body, so the atom branch inid/1never ran. The same holds for the params inlog_event_factory/1, which stringifies them first.Verification
MIX_ENV=test mix cipasses. Credo now runs 75 checks, up from 74.Test files run: backends, alerting, key_values, log_event, logs, utils, the webhook, sentry and postgres adaptors, the backend, rule and key value controllers, and the alerts and rules LiveViews. All pass.
Note for reviewers:
mix cifails underMIX_ENV=dev, because the reach baseline was written for the test scope and dev addspriv/tasks. RunMIX_ENV=test mix cilocally, as CI does. That is pre-existing and out of scope here.🤖 Generated with Claude Code
https://claude.ai/code/session_01YQ8Y8zCvSKUFNPvkwH2WS4