fix(memory): 定宽时间戳存储 + rowid 确定性排序 + 遗留数据归一化

- formatTime 改用固定 30 字节布局(9 位小数秒),让 TEXT 列的字典序与时间序一致(RFC3339Nano 会去掉尾随零产生变宽字符串,秒内会反序)
- memory_items / project / project_chapter 的 ORDER BY 全部补 rowid 兜底,消除同 tick 打平时的顺序不确定
- 开库时幂等归一化变宽的历史值;无法解析的行原样保留,不阻塞开库
- 回归测试:变宽排序反例、同一时间戳插入序、归一化幂等与跳过
This commit is contained in:
AskaEth committed 2026-10-03 16:08:50 +08:00
1 parent 1ac126fc9e
commit 31086ed1ab
10 files changed
+745 -61

No files matched your search

@@ -61,8 +61,10 @@ func (s *Store) AddChapter(ctx context.Context, projectID string, ch Chapter) er
return nil
}
// ListChapters returns every chapter for projectID in insertion order. It returns
// an empty (non-nil) slice when there are none; a blank projectID returns
// ListChapters returns every chapter for projectID in insertion order
// (created_at ASC, rowid ASC) — rowid breaks created_at ties so chapters written
// within the same clock tick keep their insertion order. It returns an empty
// (non-nil) slice when there are none; a blank projectID returns
// ErrMissingProject.
func (s *Store) ListChapters(ctx context.Context, projectID string) ([]Chapter, error) {
if strings.TrimSpace(projectID) == "" {
@@ -70,7 +72,7 @@ func (s *Store) ListChapters(ctx context.Context, projectID string) ([]Chapter,
}
rows, err := s.db.QueryContext(ctx, `SELECT id, project_id, title, content,
created_at, updated_at FROM project_chapter
WHERE project_id = ? ORDER BY created_at ASC, id ASC`, projectID)
WHERE project_id = ? ORDER BY created_at ASC, rowid ASC`, projectID)
if err != nil {
return nil, fmt.Errorf("projectindex: list chapters: %w", err)
}