Yes, Python and Ruby both have JIT compilers, but they do not operate in the same way that Julia's JIT operates.
Numba is a tracing JIT -- Julia does not do that. It precompiles a static CFG (as much of the CFG as inference can concretize) before runtime.
For the parts of the CFG where inference cannot explore call edges, special calls are inserted which allows the runtime to return back to inference when the types are known.
Julia does not have a fallback "tracing interpreter" at all, it's all compilation. When compilation occurs and how it occurs for any specific user program depends greatly on how abstract interpretation learns about the CFG.
As to your latter comments, they are all false as well. Julia does not recompile Plots.jl every time you make a change to your script -- Plots.jl precompiles once, and only recompiles if a method definition invalidates something which has already been precompiled. The specific mechanism/relationship which Julia uses to detect an invalidation is called a call backedge -- you can think of it as a relationship between callers and callees, but designed to handle multiple dispatch and the specialization that that entails.
The first time precompilation is slow -- because Julia is literally running type inference and then caching all parts of the CFG which could be inferred. But unless you doing things which would (in general) not be performant (like invalidating a ton of cached method instances) -- the full precompilation stage should never occur again.
But you asked for formal proof. I suppose I can't furnish this -- but can only give the operational semantics defined by https://github.com/JuliaLang/julia/tree/master/base/compiler. Good luck!