feat(service): implement docrevision Version/Revision kernel
Add canonicalize, stable block map, diff, risk floor, memory ledger service, contract fixtures, concurrency tests, and backfill CLI. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/docrevision"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// document-revision-backfill dry-runs or applies controlled document output.md into the ledger.
|
||||
func main() {
|
||||
dsn := flag.String("dsn", os.Getenv("TEST_DATABASE_URL"), "postgres DSN")
|
||||
repoRoot := flag.String("repo-root", ".", "repository root for relative work_dir")
|
||||
apply := flag.Bool("apply", false, "apply changes (default dry-run)")
|
||||
outPath := flag.String("report", "", "write JSON report path")
|
||||
flag.Parse()
|
||||
if *dsn == "" {
|
||||
fmt.Fprintln(os.Stderr, "dsn or TEST_DATABASE_URL required")
|
||||
os.Exit(2)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
defer cancel()
|
||||
pool, err := pgxpool.New(ctx, *dsn)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer pool.Close()
|
||||
|
||||
rows, err := pool.Query(ctx, `
|
||||
SELECT doc_id, COALESCE(work_dir,''), COALESCE(content_sha256,''), COALESCE(current_state,'drafting'), project_id
|
||||
FROM document_records
|
||||
ORDER BY doc_id`)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
type item struct {
|
||||
DocID string `json:"doc_id"`
|
||||
Status string `json:"status"`
|
||||
Detail string `json:"detail,omitempty"`
|
||||
SHA string `json:"sha,omitempty"`
|
||||
FileSHA string `json:"file_sha,omitempty"`
|
||||
}
|
||||
report := struct {
|
||||
DryRun bool `json:"dry_run"`
|
||||
Items []item `json:"items"`
|
||||
Success int `json:"success"`
|
||||
Missing int `json:"missing"`
|
||||
Mismatch int `json:"hash_mismatch"`
|
||||
}{DryRun: !*apply}
|
||||
|
||||
svc := docrevision.NewService(nil)
|
||||
for rows.Next() {
|
||||
var docID, workDir, dbSHA, state string
|
||||
var projectID int64
|
||||
if err := rows.Scan(&docID, &workDir, &dbSHA, &state, &projectID); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
it := item{DocID: docID, SHA: dbSHA}
|
||||
if workDir == "" {
|
||||
it.Status = "missing"
|
||||
it.Detail = "empty work_dir"
|
||||
report.Missing++
|
||||
report.Items = append(report.Items, it)
|
||||
continue
|
||||
}
|
||||
path := workDir
|
||||
if !filepath.IsAbs(path) {
|
||||
path = filepath.Join(*repoRoot, workDir)
|
||||
}
|
||||
body, err := os.ReadFile(filepath.Join(path, "output.md"))
|
||||
if err != nil {
|
||||
it.Status = "missing"
|
||||
it.Detail = err.Error()
|
||||
report.Missing++
|
||||
report.Items = append(report.Items, it)
|
||||
continue
|
||||
}
|
||||
canon := docrevision.CanonicalizeMarkdown(string(body))
|
||||
fileSHA := docrevision.SHA256Hex(canon)
|
||||
it.FileSHA = fileSHA
|
||||
if dbSHA != "" && !strings.EqualFold(dbSHA, fileSHA) {
|
||||
it.Status = "hash_mismatch"
|
||||
it.Detail = "document_records.content_sha256 != file"
|
||||
report.Mismatch++
|
||||
report.Items = append(report.Items, it)
|
||||
continue
|
||||
}
|
||||
if *apply {
|
||||
if _, err := svc.OpenTemplateVersion(ctx, docID, canon, docrevision.ActorSnapshot{DisplayName: "backfill"}, projectID, workDir); err != nil {
|
||||
it.Status = "error"
|
||||
it.Detail = err.Error()
|
||||
report.Items = append(report.Items, it)
|
||||
continue
|
||||
}
|
||||
}
|
||||
it.Status = "success"
|
||||
report.Success++
|
||||
report.Items = append(report.Items, it)
|
||||
}
|
||||
enc, _ := json.MarshalIndent(report, "", " ")
|
||||
if *outPath != "" {
|
||||
_ = os.WriteFile(*outPath, enc, 0o644)
|
||||
}
|
||||
fmt.Println(string(enc))
|
||||
if report.Mismatch > 0 {
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user