From 29f1afa5fff5440ad5ce7dd40dee1053ea0ff7bf Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期三, 02 九月 2026 12:14:46 +0800
Subject: [PATCH] 彻底删除补采完整性与断线恢复遗留代码

---
 /dev/null                                                                         |   33 ----------------
 ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestServiceImplTest.java |    2 -
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java               |   68 ----------------------------------
 3 files changed, 0 insertions(+), 103 deletions(-)

diff --git a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/CollectorDisconnectRecoveryServiceImplTest.java b/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/CollectorDisconnectRecoveryServiceImplTest.java
deleted file mode 100644
index 1c2c636..0000000
--- a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/CollectorDisconnectRecoveryServiceImplTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.time.Instant;
-import java.util.List;
-import java.util.Set;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import com.ruoyi.system.domain.TTestCollectorExceptionInterval;
-import com.ruoyi.system.domain.TTestCollectorSource;
-import com.ruoyi.system.mapper.TTestMapper;
-
-/** 采集器断线对账的来源级幂等与恢复边界测试。 */
-@ExtendWith(MockitoExtension.class)
-class CollectorDisconnectRecoveryServiceImplTest
-{
-    @Mock private TTestMapper mapper;
-    @InjectMocks private CollectorDisconnectRecoveryServiceImpl service;
-
-    @Test
-    void opensOnlyOfflineSourceAndKeepsOtherSourcesIndependent()
-    {
-        TTestCollectorSource offline = source(10L, 20L, 8L, "COL-1", "S-01");
-        TTestCollectorSource online = source(10L, 20L, 9L, "COL-2", "S-01");
-        when(mapper.selectReceivingCollectorSources()).thenReturn(List.of(offline, online));
-        when(mapper.selectOpenCollectorException(10L, 20L, 8L, "S-01")).thenReturn(null);
-        when(mapper.selectOpenCollectorException(10L, 20L, 9L, "S-01")).thenReturn(null);
-
-        service.reconcile(Set.of("COL-2"), Instant.parse("2026-08-30T09:00:00Z"));
-
-        verify(mapper).insertCollectorExceptionInterval(any(TTestCollectorExceptionInterval.class));
-        verify(mapper, never()).closeCollectorExceptionInterval(any(), any(), any());
-    }
-
-    @Test
-    void closesOpenIntervalAtRecoveryBoundary()
-    {
-        TTestCollectorSource source = source(10L, 20L, 8L, "COL-1", "S-01");
-        TTestCollectorExceptionInterval open = new TTestCollectorExceptionInterval();
-        open.setIntervalId(99L);
-        open.setIntervalStatus("OPEN");
-        when(mapper.selectReceivingCollectorSources()).thenReturn(List.of(source));
-        when(mapper.selectOpenCollectorException(10L, 20L, 8L, "S-01")).thenReturn(open);
-
-        service.reconcile(Set.of("COL-1"), Instant.parse("2026-08-30T09:01:00Z"));
-
-        verify(mapper).closeCollectorExceptionInterval(eq(99L), any(), any());
-        verify(mapper, never()).insertCollectorExceptionInterval(any());
-    }
-
-    @Test
-    void allowsAnotherDisconnectCycleAfterPreviousIntervalWasClosed()
-    {
-        TTestCollectorSource source = source(10L, 20L, 8L, "COL-1", "S-01");
-        TTestCollectorExceptionInterval first = openInterval(99L);
-        TTestCollectorExceptionInterval second = openInterval(100L);
-        when(mapper.selectReceivingCollectorSources()).thenReturn(List.of(source));
-        when(mapper.selectOpenCollectorException(10L, 20L, 8L, "S-01"))
-                .thenReturn(null, first, null, second);
-
-        service.reconcile(Set.of(), Instant.parse("2026-08-30T09:00:00Z"));
-        service.reconcile(Set.of("COL-1"), Instant.parse("2026-08-30T09:01:00Z"));
-        service.reconcile(Set.of(), Instant.parse("2026-08-30T09:02:00Z"));
-        service.reconcile(Set.of("COL-1"), Instant.parse("2026-08-30T09:03:00Z"));
-
-        verify(mapper, org.mockito.Mockito.times(2)).insertCollectorExceptionInterval(any());
-        verify(mapper).closeCollectorExceptionInterval(eq(99L), any(), any());
-        verify(mapper).closeCollectorExceptionInterval(eq(100L), any(), any());
-    }
-
-    private TTestCollectorExceptionInterval openInterval(Long intervalId)
-    {
-        TTestCollectorExceptionInterval interval = new TTestCollectorExceptionInterval();
-        interval.setIntervalId(intervalId);
-        interval.setIntervalStatus("OPEN");
-        return interval;
-    }
-
-    private TTestCollectorSource source(Long testId, Long relationId, Long collectorId,
-            String collectorCode, String channelCode)
-    {
-        TTestCollectorSource source = new TTestCollectorSource();
-        source.setTestId(testId); source.setBatteryRelationId(relationId); source.setCollectorId(collectorId);
-        source.setCollectorCode(collectorCode); source.setBatteryNo("BAT-01"); source.setChannelCode(channelCode);
-        return source;
-    }
-}
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/IntervalIntegrityCheckerTest.java b/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/IntervalIntegrityCheckerTest.java
deleted file mode 100644
index fd8a10b..0000000
--- a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/IntervalIntegrityCheckerTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.util.Arrays;
-import java.util.List;
-import org.junit.jupiter.api.Test;
-
-/** 区间完整性序号检查的外部行为测试。 */
-class IntervalIntegrityCheckerTest
-{
-    @Test
-    void ignoresDuplicatesAndOutOfOrderSamples()
-    {
-        assertEquals(List.of(new IntervalIntegrityChecker.Gap(3, 3), new IntervalIntegrityChecker.Gap(5, 5)),
-                IntervalIntegrityChecker.gaps(List.of(4L, 1L, 2L, 4L, 6L)));
-    }
-
-    @Test
-    void treatsEachReceptionIntervalIndependently()
-    {
-        assertEquals(List.of(), IntervalIntegrityChecker.gaps(List.of(1L, 2L)));
-        assertEquals(List.of(), IntervalIntegrityChecker.gaps(List.of(8L, 9L)));
-    }
-
-    @Test
-    void reportsMultipleOpenGaps()
-    {
-        assertEquals(List.of(new IntervalIntegrityChecker.Gap(3, 4), new IntervalIntegrityChecker.Gap(7, 8)),
-                IntervalIntegrityChecker.gaps(List.of(1L, 2L, 5L, 6L, 9L)));
-    }
-
-    @Test
-    void doesNotTreatPauseOrHandoverAsAnIntraIntervalGap()
-    {
-        assertEquals(List.of(), IntervalIntegrityChecker.gaps(List.of(10L, 11L)));
-        assertEquals(List.of(), IntervalIntegrityChecker.gaps(List.of(20L, 21L)));
-    }
-
-    @Test
-    void emptyIntervalHasNoSyntheticSequenceGap()
-    {
-        assertEquals(List.of(), IntervalIntegrityChecker.gaps(List.of()));
-    }
-
-    @Test
-    void filtersInvalidSequenceValuesWithoutInventingGaps()
-    {
-        assertEquals(List.of(), IntervalIntegrityChecker.gaps(Arrays.asList(null, 0L, -1L, 5L)));
-    }
-
-    @Test
-    void remainsStableAcrossReplayPermutationsAndDuplicates()
-    {
-        List<IntervalIntegrityChecker.Gap> expected = List.of(
-                new IntervalIntegrityChecker.Gap(3, 3), new IntervalIntegrityChecker.Gap(6, 7));
-        List<List<Long>> replays = List.of(
-                List.of(8L, 1L, 2L, 4L, 5L, 8L),
-                List.of(1L, 8L, 5L, 4L, 2L, 5L),
-                List.of(2L, 4L, 1L, 8L, 4L, 5L));
-        for (List<Long> replay : replays) assertEquals(expected, IntervalIntegrityChecker.gaps(replay));
-        assertEquals(expected, IntervalIntegrityChecker.gaps(replays.get(0)));
-    }
-}
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestServiceImplTest.java b/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestServiceImplTest.java
index fea0c55..561b2de 100644
--- a/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestServiceImplTest.java
+++ b/ruoyi-admin/src/test/java/com/ruoyi/system/service/impl/TTestServiceImplTest.java
@@ -535,8 +535,6 @@
 
         assertEquals(1, testService.stopTest(10L, 7L, "operator"));
         verify(testMapper).updateReceptionStopped(eq(10L), eq("operator"), any());
-        verify(testMapper, never()).deleteChannelLeasesByTestId(anyLong());
-        verify(testMapper, never()).deleteCollectorChannelLeasesByTestId(anyLong());
         verify(testMapper).insertTestAudit(eq(10L), eq("TEST_STOPPED"), eq(7L), eq("operator"), isNull(),
                 org.mockito.ArgumentMatchers.argThat(value -> value != null && value.contains("COMPLETED")));
     }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestBackfillCursor.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestBackfillCursor.java
deleted file mode 100644
index 5d5f802..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestBackfillCursor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.ruoyi.system.domain;
-
-import java.util.Date;
-
-/** 测试来源历史补采的可恢复游标。 */
-public class TTestBackfillCursor
-{
-    private Long cursorId;
-    private Long testId;
-    private Long bindingId;
-    private String sourceType;
-    private Long sourceId;
-    private String sourceChannelCode;
-    private String protocolTestId;
-    private Long nextPosition;
-    private String sourceStatus;
-    private String protocolMetadata;
-    private String lastError;
-    private Date updatedAtUtc;
-
-    public Long getCursorId() { return cursorId; }
-    public void setCursorId(Long value) { cursorId = value; }
-    public Long getTestId() { return testId; }
-    public void setTestId(Long value) { testId = value; }
-    public Long getBindingId() { return bindingId; }
-    public void setBindingId(Long value) { bindingId = value; }
-    public String getSourceType() { return sourceType; }
-    public void setSourceType(String value) { sourceType = value; }
-    public Long getSourceId() { return sourceId; }
-    public void setSourceId(Long value) { sourceId = value; }
-    public String getSourceChannelCode() { return sourceChannelCode; }
-    public void setSourceChannelCode(String value) { sourceChannelCode = value; }
-    public String getProtocolTestId() { return protocolTestId; }
-    public void setProtocolTestId(String value) { protocolTestId = value; }
-    public Long getNextPosition() { return nextPosition; }
-    public void setNextPosition(Long value) { nextPosition = value; }
-    public String getSourceStatus() { return sourceStatus; }
-    public void setSourceStatus(String value) { sourceStatus = value; }
-    public String getProtocolMetadata() { return protocolMetadata; }
-    public void setProtocolMetadata(String value) { protocolMetadata = value; }
-    public String getLastError() { return lastError; }
-    public void setLastError(String value) { lastError = value; }
-    public Date getUpdatedAtUtc() { return updatedAtUtc; }
-    public void setUpdatedAtUtc(Date value) { updatedAtUtc = value; }
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestCollectorExceptionInterval.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestCollectorExceptionInterval.java
deleted file mode 100644
index 798f595..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestCollectorExceptionInterval.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.ruoyi.system.domain;
-
-import java.util.Date;
-
-/** 采集器来源断线期间的只追加事实。关闭动作只补写恢复边界。 */
-public class TTestCollectorExceptionInterval
-{
-    private Long intervalId;
-    private Long testId;
-    private Long batteryRelationId;
-    private Long collectorId;
-    private String collectorCode;
-    private String collectorName;
-    private String collectorChannelCode;
-    private String measurementName;
-    private String exceptionType;
-    private Date openedAtUtc;
-    private Date missingFromUtc;
-    private Date recoveredAtUtc;
-    private Date missingToUtc;
-    private String intervalStatus;
-    private String detail;
-
-    public Long getIntervalId() { return intervalId; }
-    public void setIntervalId(Long intervalId) { this.intervalId = intervalId; }
-    public Long getTestId() { return testId; }
-    public void setTestId(Long testId) { this.testId = testId; }
-    public Long getBatteryRelationId() { return batteryRelationId; }
-    public void setBatteryRelationId(Long batteryRelationId) { this.batteryRelationId = batteryRelationId; }
-    public Long getCollectorId() { return collectorId; }
-    public void setCollectorId(Long collectorId) { this.collectorId = collectorId; }
-    public String getCollectorCode() { return collectorCode; }
-    public void setCollectorCode(String collectorCode) { this.collectorCode = collectorCode; }
-    public String getCollectorName() { return collectorName; }
-    public void setCollectorName(String collectorName) { this.collectorName = collectorName; }
-    public String getCollectorChannelCode() { return collectorChannelCode; }
-    public void setCollectorChannelCode(String collectorChannelCode) { this.collectorChannelCode = collectorChannelCode; }
-    public String getMeasurementName() { return measurementName; }
-    public void setMeasurementName(String measurementName) { this.measurementName = measurementName; }
-    public String getExceptionType() { return exceptionType; }
-    public void setExceptionType(String exceptionType) { this.exceptionType = exceptionType; }
-    public Date getOpenedAtUtc() { return openedAtUtc; }
-    public void setOpenedAtUtc(Date openedAtUtc) { this.openedAtUtc = openedAtUtc; }
-    public Date getMissingFromUtc() { return missingFromUtc; }
-    public void setMissingFromUtc(Date missingFromUtc) { this.missingFromUtc = missingFromUtc; }
-    public Date getRecoveredAtUtc() { return recoveredAtUtc; }
-    public void setRecoveredAtUtc(Date recoveredAtUtc) { this.recoveredAtUtc = recoveredAtUtc; }
-    public Date getMissingToUtc() { return missingToUtc; }
-    public void setMissingToUtc(Date missingToUtc) { this.missingToUtc = missingToUtc; }
-    public String getIntervalStatus() { return intervalStatus; }
-    public void setIntervalStatus(String intervalStatus) { this.intervalStatus = intervalStatus; }
-    public String getDetail() { return detail; }
-    public void setDetail(String detail) { this.detail = detail; }
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestIntegrityIssue.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestIntegrityIssue.java
deleted file mode 100644
index c0646c3..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestIntegrityIssue.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.ruoyi.system.domain;
-
-import java.util.Date;
-import com.fasterxml.jackson.annotation.JsonFormat;
-
-/** 测试来源区间完整性问题事实。 */
-public class TTestIntegrityIssue
-{
-    private Long issueId;
-    private Long testId;
-    private Long intervalId;
-    private Long bindingId;
-    private String sourceType;
-    private Long sourceId;
-    private String sourceChannelCode;
-    private String issueType;
-    private String issueStatus;
-    private Long missingFromSequence;
-    private Long missingToSequence;
-    private Integer retryCount;
-    private String detail;
-    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
-    private Date firstDetectedAtUtc;
-    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
-    private Date lastDetectedAtUtc;
-    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC")
-    private Date resolvedAtUtc;
-
-    public Long getIssueId() { return issueId; }
-    public void setIssueId(Long value) { issueId = value; }
-    public Long getTestId() { return testId; }
-    public void setTestId(Long value) { testId = value; }
-    public Long getIntervalId() { return intervalId; }
-    public void setIntervalId(Long value) { intervalId = value; }
-    public Long getBindingId() { return bindingId; }
-    public void setBindingId(Long value) { bindingId = value; }
-    public String getSourceType() { return sourceType; }
-    public void setSourceType(String value) { sourceType = value; }
-    public Long getSourceId() { return sourceId; }
-    public void setSourceId(Long value) { sourceId = value; }
-    public String getSourceChannelCode() { return sourceChannelCode; }
-    public void setSourceChannelCode(String value) { sourceChannelCode = value; }
-    public String getIssueType() { return issueType; }
-    public void setIssueType(String value) { issueType = value; }
-    public String getIssueStatus() { return issueStatus; }
-    public void setIssueStatus(String value) { issueStatus = value; }
-    public Long getMissingFromSequence() { return missingFromSequence; }
-    public void setMissingFromSequence(Long value) { missingFromSequence = value; }
-    public Long getMissingToSequence() { return missingToSequence; }
-    public void setMissingToSequence(Long value) { missingToSequence = value; }
-    public Integer getRetryCount() { return retryCount; }
-    public void setRetryCount(Integer value) { retryCount = value; }
-    public String getDetail() { return detail; }
-    public void setDetail(String value) { detail = value; }
-    public Date getFirstDetectedAtUtc() { return firstDetectedAtUtc; }
-    public void setFirstDetectedAtUtc(Date value) { firstDetectedAtUtc = value; }
-    public Date getLastDetectedAtUtc() { return lastDetectedAtUtc; }
-    public void setLastDetectedAtUtc(Date value) { lastDetectedAtUtc = value; }
-    public Date getResolvedAtUtc() { return resolvedAtUtc; }
-    public void setResolvedAtUtc(Date value) { resolvedAtUtc = value; }
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestReceptionInterval.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestReceptionInterval.java
deleted file mode 100644
index 1ece2e3..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TTestReceptionInterval.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.ruoyi.system.domain;
-
-import java.util.Date;
-
-/** 测试数据来源的追加接收区间事实。 */
-public class TTestReceptionInterval
-{
-    private Long intervalId;
-    private Long testId;
-    private Long bindingId;
-    private String sourceType;
-    private Long sourceId;
-    private String sourceChannelCode;
-    private Date actionAtUtc;
-    private Date startBoundaryAtUtc;
-    private Date endBoundaryAtUtc;
-    private String boundaryNote;
-    private String intervalStatus;
-
-    public Long getIntervalId() { return intervalId; }
-    public void setIntervalId(Long value) { intervalId = value; }
-    public Long getTestId() { return testId; }
-    public void setTestId(Long value) { testId = value; }
-    public Long getBindingId() { return bindingId; }
-    public void setBindingId(Long value) { bindingId = value; }
-    public String getSourceType() { return sourceType; }
-    public void setSourceType(String value) { sourceType = value; }
-    public Long getSourceId() { return sourceId; }
-    public void setSourceId(Long value) { sourceId = value; }
-    public String getSourceChannelCode() { return sourceChannelCode; }
-    public void setSourceChannelCode(String value) { sourceChannelCode = value; }
-    public Date getActionAtUtc() { return actionAtUtc; }
-    public void setActionAtUtc(Date value) { actionAtUtc = value; }
-    public Date getStartBoundaryAtUtc() { return startBoundaryAtUtc; }
-    public void setStartBoundaryAtUtc(Date value) { startBoundaryAtUtc = value; }
-    public Date getEndBoundaryAtUtc() { return endBoundaryAtUtc; }
-    public void setEndBoundaryAtUtc(Date value) { endBoundaryAtUtc = value; }
-    public String getBoundaryNote() { return boundaryNote; }
-    public void setBoundaryNote(String value) { boundaryNote = value; }
-    public String getIntervalStatus() { return intervalStatus; }
-    public void setIntervalStatus(String value) { intervalStatus = value; }
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java
index f610df5..0bd548a 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TTestMapper.java
@@ -11,11 +11,6 @@
 import com.ruoyi.system.domain.TTestPlanStep;
 import com.ruoyi.system.domain.TTestResult;
 import com.ruoyi.system.domain.TTestWarningThreshold;
-import com.ruoyi.system.domain.TTestCollectorExceptionInterval;
-import com.ruoyi.system.domain.TTestCollectorSource;
-import com.ruoyi.system.domain.TTestBackfillCursor;
-import com.ruoyi.system.domain.TTestIntegrityIssue;
-import com.ruoyi.system.domain.TTestReceptionInterval;
 import com.ruoyi.system.domain.TTestLogicStepMapping;
 import com.ruoyi.system.domain.TDetectionChannel;
 import com.ruoyi.system.domain.TTestDataRevisionAction;
@@ -158,67 +153,4 @@
     int insertSampleConflict(@Param("testId") Long testId, @Param("channelId") Long channelId,
             @Param("detail") String detail);
     int countTestBatteryNo(@Param("testId") Long testId, @Param("batteryNo") String batteryNo);
-    /** 兼容已移除的历史实现源码;当前运行链路不再调用这些方法。 */
-    TTestChannelBinding selectChannelLeaseForUpdate(Long channelId);
-    int insertChannelLease(@Param("channelId") Long channelId, @Param("testId") Long testId,
-            @Param("bindingId") Long bindingId, @Param("acquiredBy") Long acquiredBy,
-            @Param("acquiredAtUtc") Date acquiredAtUtc);
-    int insertCollectorChannelLease(@Param("collectorId") Long collectorId, @Param("channelCode") String channelCode,
-            @Param("testId") Long testId, @Param("bindingId") Long bindingId,
-            @Param("acquiredBy") Long acquiredBy, @Param("acquiredAtUtc") Date acquiredAtUtc);
-    int deleteChannelLeasesByTestId(Long testId);
-    int deleteCollectorChannelLeasesByTestId(Long testId);
-    List<TTestCollectorSource> selectReceivingCollectorSources();
-    TTestCollectorExceptionInterval selectOpenCollectorException(@Param("testId") Long testId,
-            @Param("batteryRelationId") Long batteryRelationId, @Param("collectorId") Long collectorId,
-            @Param("channelCode") String channelCode);
-    int insertCollectorExceptionInterval(TTestCollectorExceptionInterval interval);
-    int closeCollectorExceptionInterval(@Param("intervalId") Long intervalId,
-            @Param("recoveredAtUtc") Date recoveredAtUtc, @Param("missingToUtc") Date missingToUtc);
-    List<TTestCollectorExceptionInterval> selectCollectorExceptionIntervals(Long testId);
-    List<TTest> selectTestsForNaturalEnd();
-    List<TTest> selectTestsForBackfill();
-    TTestBackfillCursor selectBackfillCursorForUpdate(@Param("testId") Long testId,
-            @Param("bindingId") Long bindingId, @Param("sourceType") String sourceType,
-            @Param("sourceId") Long sourceId, @Param("sourceChannelCode") String sourceChannelCode);
-    int insertBackfillCursor(TTestBackfillCursor cursor);
-    int updateBackfillCursor(TTestBackfillCursor cursor);
-    int updateTestBackfillStarted(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc);
-    int updateTestBackfillWaiting(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc,
-            @Param("error") String error);
-    int updateTestBackfillCompleted(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc);
-    int updateTestCompleted(@Param("testId") Long testId, @Param("updatedAtUtc") Date updatedAtUtc);
-    int updateTestNaturallyEnded(@Param("testId") Long testId, @Param("endedAtUtc") Date endedAtUtc);
-    String selectSampleContentHash(@Param("channelId") Long channelId, @Param("btsTestId") String btsTestId,
-            @Param("sequenceId") Long sequenceId);
-    int insertBackfillConflict(@Param("testId") Long testId, @Param("channelId") Long channelId,
-            @Param("detail") String detail);
-    List<TTestIntegrityIssue> selectIntegrityIssues(Long testId);
-    List<TTestIntegrityIssue> selectTestExceptionFacts(Long testId);
-    List<Long> selectBtsSequencesByInterval(Long intervalId);
-    List<Long> selectCollectorSequencesByInterval(Long intervalId);
-    TTestIntegrityIssue selectOpenIntegrityIssue(@Param("intervalId") Long intervalId,
-            @Param("sourceType") String sourceType, @Param("sourceId") Long sourceId,
-            @Param("sourceChannelCode") String sourceChannelCode, @Param("missingFrom") Long missingFrom,
-            @Param("missingTo") Long missingTo);
-    List<TTestIntegrityIssue> selectOpenIntegrityIssues(@Param("intervalId") Long intervalId,
-            @Param("sourceType") String sourceType, @Param("sourceId") Long sourceId,
-            @Param("sourceChannelCode") String sourceChannelCode);
-    int insertIntegrityIssue(TTestIntegrityIssue issue);
-    int touchIntegrityIssue(@Param("issueId") Long issueId, @Param("retryCount") Integer retryCount,
-            @Param("detail") String detail, @Param("detectedAtUtc") Date detectedAtUtc);
-    int rewindBackfillCursor(@Param("testId") Long testId, @Param("bindingId") Long bindingId,
-            @Param("sourceType") String sourceType, @Param("sourceId") Long sourceId,
-            @Param("sourceChannelCode") String sourceChannelCode, @Param("nextPosition") Long nextPosition);
-    int resolveIntegrityIssues(@Param("testId") Long testId, @Param("intervalId") Long intervalId,
-            @Param("sourceType") String sourceType, @Param("sourceId") Long sourceId,
-            @Param("sourceChannelCode") String sourceChannelCode, @Param("resolvedAtUtc") Date resolvedAtUtc);
-    int resolveIntegrityIssue(@Param("issueId") Long issueId, @Param("resolvedAtUtc") Date resolvedAtUtc);
-    int countOpenIntegrityIssues(Long testId);
-    int countOpenExceptions(Long testId);
-    int closeOpenReceptionIntervals(@Param("testId") Long testId, @Param("endBoundaryAtUtc") Date endBoundaryAtUtc,
-            @Param("boundaryNote") String boundaryNote);
-    List<TTestReceptionInterval> selectTestReceptionIntervals(Long testId);
-
-    /** ����兼容旧源码的声明;Ticket28 运行链路不再调用。 */
 }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ICollectorDisconnectRecoveryService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ICollectorDisconnectRecoveryService.java
deleted file mode 100644
index 8bbf49f..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ICollectorDisconnectRecoveryService.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.time.Instant;
-import java.util.Set;
-
-
-/** 维护接收中采集器来源的断线异常与恢复边界。 */
-public interface ICollectorDisconnectRecoveryService
-{
-    void reconcile(Set<String> onlineCollectorCodes, Instant observedAt);
-    /** 根据当前模拟器在线设备编码对账所有接收中来源。 */
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestBackfillService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestBackfillService.java
deleted file mode 100644
index 3ae4fff..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestBackfillService.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.ruoyi.system.service;
-
-/** 设备自然结束后的区间历史补采与恢复协调接口。 */
-public interface ITestBackfillService
-{
-    void reconcileNaturalEnd();
-    void resumePendingBackfill();
-    void endNaturally(Long testId, String reason);
-    /** 对接收中的测试检查检测柜自然结束并关闭其接收边界。 */
-
-    /** 从持久化游标继续所有处于完成确认中的测试补采。 */
-
-    /** 立即结束指定测试的接收并进入完成确认中,供自然结束协调器使用。 */
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestIntegrityService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestIntegrityService.java
deleted file mode 100644
index a7b8fcc..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ITestIntegrityService.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.domain.TTestIntegrityIssue;
-
-
-/** 查询测试区间完整性事实。 */
-public interface ITestIntegrityService
-{
-    List<TTestIntegrityIssue> selectIssues(Long testId);
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CollectorDisconnectRecoveryServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CollectorDisconnectRecoveryServiceImpl.java
deleted file mode 100644
index 4776ed4..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/CollectorDisconnectRecoveryServiceImpl.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.time.Instant;
-import java.util.Collections;
-import java.util.Set;
-import java.util.stream.Collectors;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import com.alibaba.fastjson2.JSON;
-import com.ruoyi.system.domain.TTestCollectorExceptionInterval;
-import com.ruoyi.system.domain.TTestCollectorSource;
-import com.ruoyi.system.mapper.TTestMapper;
-import com.ruoyi.system.service.ICollectorDisconnectRecoveryService;
-
-/** 将采集器在线事实对账为可恢复的来源级异常区间。 */
-public class CollectorDisconnectRecoveryServiceImpl implements ICollectorDisconnectRecoveryService
-{
-    private final TTestMapper mapper;
-
-    public CollectorDisconnectRecoveryServiceImpl(TTestMapper mapper) { this.mapper = mapper; }
-
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void reconcile(Set<String> onlineCollectorCodes, Instant observedAt)
-    {
-        Set<String> online = onlineCollectorCodes == null ? Collections.emptySet()
-                : onlineCollectorCodes.stream().filter(code -> code != null && !code.isBlank()).collect(Collectors.toSet());
-        for (TTestCollectorSource source : mapper.selectReceivingCollectorSources())
-        {
-            TTestCollectorExceptionInterval open = mapper.selectOpenCollectorException(source.getTestId(),
-                    source.getBatteryRelationId(), source.getCollectorId(), source.getChannelCode());
-            boolean isOnline = online.contains(source.getCollectorCode());
-            if (!isOnline && open == null)
-            {
-                TTestCollectorExceptionInterval interval = new TTestCollectorExceptionInterval();
-                interval.setTestId(source.getTestId());
-                interval.setBatteryRelationId(source.getBatteryRelationId());
-                interval.setCollectorId(source.getCollectorId());
-                interval.setCollectorChannelCode(source.getChannelCode());
-                interval.setExceptionType("COLLECTOR_DISCONNECTED");
-                java.util.Date at = java.util.Date.from(observedAt);
-                interval.setOpenedAtUtc(at);
-                interval.setMissingFromUtc(at);
-                interval.setDetail(JSON.toJSONString(java.util.Map.of("batteryNo", source.getBatteryNo(),
-                        "collectorCode", source.getCollectorCode(), "message", "采集器离线,检测柜及其他来源继续接收")));
-                mapper.insertCollectorExceptionInterval(interval);
-                mapper.insertTestAudit(source.getTestId(), "COLLECTOR_DISCONNECTED", null, "system", null,
-                        JSON.toJSONString(java.util.Map.of("collectorId", source.getCollectorId(),
-                                "channelCode", source.getChannelCode(), "missingFrom", observedAt.toString())));
-            }
-            else if (isOnline && open != null)
-            {
-                java.util.Date at = java.util.Date.from(observedAt);
-                mapper.closeCollectorExceptionInterval(open.getIntervalId(), at, at);
-                mapper.insertTestAudit(source.getTestId(), "COLLECTOR_RECONNECTED", null, "system", null,
-                        JSON.toJSONString(java.util.Map.of("collectorId", source.getCollectorId(),
-                                "channelCode", source.getChannelCode(), "recoveredAt", observedAt.toString())));
-            }
-        }
-    }
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/IntervalIntegrityChecker.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/IntervalIntegrityChecker.java
deleted file mode 100644
index c2302f8..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/IntervalIntegrityChecker.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-/** 按单个接收区间检查历史序号;暂停和区间边界由调用方分组后自然排除。 */
-final class IntervalIntegrityChecker
-{
-    record Gap(long from, long to) { }
-
-    private IntervalIntegrityChecker() { }
-
-    static List<Gap> gaps(Collection<Long> sequenceIds)
-    {
-        if (sequenceIds == null || sequenceIds.isEmpty()) return List.of();
-        Set<Long> unique = new LinkedHashSet<>();
-        sequenceIds.stream().filter(value -> value != null && value > 0).forEach(unique::add);
-        List<Long> ordered = new ArrayList<>(unique);
-        ordered.sort(Comparator.naturalOrder());
-        List<Gap> result = new ArrayList<>();
-        for (int index = 1; index < ordered.size(); index++)
-        {
-            long previous = ordered.get(index - 1);
-            long current = ordered.get(index);
-            if (current > previous + 1) result.add(new Gap(previous + 1, current - 1));
-        }
-        return List.copyOf(result);
-    }
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestBackfillServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestBackfillServiceImpl.java
deleted file mode 100644
index 5a92d54..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestBackfillServiceImpl.java
+++ /dev/null
@@ -1,423 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-import java.time.Instant;
-import java.util.Date;
-import java.util.HexFormat;
-import java.util.List;
-import java.util.Objects;
-import com.alibaba.fastjson2.JSON;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.PlatformTransactionManager;
-import org.springframework.transaction.support.TransactionTemplate;
-import org.springframework.transaction.annotation.Transactional;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.device.api.DeviceAdapter;
-import com.ruoyi.device.model.ChannelIdentity;
-import com.ruoyi.device.model.HistoryAvailability;
-import com.ruoyi.device.model.HistoryPage;
-import com.ruoyi.device.model.HistorySample;
-import com.ruoyi.device.simulator.BtsSimulatorStateStore;
-import com.ruoyi.device.simulator.BtsSimulatorStateStore.CollectorMeasurementRecord;
-import com.ruoyi.device.registry.DeviceAdapterRegistry;
-import com.ruoyi.system.domain.TTest;
-import com.ruoyi.system.domain.TTestBackfillCursor;
-import com.ruoyi.system.domain.TTestBattery;
-import com.ruoyi.system.domain.TTestChannelBinding;
-import com.ruoyi.system.domain.TTestCollectorChannel;
-import com.ruoyi.system.domain.TTestReceptionInterval;
-import com.ruoyi.system.domain.TTestIntegrityIssue;
-import com.ruoyi.system.mapper.TTestMapper;
-import com.ruoyi.system.service.ITestBackfillService;
-import com.ruoyi.system.service.ITTestService;
-
-/** 以测试动作边界筛选来源历史,并以数据库游标保证补采可恢复。 */
-public class TestBackfillServiceImpl implements ITestBackfillService
-{
-    private static final int PAGE_SIZE = 1000;
-    private static final int MAX_INTEGRITY_RETRIES = 3;
-    private final TTestMapper mapper;
-    private final DeviceAdapterRegistry registry;
-    private final BtsSimulatorStateStore collectorHistoryStore;
-    private final ITTestService tests;
-    private final TransactionTemplate transactionTemplate;
-
-    public TestBackfillServiceImpl(TTestMapper mapper, DeviceAdapterRegistry registry,
-            BtsSimulatorStateStore collectorHistoryStore, ITTestService tests,
-            PlatformTransactionManager transactionManager)
-    {
-        this.mapper = mapper;
-        this.registry = registry;
-        this.collectorHistoryStore = collectorHistoryStore;
-        this.tests = tests;
-        this.transactionTemplate = new TransactionTemplate(transactionManager);
-    }
-
-    /** 将已自然结束的设备事实转为待补采测试,并关闭其开放接收区间。 */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void reconcileNaturalEnd()
-    {
-        List<TTest> summaries = mapper.selectTestsForNaturalEnd();
-        if (summaries == null) return;
-        for (TTest summary : summaries)
-        {
-            TTest test = tests.selectTestById(summary.getTestId());
-            if (test == null || test.getBatteries() == null || test.getBatteries().isEmpty()) continue;
-            boolean allFinished = true;
-            for (TTestBattery battery : test.getBatteries())
-            {
-                TTestChannelBinding binding = battery.getBinding();
-                if (binding == null) { allFinished = false; break; }
-                var channel = mapper.selectReceptionChannelForUpdate(binding.getChannelId());
-                if (channel == null || !"FINISHED".equalsIgnoreCase(channel.getWorkStatus()))
-                { allFinished = false; break; }
-            }
-            if (allFinished) endNaturally(test.getTestId(), "NATURAL_FINISH");
-        }
-    }
-
-    /** 恢复等待中的历史补采;完整性未确认时继续保持完成确认中。 */
-    @Override
-    public void resumePendingBackfill()
-    {
-        List<TTest> pending = mapper.selectTestsForBackfill();
-        if (pending == null) return;
-        for (TTest test : pending)
-        {
-            try { transactionTemplate.executeWithoutResult(status -> backfill(test)); }
-            catch (RuntimeException exception)
-            {
-                mapper.updateTestBackfillWaiting(test.getTestId(), new Date(), exception.getMessage());
-            }
-        }
-    }
-
-    /** 记录自然结束并释放租约;测试完成状态由后续补采完整性门禁确认。 */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void endNaturally(Long testId, String reason)
-    {
-        if (testId == null) throw new ServiceException("测试ID不能为空");
-        Date endedAt = new Date();
-        if (mapper.updateTestNaturallyEnded(testId, endedAt) != 1) return;
-        mapper.closeOpenReceptionIntervals(testId, endedAt, reason == null ? "NATURAL_FINISH" : reason);
-        mapper.deleteChannelLeasesByTestId(testId);
-        mapper.deleteCollectorChannelLeasesByTestId(testId);
-        mapper.insertTestAudit(testId, "RECEPTION_NATURALLY_ENDED", null, "system", null,
-                JSON.toJSONString(java.util.Map.of("testStatus", "COMPLETION_PENDING",
-                        "receptionStatus", "ENDED", "reason", reason == null ? "NATURAL_FINISH" : reason)));
-    }
-
-    /** 补采全部来源历史,只有完整性和异常检查通过后才写入检测完成。 */
-    @Transactional(rollbackFor = Exception.class)
-    protected void backfill(TTest test)
-    {
-        if (mapper.updateTestBackfillStarted(test.getTestId(), new Date()) == 0) return;
-        // 来源按检测柜、采集器分别提交;任何一页失败都不推进该来源游标。
-        for (TTestBattery battery : test.getBatteries() == null ? List.<TTestBattery>of() : test.getBatteries())
-        {
-            TTestChannelBinding binding = battery.getBinding();
-            if (binding != null) backfillCabinet(test, battery, binding);
-            for (TTestCollectorChannel mapping : battery.getCollectorChannels() == null
-                    ? List.<TTestCollectorChannel>of() : battery.getCollectorChannels())
-                backfillCollector(test, battery, mapping);
-        }
-        Date checkedAt = new Date();
-        boolean complete = checkIntegrity(test, checkedAt);
-        if (complete)
-        {
-            mapper.updateTestCompleted(test.getTestId(), checkedAt);
-            mapper.insertTestAudit(test.getTestId(), "TEST_COMPLETED", null, "system", null,
-                    JSON.toJSONString(java.util.Map.of("backfillStatus", "COMPLETED", "integrity", "PASSED")));
-        }
-        else
-        {
-            mapper.updateTestBackfillWaiting(test.getTestId(), checkedAt, "区间完整性检查未通过");
-            mapper.insertTestAudit(test.getTestId(), "INTEGRITY_CHECK_BLOCKED", null, "system", null,
-                    JSON.toJSONString(java.util.Map.of("backfillStatus", "WAITING", "integrity", "OPEN")));
-        }
-    }
-
-    private void backfillCabinet(TTest test, TTestBattery battery, TTestChannelBinding binding)
-    {
-        String adapterCode = binding.getAdapterCode();
-        if (adapterCode == null || adapterCode.isBlank()) throw new ServiceException("检测柜适配器身份缺失");
-        ChannelIdentity identity = new ChannelIdentity(adapterCode, binding.getDevtype(), binding.getDevid(),
-                binding.getSubdevid(), binding.getChlid());
-        List<TTestReceptionInterval> intervals = intervals(test.getTestId(), binding.getBindingId(), "CABINET_CHANNEL",
-                binding.getChannelId(), null);
-        if (intervals.isEmpty()) return;
-        HistoryAvailability availability = registry.execute(adapterCode,
-                adapter -> adapter.inquireHistory(java.util.Set.of(identity)).stream().findFirst()
-                        .orElseThrow(() -> new ServiceException("检测柜未返回历史清单")));
-        TTestBackfillCursor cursor = cursor(test, binding.getBindingId(), "CABINET_CHANNEL", binding.getChannelId(), null,
-                availability.btsTestId());
-        cursor.setProtocolMetadata(JSON.toJSONString(java.util.Map.of("availableRecordCount",
-                availability.availableRecordCount(), "uploadComplete", availability.uploadComplete(),
-                "adapterCode", adapterCode)));
-        cursor.setUpdatedAtUtc(new Date());
-        mapper.updateBackfillCursor(cursor);
-        long position = Math.max(1L, cursor.getNextPosition() == null ? 1L : cursor.getNextPosition());
-        while (true)
-        {
-            final long requestPosition = position;
-            HistoryPage page = registry.execute(adapterCode,
-                    adapter -> adapter.downloadHistory(identity, availability.btsTestId(), requestPosition, PAGE_SIZE));
-            for (HistorySample sample : page.samples())
-            {
-                if (!within(sample.deviceTime(), intervals)) continue;
-                saveBtsSample(test, binding, intervals, availability.btsTestId(), sample);
-            }
-            long next = page.nextPosition() > position ? page.nextPosition() : position + page.samples().size();
-            cursor.setNextPosition(next);
-            cursor.setSourceStatus(page.samples().isEmpty() && page.nextPosition() <= position ? "COMPLETED" : "RUNNING");
-            cursor.setUpdatedAtUtc(new Date());
-            mapper.updateBackfillCursor(cursor);
-            if (page.samples().isEmpty() || page.nextPosition() <= position) break;
-            position = next;
-        }
-        cursor.setSourceStatus("COMPLETED");
-        cursor.setUpdatedAtUtc(new Date());
-        mapper.updateBackfillCursor(cursor);
-    }
-
-    private void saveBtsSample(TTest test, TTestChannelBinding binding, List<TTestReceptionInterval> intervals,
-            String btsTestId, HistorySample sample)
-    {
-        byte[] hash = hash(sample.sequenceId() + "|" + sample.stepNo() + "|" + sample.cycleNo() + "|"
-                + sample.stepType() + "|" + sample.deviceTimeRaw() + "|" + sample.voltageV() + "|"
-                + sample.currentA() + "|" + sample.capacityAh() + "|" + sample.energyWh());
-        String testScoped = mapper.selectTestSampleContentHash(test.getTestId(), binding.getChannelId(),
-                sample.sequenceId());
-        if (testScoped != null)
-        {
-            if (!testScoped.equalsIgnoreCase(HexFormat.of().formatHex(hash)))
-                mapper.insertSampleConflict(test.getTestId(), binding.getChannelId(),
-                        "测试内采样内容冲突 seqid=" + sample.sequenceId());
-            return;
-        }
-        String old = mapper.selectSampleContentHash(binding.getChannelId(), btsTestId, sample.sequenceId());
-        if (old != null && !old.equalsIgnoreCase(HexFormat.of().formatHex(hash)))
-        {
-            mapper.insertSampleConflict(test.getTestId(), binding.getChannelId(),
-                    "BTS testid=" + btsTestId + ", seqid=" + sample.sequenceId());
-            return;
-        }
-        mapper.insertBtsSample(test.getTestId(), binding.getBindingId(), binding.getChannelId(),
-                intervalId(intervals, sample.deviceTime()), btsTestId, sample.sequenceId(), Date.from(sample.deviceTime()),
-                sample.deviceTimeRaw(), new Date(), sample.cycleNo(), sample.stepNo(), sample.stepType(),
-                stepNameForType(sample.stepType()), sample.testTimeMs(),
-                sample.voltageV(), sample.currentA(), sample.capacityAh(), sample.energyWh(), hash);
-        Long sampleId = mapper.selectBtsSampleId(binding.getChannelId(), btsTestId, sample.sequenceId());
-        if (sampleId != null)
-            sample.measurements().forEach((code, measurement) -> mapper.insertBtsMeasurement(sampleId, code,
-                    measurement.value(), measurement.unit() == null ? "" : measurement.unit(), measurement.sourceType()));
-    }
-
-    private void backfillCollector(TTest test, TTestBattery battery, TTestCollectorChannel mapping)
-    {
-        if (battery.getCollectorId() == null) return;
-        if (battery.getBinding() == null) throw new ServiceException("采集器绑定缺少检测柜通道");
-        String collectorCode = mapper.selectCollectorCode(battery.getCollectorId());
-        if (collectorCode == null || collectorCode.isBlank()) throw new ServiceException("采集器来源不存在");
-        List<TTestReceptionInterval> intervals = intervals(test.getTestId(), battery.getBinding().getBindingId(),
-                "COLLECTOR_CHANNEL", battery.getCollectorId(), mapping.getChannelCode());
-        if (intervals.isEmpty()) return;
-        TTestBackfillCursor cursor = cursor(test, battery.getBinding().getBindingId(), "COLLECTOR_CHANNEL",
-                battery.getCollectorId(), mapping.getChannelCode(), collectorCode);
-        long offset = Math.max(0L, (cursor.getNextPosition() == null ? 1L : cursor.getNextPosition()) - 1L);
-        while (true)
-        {
-            var page = collectorHistoryStore.loadCollectorHistoryPage(collectorCode, offset, PAGE_SIZE, false);
-            for (CollectorMeasurementRecord record : page.records())
-            {
-                if (!mapping.getMeasurementCode().equalsIgnoreCase(record.metricCode()) || !within(record.deviceTime(), intervals)) continue;
-                saveCollectorSample(test, battery, mapping, intervals, record);
-            }
-            offset = page.nextOffset();
-            cursor.setNextPosition(offset + 1L);
-            cursor.setSourceStatus(page.hasMore() ? "RUNNING" : "COMPLETED");
-            cursor.setUpdatedAtUtc(new Date());
-            mapper.updateBackfillCursor(cursor);
-            if (!page.hasMore()) break;
-        }
-    }
-
-    private void saveCollectorSample(TTest test, TTestBattery battery, TTestCollectorChannel mapping,
-            List<TTestReceptionInterval> intervals, CollectorMeasurementRecord record)
-    {
-        byte[] hash = hash(record.sequenceId() + "|" + record.deviceTimeRaw() + "|" + record.metricCode() + "|"
-                + record.value() + "|" + record.unit());
-        String old = mapper.selectCollectorSampleContentHash(battery.getCollectorId(), record.channelCode(),
-                record.sequenceId(), record.metricCode());
-        if (old != null && !old.equalsIgnoreCase(HexFormat.of().formatHex(hash)))
-        {
-            mapper.insertSampleConflict(test.getTestId(), null,
-                    "采集器=" + record.collectorCode() + ", seqid=" + record.sequenceId());
-            return;
-        }
-        mapper.insertCollectorSample(test.getTestId(), battery.getBinding().getBindingId(),
-                intervalId(intervals, record.deviceTime()), battery.getCollectorId(),
-                record.channelCode(), record.sequenceId(), Date.from(record.deviceTime()), record.deviceTimeRaw(),
-                Date.from(record.serverReceivedAt()), record.metricCode(), record.value(), record.unit(), hash);
-    }
-
-    /** BTS download 协议只提供类型码;演示协议按已确认的类型语义补出名称。 */
-    private String stepNameForType(String stepType)
-    {
-        return switch (stepType == null ? "" : stepType.toLowerCase(java.util.Locale.ROOT))
-        {
-            case "cc" -> "恒流充电";
-            case "dc" -> "恒流放电";
-            case "rest" -> "搁置";
-            default -> stepType;
-        };
-    }
-
-    private boolean checkIntegrity(TTest test, Date checkedAt)
-    {
-        // 序号只在同一来源、同一接收区间内比较;区间边界和暂停间隔不构成缺口。
-        boolean complete = true;
-        for (TTestReceptionInterval interval : mapper.selectTestReceptionIntervals(test.getTestId()))
-        {
-            String sourceType = interval.getSourceType();
-            List<Long> sequenceIds = "CABINET_CHANNEL".equals(sourceType)
-                    ? mapper.selectBtsSequencesByInterval(interval.getIntervalId())
-                    : mapper.selectCollectorSequencesByInterval(interval.getIntervalId());
-            List<IntervalIntegrityChecker.Gap> gaps = IntervalIntegrityChecker.gaps(sequenceIds);
-            if (sequenceIds == null || sequenceIds.isEmpty())
-            {
-                complete = false;
-                TTestIntegrityIssue old = mapper.selectOpenIntegrityIssue(interval.getIntervalId(), sourceType,
-                        interval.getSourceId(), interval.getSourceChannelCode(), null, null);
-                if (old == null)
-                {
-                    TTestIntegrityIssue issue = new TTestIntegrityIssue();
-                    issue.setTestId(test.getTestId()); issue.setIntervalId(interval.getIntervalId());
-                    issue.setBindingId(interval.getBindingId()); issue.setSourceType(sourceType);
-                    issue.setSourceId(interval.getSourceId()); issue.setSourceChannelCode(interval.getSourceChannelCode());
-                    issue.setIssueType("NO_SAMPLES"); issue.setRetryCount(1);
-                    issue.setDetail("接收区间没有可确认的历史采样"); issue.setFirstDetectedAtUtc(checkedAt);
-                    issue.setLastDetectedAtUtc(checkedAt); mapper.insertIntegrityIssue(issue);
-                    mapper.insertTestAudit(test.getTestId(), "INTEGRITY_GAP_DETECTED", null, "system", null,
-                            JSON.toJSONString(java.util.Map.of("intervalId", interval.getIntervalId(), "sourceType", sourceType,
-                                    "issueType", "NO_SAMPLES")));
-                }
-                else
-                {
-                    int retry = old.getRetryCount() == null ? 1 : old.getRetryCount() + 1;
-                    int cappedRetry = Math.min(retry, MAX_INTEGRITY_RETRIES);
-                    mapper.touchIntegrityIssue(old.getIssueId(), cappedRetry,
-                            old.getDetail(), checkedAt);
-                    mapper.insertTestAudit(test.getTestId(), "INTEGRITY_GAP_RETRIED", null, "system", null,
-                            JSON.toJSONString(java.util.Map.of("issueId", old.getIssueId(), "retryCount", cappedRetry)));
-                    if (cappedRetry < MAX_INTEGRITY_RETRIES)
-                        mapper.rewindBackfillCursor(test.getTestId(), interval.getBindingId(), sourceType,
-                                interval.getSourceId(), interval.getSourceChannelCode(), 1L);
-                }
-                continue;
-            }
-            if (gaps.isEmpty())
-            {
-                int resolved = mapper.resolveIntegrityIssues(test.getTestId(), interval.getIntervalId(), sourceType,
-                        interval.getSourceId(), interval.getSourceChannelCode(), checkedAt);
-                if (resolved > 0) mapper.insertTestAudit(test.getTestId(), "INTEGRITY_GAP_RESOLVED", null, "system", null,
-                        JSON.toJSONString(java.util.Map.of("intervalId", interval.getIntervalId())));
-                continue;
-            }
-            complete = false;
-            for (TTestIntegrityIssue open : mapper.selectOpenIntegrityIssues(interval.getIntervalId(), sourceType,
-                    interval.getSourceId(), interval.getSourceChannelCode()))
-            {
-                boolean stillOpen = gaps.stream().anyMatch(gap -> Objects.equals(gap.from(), open.getMissingFromSequence())
-                        && Objects.equals(gap.to(), open.getMissingToSequence()));
-                if (!stillOpen && mapper.resolveIntegrityIssue(open.getIssueId(), checkedAt) > 0)
-                    mapper.insertTestAudit(test.getTestId(), "INTEGRITY_GAP_RESOLVED", null, "system", null,
-                            JSON.toJSONString(java.util.Map.of("issueId", open.getIssueId())));
-            }
-            for (IntervalIntegrityChecker.Gap gap : gaps)
-            {
-                TTestIntegrityIssue old = mapper.selectOpenIntegrityIssue(interval.getIntervalId(), sourceType,
-                        interval.getSourceId(), interval.getSourceChannelCode(), gap.from(), gap.to());
-                if (old == null)
-                {
-                    TTestIntegrityIssue issue = new TTestIntegrityIssue();
-                    issue.setTestId(test.getTestId()); issue.setIntervalId(interval.getIntervalId());
-                    issue.setBindingId(interval.getBindingId()); issue.setSourceType(sourceType);
-                    issue.setSourceId(interval.getSourceId()); issue.setSourceChannelCode(interval.getSourceChannelCode());
-                    issue.setIssueType("SEQUENCE_GAP"); issue.setMissingFromSequence(gap.from());
-                    issue.setMissingToSequence(gap.to()); issue.setRetryCount(1);
-                    issue.setDetail("接收区间内存在未解释序号缺口"); issue.setFirstDetectedAtUtc(checkedAt);
-                    issue.setLastDetectedAtUtc(checkedAt); mapper.insertIntegrityIssue(issue);
-                    mapper.insertTestAudit(test.getTestId(), "INTEGRITY_GAP_DETECTED", null, "system", null,
-                            JSON.toJSONString(java.util.Map.of("intervalId", interval.getIntervalId(), "sourceType", sourceType,
-                                    "missingFrom", gap.from(), "missingTo", gap.to())));
-                }
-                else
-                {
-                    int retry = old.getRetryCount() == null ? 1 : old.getRetryCount() + 1;
-                    int cappedRetry = Math.min(retry, MAX_INTEGRITY_RETRIES);
-                    mapper.touchIntegrityIssue(old.getIssueId(), cappedRetry,
-                            old.getDetail(), checkedAt);
-                    mapper.insertTestAudit(test.getTestId(), "INTEGRITY_GAP_RETRIED", null, "system", null,
-                            JSON.toJSONString(java.util.Map.of("issueId", old.getIssueId(), "retryCount", cappedRetry)));
-                    if (cappedRetry >= MAX_INTEGRITY_RETRIES) continue;
-                }
-                // next_position 是分页偏移而非 seqid;从安全起点重放,依靠幂等键避免覆盖原始事实。
-                mapper.rewindBackfillCursor(test.getTestId(), interval.getBindingId(), sourceType,
-                        interval.getSourceId(), interval.getSourceChannelCode(), 1L);
-            }
-        }
-        return complete && mapper.countOpenIntegrityIssues(test.getTestId()) == 0
-                && mapper.countOpenExceptions(test.getTestId()) == 0;
-    }
-
-    private TTestBackfillCursor cursor(TTest test, Long bindingId, String sourceType, Long sourceId,
-            String channelCode, String protocolTestId)
-    {
-        TTestBackfillCursor value = mapper.selectBackfillCursorForUpdate(test.getTestId(), bindingId, sourceType, sourceId, channelCode);
-        if (value != null)
-        {
-            if (value.getProtocolTestId() != null && !Objects.equals(value.getProtocolTestId(), protocolTestId))
-                throw new ServiceException("历史协议测试标识发生变化");
-            return value;
-        }
-        value = new TTestBackfillCursor();
-        value.setTestId(test.getTestId()); value.setBindingId(bindingId); value.setSourceType(sourceType);
-        value.setSourceId(sourceId); value.setSourceChannelCode(channelCode); value.setProtocolTestId(protocolTestId);
-        value.setNextPosition(1L); value.setSourceStatus("PENDING"); value.setProtocolMetadata("{}");
-        value.setUpdatedAtUtc(new Date());
-        mapper.insertBackfillCursor(value);
-        return value;
-    }
-
-    private List<TTestReceptionInterval> intervals(Long testId, Long bindingId, String sourceType, Long sourceId,
-            String channelCode)
-    {
-        return mapper.selectTestReceptionIntervals(testId).stream()
-                .filter(item -> Objects.equals(item.getBindingId(), bindingId) && Objects.equals(item.getSourceType(), sourceType)
-                        && Objects.equals(item.getSourceId(), sourceId)
-                        && Objects.equals(item.getSourceChannelCode(), channelCode)).toList();
-    }
-
-    private boolean within(Instant time, List<TTestReceptionInterval> intervals)
-    {
-        return time != null && intervals.stream().anyMatch(item -> !time.isBefore(item.getStartBoundaryAtUtc().toInstant())
-                && (item.getEndBoundaryAtUtc() == null || time.isBefore(item.getEndBoundaryAtUtc().toInstant())));
-    }
-
-    private Long intervalId(List<TTestReceptionInterval> intervals, Instant time)
-    {
-        return intervals.stream().filter(item -> !time.isBefore(item.getStartBoundaryAtUtc().toInstant())
-                && (item.getEndBoundaryAtUtc() == null || time.isBefore(item.getEndBoundaryAtUtc().toInstant())))
-                .map(TTestReceptionInterval::getIntervalId).findFirst().orElse(null);
-    }
-
-    private byte[] hash(String value)
-    {
-        try { return MessageDigest.getInstance("SHA-256").digest(value.getBytes(StandardCharsets.UTF_8)); }
-        catch (Exception exception) { throw new IllegalStateException("SHA-256不可用", exception); }
-    }
-}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestIntegrityServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestIntegrityServiceImpl.java
deleted file mode 100644
index ebb44b4..0000000
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/TestIntegrityServiceImpl.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import org.springframework.stereotype.Service;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.system.domain.TTestIntegrityIssue;
-import com.ruoyi.system.mapper.TTestMapper;
-import com.ruoyi.system.service.ITTestService;
-import com.ruoyi.system.service.ITestIntegrityService;
-
-/** 完整性查询只返回持久化问题事实,不把实时快照当作历史结果。 */
-public class TestIntegrityServiceImpl implements ITestIntegrityService
-{
-    private final TTestMapper mapper;
-    private final ITTestService tests;
-
-    public TestIntegrityServiceImpl(TTestMapper mapper, ITTestService tests)
-    { this.mapper = mapper; this.tests = tests; }
-
-    /** 返回持久化完整性问题和历史异常事实,不把实时快照当作最终结果。 */
-    @Override
-    public List<TTestIntegrityIssue> selectIssues(Long testId)
-    {
-        if (testId == null) throw new ServiceException("测试ID不能为空");
-        tests.selectTestById(testId);
-        List<TTestIntegrityIssue> issues = new java.util.ArrayList<>();
-        List<TTestIntegrityIssue> integrity = mapper.selectIntegrityIssues(testId);
-        if (integrity != null) issues.addAll(integrity);
-        List<TTestIntegrityIssue> exceptions = mapper.selectTestExceptionFacts(testId);
-        if (exceptions != null) issues.addAll(exceptions);
-        return issues;
-    }
-}

--
Gitblit v1.7.1