The remaining @dialyzer {:no_opaque, ...} / {:nowarn_function, ...}
directives in accounts.ex, devices.ex, organizations.ex all masked the
same upstream issue: Ecto.Multi.new/0 produces a struct containing a
literal %MapSet{map: %{}} whose concrete shape violates MapSet's
@opaque t at every subsequent Ecto.Multi.* call boundary.
Tried first: public helper function with @spec Ecto.Multi.t() — confirmed
dialyzer uses success typing of the body, not the spec. Doesn't help.
Real fix: drop Ecto.Multi entirely for these transactions. Each was
performing a small, sequential set of Repo operations that map cleanly
to a plain `Repo.transaction(fn -> ... end)` block with Repo.rollback
on errors. No Multi machinery is actually needed:
- accounts.ex:
- register_user/1: insert + 0-2 consent grants
- register_user_with_organization/1: insert + create_org + consents
- confirm_user_transaction/1: update + delete_all tokens
- organizations.ex:
- do_create_organization/4: lock user → limit check → insert org + membership
- set_default_organization/2: two update_alls
- accept_invitation/2: update invitation + insert membership
- devices.ex:
- create_device/2: maybe lock org → maybe quota check → insert
Caught a real consent-failure rollback bug along the way: initial
refactor discarded the return of grant_consents_sequential/2, which
meant FK violations on consent insert would abort the transaction at
the Postgres level but the caller still saw {:ok, user} — later
operations in the transaction silently failed with 25P02. Fixed by
propagating the {:error, changeset} up so Repo.rollback is called.
Verified by the AccountsDefensiveCoverageTest regression tests.
Behavior is preserved — same transactional guarantees, same success
/ error tuple shapes. Net -86 LOC and no suppressions.
mix dialyzer: `done (passed successfully)` with zero @dialyzer
directives in lib/.
|
||
|---|---|---|
| .. | ||
| mix/tasks | ||
| snmpkit | ||
| towerops | ||
| towerops_web | ||
| snmp_lib.ex | ||
| snmp_mgr.ex | ||
| snmpkit.ex | ||
| towerops.ex | ||
| towerops_native.ex | ||
| towerops_web.ex | ||