Add diagnostic logs for total pages not updating investigation

Add RDEPUBBackgroundTrace.log at key decision points in the
reconciliation pipeline to trace why pageMap updates get rejected:

1. refreshBookPageMapInPlace — logs when a full pageMap update is enqueued
2. evaluateTakeover — logs when keepCurrentWindow is returned due to:
   - jumpSession coverage ratio < 0.8
   - adjacent coverage missing (hasPrev/hasNext)
   - renderSignature mismatch
3. evaluateFullPageMapTakeover — logs when keepCurrentWindow is returned due to:
   - currentSpineIndex not in candidate chapters
   - adjacent coverage missing
4. commitPendingPageMapUpdate — logs when keepCurrentWindow decision is
   applied and pending update is removed from queue

Also fix unused variable warning for currentPageNumber in extendPartial case.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shenlei 2026-06-25 18:57:16 +08:00
parent 15b15d0e11
commit b8aa10c535
2 changed files with 29 additions and 1 deletions

View File

@ -52,6 +52,10 @@ final class RDEPUBPageMapReconciliationCoordinator {
let coverageRatio = Double(protectedIndices.intersection(candidateIndices).count) / let coverageRatio = Double(protectedIndices.intersection(candidateIndices).count) /
Double(protectedIndices.count) Double(protectedIndices.count)
if coverageRatio < 0.8 { if coverageRatio < 0.8 {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateTakeover: keepCurrentWindow — jumpSession coverageRatio=\(String(format: "%.2f", coverageRatio)) protected=\(protectedIndices.count) candidateChapters=\(candidateIndices.count)"
)
return .keepCurrentWindow return .keepCurrentWindow
} }
} }
@ -66,6 +70,10 @@ final class RDEPUBPageMapReconciliationCoordinator {
let hasPrev = candidateSegment.contains(spineIndex: currentSpineIndex - 1) let hasPrev = candidateSegment.contains(spineIndex: currentSpineIndex - 1)
let hasNext = candidateSegment.contains(spineIndex: currentSpineIndex + 1) let hasNext = candidateSegment.contains(spineIndex: currentSpineIndex + 1)
if !hasPrev || !hasNext { if !hasPrev || !hasNext {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateTakeover: keepCurrentWindow — adjacentCoverage missing hasPrev=\(hasPrev) hasNext=\(hasNext) currentSpine=\(currentSpineIndex)"
)
return .keepCurrentWindow return .keepCurrentWindow
} }
} }
@ -75,6 +83,10 @@ final class RDEPUBPageMapReconciliationCoordinator {
if let candidateSegment { if let candidateSegment {
let currentRenderSignature = context.currentRenderSignature() let currentRenderSignature = context.currentRenderSignature()
if candidateSegment.renderSignature != currentRenderSignature { if candidateSegment.renderSignature != currentRenderSignature {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateTakeover: keepCurrentWindow — renderSignature mismatch segment=\(candidateSegment.renderSignature) current=\(currentRenderSignature)"
)
return .keepCurrentWindow return .keepCurrentWindow
} }
} }
@ -156,6 +168,10 @@ final class RDEPUBPageMapReconciliationCoordinator {
if let currentSpineIndex { if let currentSpineIndex {
if !candidateIndices.contains(currentSpineIndex) { if !candidateIndices.contains(currentSpineIndex) {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateFullPageMapTakeover: keepCurrentWindow — currentSpine=\(currentSpineIndex) not in candidate chapters=\(candidateIndices.count)"
)
return .keepCurrentWindow return .keepCurrentWindow
} }
} }
@ -165,6 +181,10 @@ final class RDEPUBPageMapReconciliationCoordinator {
let hasNext = candidateIndices.contains(currentSpineIndex + 1) || let hasNext = candidateIndices.contains(currentSpineIndex + 1) ||
currentSpineIndex == lastBuildableSpineIndex currentSpineIndex == lastBuildableSpineIndex
if !hasPrev || !hasNext { if !hasPrev || !hasNext {
RDEPUBBackgroundTrace.log(
"Reconciliation",
"evaluateFullPageMapTakeover: keepCurrentWindow — adjacentCoverage missing hasPrev=\(hasPrev) hasNext=\(hasNext) currentSpine=\(currentSpineIndex)"
)
return .keepCurrentWindow return .keepCurrentWindow
} }
} }

View File

@ -56,6 +56,10 @@ final class RDEPUBPresentationRuntime {
func refreshBookPageMapInPlace(_ bookPageMap: RDEPUBBookPageMap) { func refreshBookPageMapInPlace(_ bookPageMap: RDEPUBBookPageMap) {
navigationStateMachine.transition(to: .reconcilingFullMap) navigationStateMachine.transition(to: .reconcilingFullMap)
RDEPUBBackgroundTrace.log(
"Reconciliation",
"refreshBookPageMapInPlace: enqueued reconcileFullMap chapters=\(bookPageMap.totalChapters) pages=\(bookPageMap.totalPages)"
)
enqueuePendingPageMapUpdate( enqueuePendingPageMapUpdate(
RDEPUBPendingPageMapUpdate( RDEPUBPendingPageMapUpdate(
pageMap: bookPageMap, pageMap: bookPageMap,
@ -225,6 +229,10 @@ final class RDEPUBPresentationRuntime {
switch decision { switch decision {
case .keepCurrentWindow: case .keepCurrentWindow:
RDEPUBBackgroundTrace.log(
"Reconciliation",
"commitPendingPageMapUpdate: keepCurrentWindow — removed pending update, totalPages=\(update.pageMap.totalPages)"
)
removePendingPageMapUpdate(at: index) removePendingPageMapUpdate(at: index)
return false return false
@ -238,7 +246,7 @@ final class RDEPUBPresentationRuntime {
return false return false
} }
case .extendPartial(let currentPageNumber, let currentLocation): case .extendPartial(_, let currentLocation):
removePendingPageMapUpdate(at: index) removePendingPageMapUpdate(at: index)
applyPageMapToLiveModel(update.pageMap, source: update.source) applyPageMapToLiveModel(update.pageMap, source: update.source)
if let currentLocation, if let currentLocation,