feat: content hash y timestamps inteligentes en registry
Agrega content_hash a functions, types y apps para detectar cambios reales entre reindexaciones. Los timestamps created_at se preservan si el contenido no cambió, y updated_at solo se actualiza cuando hay cambios efectivos. Incluye migración 005, hash.go con SHA256 determinístico, y ajustes en store/indexer/models para el nuevo flujo de timestamps. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+38
-1
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IndexResult holds stats from an indexing run.
|
||||
@@ -24,6 +25,12 @@ type IndexResult struct {
|
||||
// Scans functions/ and types/ at the root level, plus any language-specific
|
||||
// directories (e.g. python/functions/, python/types/).
|
||||
func Index(db *DB, root string) (*IndexResult, error) {
|
||||
// Load existing timestamps before purging so we can preserve created_at
|
||||
oldFuncs, oldTypes, oldApps, err := db.LoadTimestamps()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading timestamps: %w", err)
|
||||
}
|
||||
|
||||
if err := db.Purge(); err != nil {
|
||||
return nil, fmt.Errorf("purging database: %w", err)
|
||||
}
|
||||
@@ -109,12 +116,16 @@ func Index(db *DB, root string) (*IndexResult, error) {
|
||||
knownTypes[t.ID] = true
|
||||
}
|
||||
|
||||
// Pass 2: validate and insert
|
||||
now := time.Now().UTC()
|
||||
|
||||
// Pass 2: validate, assign timestamps via hash comparison, and insert
|
||||
for _, t := range types {
|
||||
if verr := ValidateType(t, knownTypes); verr != nil {
|
||||
result.ValidationErrors = append(result.ValidationErrors, verr.Error())
|
||||
continue
|
||||
}
|
||||
t.ContentHash = ComputeTypeHash(t)
|
||||
applyTimestamps(&t.CreatedAt, &t.UpdatedAt, t.ContentHash, oldTypes[t.ID], now)
|
||||
if err := db.InsertType(t); err != nil {
|
||||
result.Errors = append(result.Errors, fmt.Sprintf("insert %s: %v", t.ID, err))
|
||||
continue
|
||||
@@ -127,6 +138,8 @@ func Index(db *DB, root string) (*IndexResult, error) {
|
||||
result.ValidationErrors = append(result.ValidationErrors, verr.Error())
|
||||
continue
|
||||
}
|
||||
f.ContentHash = ComputeFunctionHash(f)
|
||||
applyTimestamps(&f.CreatedAt, &f.UpdatedAt, f.ContentHash, oldFuncs[f.ID], now)
|
||||
if err := db.InsertFunction(f); err != nil {
|
||||
result.Errors = append(result.Errors, fmt.Sprintf("insert %s: %v", f.ID, err))
|
||||
continue
|
||||
@@ -139,6 +152,8 @@ func Index(db *DB, root string) (*IndexResult, error) {
|
||||
result.ValidationErrors = append(result.ValidationErrors, verr.Error())
|
||||
continue
|
||||
}
|
||||
a.ContentHash = ComputeAppHash(a)
|
||||
applyTimestamps(&a.CreatedAt, &a.UpdatedAt, a.ContentHash, oldApps[a.ID], now)
|
||||
if err := db.InsertApp(a); err != nil {
|
||||
result.Errors = append(result.Errors, fmt.Sprintf("insert %s: %v", a.ID, err))
|
||||
continue
|
||||
@@ -149,6 +164,28 @@ func Index(db *DB, root string) (*IndexResult, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// applyTimestamps sets created_at and updated_at based on whether the entry
|
||||
// existed before and whether its content changed.
|
||||
// - New entry (no old record): both set to now
|
||||
// - Unchanged (hash matches): both preserved from old record
|
||||
// - Changed (hash differs): created_at preserved, updated_at set to now
|
||||
func applyTimestamps(createdAt, updatedAt *time.Time, newHash string, old timestampRecord, now time.Time) {
|
||||
if old.CreatedAt.IsZero() {
|
||||
// New entry
|
||||
*createdAt = now
|
||||
*updatedAt = now
|
||||
return
|
||||
}
|
||||
// Existing entry — always preserve created_at
|
||||
*createdAt = old.CreatedAt
|
||||
if old.ContentHash == newHash {
|
||||
// No changes — preserve updated_at too
|
||||
*updatedAt = old.UpdatedAt
|
||||
} else {
|
||||
*updatedAt = now
|
||||
}
|
||||
}
|
||||
|
||||
// walkMD walks a directory recursively and calls fn for each .md file found.
|
||||
func walkMD(dir string, fn func(path string)) {
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user