I think this is always going to be a problem when the validation checks are private, and that the solution is to declare a function to do the check:
package RingBuffer is
function Is_Full return Boolean;
procedure Push(value: T) with Pre => not Is_Full;
function Pop return T;
(Is_Full
is probably useful anyway; in other cases it might not be so).
If you leave the implementation in the package body, you’ll need to put Is_Full
there too, but you could move them to the spec and use an expression function:
package RingBuffer is
function Is_Full return Boolean;
procedure Push(value: T) with Pre => not Is_Full;
function Pop return T;
private
buffer: array(0..size) of T;
readptr: integer := 0;
writeptr: integer := 1;
function Is_Full return Boolean is (Readptr = Writeptr);
end RingBuffer;