replacing crystal with TCXO

It's a nice library. And making it more robust, even if the odds of failure are low, isn't going to cost much. In fact a burst read is faster since you don't have to keep toggling the CS line. I was curious why you didn't use hardware SPI as well. Speed when reading an RTC usually isn't an issue, but someone who is already using the SPI bus would have to use additional pins with your library. And since software SPI is slower it increases the small chance of a rollover read error.

I wrote a quick and dirty sketch to see if I could get this error to occur. I was surprised how easy it was. Here's a sketch that caused the glitch almost every time. I was using an Uno. Since the timing is critical it might not show up if you try it. One way to increase the odds is to insert a delay between the two reads (there is a commented out delay there). The sketch is setting the time to 00:59 and waiting for a rollover. It should read 1:00 but I was catching it reporting 1:59.

#define BURST_READ  0    // set to 1 for burst read, 0 for one at a time

#define SS_PIN    10
#define CLK_PIN   13
#define MISO_PIN  12
#define MOSI_PIN  11

void setup()
{
  Serial.begin(115200);
  Serial.println("\nRTC glitch test.\n");

  pinMode(SS_PIN, OUTPUT);
  digitalWrite(SS_PIN, HIGH);
  
  pinMode(CLK_PIN, OUTPUT);
  pinMode(MOSI_PIN, OUTPUT);
  pinMode(MISO_PIN, INPUT);
  
  spi_command(0x8E, 0x04);    // make sure it's running
  spi_command(0x8F, 0x00);
}

void loop()
{
  uint8_t secs, mins;
  
  spi_command(0x80, 0x59);		// write seconds = 59
  spi_command(0x81, 0x00);		// write minutes = 00

  while (1) {
#if BURST_READ
    burst(&secs, &mins);
#else
    secs = spi_command(0x00, 0x00);	// read seconds
//    delay(10);                          // inserting delay increases odds of error
    mins = spi_command(0x01, 0x00);	// read minutes
#endif
    if ((secs == 0x00) || (mins == 0x01)) {    // if rollover
      displayMMSS(mins, secs);   
      break;
    }
  }
}

void displayMMSS(uint8_t mins, uint8_t secs)
{
  twoDigitBCD(mins);
  Serial.print(":");
  twoDigitBCD(secs);
  Serial.println();
}

void twoDigitBCD(uint8_t val) {
  
  Serial.print(val >> 4, HEX);
  Serial.print(val & 0xF, HEX);
}

uint8_t spi_command (uint8_t cmd, uint8_t data)
{
	digitalWrite (SS_PIN, LOW);
	spi_transfer (cmd);
	cmd = spi_transfer (data);
	digitalWrite (SS_PIN, HIGH);
	return cmd;
}

// transfer one byte via SPI Mode 3
uint8_t spi_transfer (uint8_t data)
{
	uint8_t bits;

	bits = 8;

	while (bits--) {
		digitalWrite (CLK_PIN, LOW);
		digitalWrite (MOSI_PIN, data & _BV (bits) ? HIGH : LOW);
		digitalWrite (CLK_PIN, HIGH);
		digitalRead (MISO_PIN) ? data |= _BV (bits) : data &= ~_BV (bits);
	}

	return data;
}

void burst(uint8_t *secs, uint8_t *mins)
{
  digitalWrite(SS_PIN, LOW);
  spi_transfer(0x00);
  *secs = spi_transfer(0x00);
  *mins = spi_transfer(0x00);
  digitalWrite(SS_PIN, HIGH);
}

I'm kind of surprised that Maxim didn't make it clearer in their datasheet. I guess the odds of it causing a problem are pretty low. Here's what is in the datasheet of a sensor I'm using: "To read out data after a conversion, it is strongly recommended to use a burst read and not address every register individually. This will prevent a possible mix-up of bytes belonging to different measurements and reduce interface traffic." Even they aren't adamant about it.

Output of sketch in non-burst mode:

RTC glitch test.

01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:00
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:00
01:59
01:59
01:59
01:59
01:59
01:59
01:00
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:00
01:59
01:59
01:59
01:59
01:59
01:59
01:00
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:00
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59
01:59