@@ -543,6 +543,86 @@ public void testProvenDeadSealedResidueSanitizedThenHealsAfterOneRestart() throw
543543 });
544544 }
545545
546+ /**
547+ * The legacy-migration twin of
548+ * {@link #testProvenDeadSealedResidueSanitizedThenHealsAfterOneRestart}:
549+ * the SAME proven-dead sealed residue, but already on disk BEFORE the
550+ * first recovery ever runs — a pre-manifest slot written by a pre-fix
551+ * client. Legacy slots predate the fail-closed sealed-suffix contract,
552+ * so migration must zero the residue SILENTLY (no first-sight throw)
553+ * and hand the manifest era a chain that already satisfies the
554+ * all-zero sealed-suffix invariant — the next restart comes up clean
555+ * instead of tripping a spurious {@link SfSanitizedResidueException}
556+ * over bytes migration should have healed.
557+ */
558+ @ Test
559+ public void testLegacyMigrationSilentlySanitizesProvenDeadSealedResidue () throws Exception {
560+ TestUtils .assertMemoryLeak (() -> {
561+ long segSize = MmapSegment .HEADER_SIZE
562+ + 4 * (MmapSegment .FRAME_HEADER_SIZE + 16 )
563+ + 12 ; // sealed suffix gap that can never fit a frame
564+ String m0Path = tmpDir + "/q0.sfa" ;
565+ String m1Path = tmpDir + "/q1.sfa" ;
566+ long buf = Unsafe .malloc (16 , MemoryTag .NATIVE_DEFAULT );
567+ try {
568+ fillPattern (buf , 16 , 6 );
569+ MmapSegment s0 = MmapSegment .create (m0Path , 0 , segSize );
570+ for (int i = 0 ; i < 4 ; i ++) s0 .tryAppend (buf , 16 );
571+ long gapStart = s0 .publishedOffset ();
572+ s0 .close ();
573+ MmapSegment s1 = MmapSegment .create (m1Path , 4 , segSize );
574+ s1 .tryAppend (buf , 16 );
575+ s1 .close ();
576+ // Poison the sealed suffix gap BEFORE any recovery: no
577+ // manifest exists yet, so this is a legacy slot carrying
578+ // pre-fix-client residue into migration.
579+ int fd = Files .openRW (m0Path );
580+ assertTrue ("openRW must succeed" , fd >= 0 );
581+ long junk = Unsafe .malloc (12 , MemoryTag .NATIVE_DEFAULT );
582+ try {
583+ for (int i = 0 ; i < 3 ; i ++) {
584+ Unsafe .getUnsafe ().putInt (junk + i * 4L , 0xCAFEBABE );
585+ }
586+ assertEquals (12L , Files .write (fd , junk , 12 , gapStart ));
587+ Files .fsync (fd );
588+ } finally {
589+ Unsafe .free (junk , 12 , MemoryTag .NATIVE_DEFAULT );
590+ Files .close (fd );
591+ }
592+ // Migration: contiguity proves the residue dead, so the
593+ // legacy chain recovers in ONE pass — silently.
594+ try (SegmentRing ring = SegmentRing .openExisting (tmpDir , segSize )) {
595+ assertNotNull ("legacy migration must not fail closed over "
596+ + "proven-dead sealed residue" , ring );
597+ assertEquals (1 , ring .getSealedSegments ().size ());
598+ assertEquals (4 , ring .getSealedSegments ().get (0 ).frameCount ());
599+ assertEquals (4 , ring .getActive ().baseSeq ());
600+ }
601+ // The silent heal: residue durably zeroed, frames intact,
602+ // slot migrated to the manifest era.
603+ try (MmapSegment seg = MmapSegment .openExisting (m0Path )) {
604+ assertEquals ("frames must be untouched" , 4L , seg .frameCount ());
605+ assertEquals ("legacy migration must durably zero the dead residue" ,
606+ 0L , seg .tornTailBytes ());
607+ }
608+ assertTrue ("legacy migration must create the manifest" ,
609+ Files .exists (tmpDir + "/sf-manifest.bin" ));
610+ // The manifest-era invariant holds: the restart's fail-closed
611+ // sealed-suffix pass finds nothing to surface. A
612+ // SfSanitizedResidueException here means migration skipped
613+ // the sanitize and deferred the incident to production's
614+ // next restart.
615+ try (SegmentRing ring = SegmentRing .openExisting (tmpDir , segSize )) {
616+ assertNotNull ("restart over the migrated chain must come up clean" , ring );
617+ assertEquals (1 , ring .getSealedSegments ().size ());
618+ assertEquals (5 , ring .nextSeqHint ());
619+ }
620+ } finally {
621+ Unsafe .free (buf , 16 , MemoryTag .NATIVE_DEFAULT );
622+ }
623+ });
624+ }
625+
546626 @ Test
547627 public void testRingRecoverySanitizesResumedActiveTornTail () throws Exception {
548628 TestUtils .assertMemoryLeak (() -> {
0 commit comments