I agree with you but still want to play devil's advocate regarding you argument:
> [It's easier to write specifications than implementations because] in a specification I can specify outcomes without having to say how they're achieved
It's even easier to write a few "unit tests" that "specify" intended behavior, write code that passes those tests, and then worry what to do in edge-cases when they happen. This way, "correct" isn't a meaningful category, there's only "incorrect in retrospect". This is how most software is made and for most applications I would expect cost-benefit analysis to favor it.
I can easily write a specification for a function that says: given input integer n (n>2) return a vector of integer values (a, b, c) such that a^n + b^n = c^n or return an error if no such value exists. I invite you to write a concise unit test of the implementation of said function!
> It's even easier to write a few "unit tests" that "specify" intended behavior, write code that passes those tests, and then worry what to do in edge-cases when they happen.
It's even even easier to write a specification that says "if this case, do this; if that case, do that; otherwise, do whatever". Just use your proof language's implication symbol. (this ==> THIS) && (that ==> THAT), done.
> [It's easier to write specifications than implementations because] in a specification I can specify outcomes without having to say how they're achieved
It's even easier to write a few "unit tests" that "specify" intended behavior, write code that passes those tests, and then worry what to do in edge-cases when they happen. This way, "correct" isn't a meaningful category, there's only "incorrect in retrospect". This is how most software is made and for most applications I would expect cost-benefit analysis to favor it.