f92302cc64
Reconstructing full document content from chunks relied on position math (offset = content length - (EndAt - lastEndAt)) that assumes len([]rune(Content)) == EndAt - StartAt. Two upstream behaviors break that invariant and caused the merged "全文" view to drop or duplicate text: - The parent-child chunker prepends a synthetic table header to split tables; that header is zero-width in position space (start == end), so Content is longer than EndAt - StartAt. - Chunk Content can retain HTML entities (", > ...), inflating the rune count relative to the source span. Replace position-based trimming with text-overlap matching: find where the accumulated text's suffix reappears at the head of the next chunk and join there. Positions are only used to size the search window. This naturally skips the prepended header and is immune to entity length drift. Extract the logic into searchutil.AppendWithOverlap / MergeTextChunks and reuse it across the three backend stitching sites (wiki_ingest reconstructContent, graph mergeChunkContents, chat_pipeline mergeOverlappingChunks). Mirror the same algorithm in the frontend doc-content merge. Also fix the markdown hr/heading styles (thin solid divider, primary heading color).