I would recommend the Gardner Timing Error Detector vs the CORDIC for determining timing error for use in a timing recovery loop. (The CORDIC is an algorithm of choice when we desire to trade iteration for computation of accurate phase, but the computations required for the Gardner are so minimal that this point is mute). The Gardner works with only two samples per symbol and up to very large carrier offsets up to a quarter of the symbol rate). Any given single sample from the Gardner will not be necessarily accurate (has self noise) but for use in a timing recovery loop (which provides the average over several samples) will converge to low phase error, so do not be discouraged in the accuracy of any one given sample from the Gardner or any other timing error detector for this purpose in a tracking loop.
The OP also mentions making use of the largest sample, but with observation of an eye pattern of raised cosine pulse shaped waveforms with tighter bandwidths (see Eye pattern construction and interpretation) it is clear that the largest sample is NOT at the ideal sampling location. Also I would advise on ensuring both carrier offset and timing offset is being addressed as these are two separate and independent offsets that need to be corrected in independently operating receivers.
The links below provide the implementation details of the Gardner Loop for determining the timing error from the samples with the sampling rate decimated to two samples per symbol. The error is accumulated in a loop filter (for a simple first order loop, just accumulate the error samples and multiply by the loop gain as needed for stability (due to parasitic delays it will be unstable if the gain is too high) and to adjust the loop bandwidth. A typical rule of thumb for the loop bandwidth is to use a small fraction of the symbol rate (such as 1/20th or less).
The accumulated error (which should converge to zero) controls a variable delay element: this element has nominal delay when the accumulated error is zero, and can shift the waveform forward and reverse by small incremental delays based on the accumulated error being positive or negative (in such a way to drive the error to zero). This is a simple first order delay lock loop with one integrator element (the accumulator). Depending on design requirements (dynamics and tracking requirements), this can be expanded into a 2nd order loop with an additional accumulator and direct control path (forming a Proportional-Integral Loop Filter), but this complexity won't be necessary for an initial demonstration. It would be simplest without getting into control loop theory and modelling to set up a simple demonstration with a waveform that has a static timing error and start with a very small multiplier in the accumulator (meaning multiply the error from the timing error detector by 0.01 for example and then add that result to the accumulated result) such that convergence is very slow. Then increase that multiplier to observe the increase in convergence rate. At the lower convergence rate (narrower loop BW) the self noise from the detector as well as other noise sources in the signal itself are significantly filtered, so ultimately there is a trade between desired dynamics (how fast we want to track) and noise that gets added.
To implement the variable delay element used for delay correction, interpolators are often used and polyphase filters are great for this since with that you don't actually have to increase the sampling rate. Farrow filters are another option (see https://www.dsprelated.com/showarticle/22.php). For more details on the polyphase interpolator for variable delay, see:
Emulating a Variable Delay
Fractional Delay using Polyphase Filter
How to implement Polyphase filter?
Please also see the following posts with further details of this:
Fractional spaced equalizer + timing (clock) recovery
Gardner Timing Recovery for Repeated Symbols
Isn't Gardner's algorithm and Early-Late gate the same thing?
Symbol timing synchronization using a high sampling rate
Recovering signal for psk (this last link provides an example of a carrier recovery loop but does not show timing recovery, but shows a similar loop structure of two accumulators as a PI Loop, here the second accumulator is part of the NCO).
For AGC: Role of Power Metric and LPF in AGC(Automatic Gain Controller)