My guess is: results of operations on arguments with different precision should have the lowest precision of all the arguments. Everything else would pretend a precision which isn’t there.

You’re right!
That does make sense.
I guess that I would like to have the lower precision number passed with zeros at the end.
For example, if I have something like this:

a=ArbFloat(0.2, bits=100)
b=ArbFloat(0.3, bits=1000)
function f(x, y)
a, b = promote(a, b)
a * b
end
f(a, b)

using ArbNumerics
const ArbFR = Union{ArbFloat, ArbReal}
promote_widen(a, b) = promote(a, b)
function promote_widen(a::ArbFR, b::ArbFR)
aprec, bprec = precision(a), precision(b)
if aprec == bprec
return a, b
end
if aprec < bprec
a = typeof(b)(a)
else
b = typeof(a)(b)
end
a, b
end
function times(a, b)
a, b = promote_widen(a, b)
a * b
end

then

a = 0.3f0
b = 0.7
x = ArbFloat(0.3, bits = 50)
y = ArbFloat(0.7, bits = 100)
ab = times(a, b);
bx = times(b, x);
xy = times(x, y);
a = 0.3f0
b = 0.7
x = ArbFloat(0.3, bits = 50)
y = ArbFloat(0.7, bits = 100)
aa = times(a, a);
ab = times(a, b);
bx = times(b, x);
xy = times(x, y);

we obtain

julia> precision(aa), aa
(24, 0.09f0)
julia> precision(ab), ab
(53, 0.21000000834465027)
julia> precision(bx), bx
(50, 0.21)
julia> precision(xy), xy
(100, 0.209999999999999978905762532122)