As an interviewer, I'm interested in your development process. So it's really valuable to see evidence of how you tested your code, preferably as a suite of unit tests. Without those, not only will I need to work harder, but I'll also be much more wary of the correctness.
Evidence of testing is of course helpful in any code review, so I encourage you to always present the tests along with the code. When reviewers can see what's been proved to be functionally correct (and more importantly, what has been missed from testing), then they can spend more time on the aspects that benefit from human inspection.
When implementing a type with a published interface, I believe it's important to implement exactly the interface that is specified. In this case, we've failed at pretty much the first hurdle:
optional(T&& value) noexcept;
This accepts only an rvalue, so there's no match here:
int a = 0;
optional<int> oa = a; // compilation error
The standard type's constructor accepts a forwarding reference, like this:
/* simplified */
template<class U> optional(U&& v);
Here, U can bind to any value or reference type, such as the lvalue a above.
Consider giving _engaged an in-class initialiser. Then we could write the default constructor as optional() noexcept = default.
It's good to see noexcept being used. However, I think it has been sprinkled a little too liberally. For example, the constructors assign a T&& to the _value member, which can throw unless std::std::is_nothrow_move_constructible_v<T>.
Similarly, the assignment operators of std::optional are specified to be noexcept(is_move_constructible_v<T> && is_move_assignable_v<T>).
In the specification, pretty much all of the interface is declared constexpr, but this code makes no attempt at that.
Another departure from specification is that conversions to T& or T&& are required to throw std::bad_optional_access if there's no contained value, but we just have the same UB as in operator*().
We're completely missing an implementation corresponding to std::optional::swap().
We're also missing the non-member parts of the interface (relational operators, make_optional(), nullopt_t and std::swap<optional>).
I find it surprising that we use std::construct_at() to create values, but use plain ~T() rather than the consistent std::destroy_at() in our reset().
A final note: be careful with identifiers beginning with underscore, particularly in places that also use the C language. While you might be fully conversant with the rules, your interviewer might not be; given the prospect of an in-depth language-lawyer argument, it might be better to deflect that well in advance.