internal/index/sqlite.go
@@ -156,9 +156,15 @@
   for rows.Next() {
      var st FileStat
      var hash sql.NullString
      if err := rows.Scan(&st.Path, &st.Size, &st.Mtime, &hash); err != nil {
      var size, mtime sql.NullInt64
      // 旧库迁移到 v2 后,老行的 size/mtime/content_hash 为 NULL(ALTER ADD COLUMN 不带值)。
      // 用 Null 类型容忍 NULL:指纹缺失的行在对账时 size/mtime 必然不等,会走
      // sha256 二次确认并重新写入指纹,实现自愈,不会误判为"未变更"。
      if err := rows.Scan(&st.Path, &size, &mtime, &hash); err != nil {
         return nil, err
      }
      st.Size = size.Int64
      st.Mtime = mtime.Int64
      st.ContentHash = hash.String
      m[st.Path] = st
   }
@@ -482,7 +488,7 @@
         visited[id] = true
         query := `
            SELECT id, from_node, to_node, relation, label
            SELECT id, from_node, to_node, relation, label, provenance
            FROM edges
            WHERE from_node = ?
         `
@@ -501,7 +507,7 @@
         for rows.Next() {
            var e graph.Edge
            var edgeID int64
            if err := rows.Scan(&edgeID, &e.FromNode, &e.ToNode, &e.Relation, &e.Label); err != nil {
            if err := rows.Scan(&edgeID, &e.FromNode, &e.ToNode, &e.Relation, &e.Label, &e.Provenance); err != nil {
               rows.Close()
               return nil, fmt.Errorf("扫描边失败: %w", err)
            }