As far as I understand due to map being a parameter to mk_vec and by applying lifetime elision rules, the &str in vec will have the same lifetime as map. At the end of mk_ctxmap is moved to ctx.map. I would assume that vec can be moved to ctx.vec as well.
What is the issue here and how can the code be fixed?
You are trying to create a self-referential struct, which are borderline useless types and therefore best to be avoided. If you can't find a better abstraction for your problem, libraries like ouroboros and yoke provide safe abstractions for creating usable self-referential structs.
The mk_vec function as you have written needs to return string slices with an unbounded lifetime 'b. Effectively the only way to implement mk_vec is returning either an empty Vec or a Vec of &'static strs, both of which are not reasonable.
Whenever you think that specifying some lifetime annotation will make a piece of code compile you also need to make sure that other pieces of code will be able to compile, otherwise you're just moving some unreasonable constraints from one place to the other, ultimately just wasting your time.
I'm not sure how that confirms OP's analysis. From what I see their analysis is:
given the lifetime elision in mk_vec, vec borrows from map
map is moved in the Ctx
hence vec should be able to be moved too
This is incorrect, because the last point is wrong. Your playground however changes the assumption in the first point by making vec no longer borrow from map. This changes everything and makes any conclusion useless
Lifetimes on structs refer to data in a larger scope, one that is not in the struct.
This is the "outlives" relationship. The data borrowed for the scope 'a may exist before Ctx<'a> is created, and keep existing after Ctx<'a> is destroyed. This means the temporarily borrowed data can't be stored in the struct itself.