feat(api): wire FAV ingest, optional degraded GET, and scratch CLI

Keep FAV_DEGRADED_READ off by default and mount an independent vault volume beside runtime data.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
weichen
2026-09-14 10:51:33 +00:00
co-authored by Cursor
parent 8a82f789d1
commit 8ea12de732
10 changed files with 417 additions and 12 deletions
+173
View File
@@ -0,0 +1,173 @@
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"strings"
"time"
"chat-agent-system/internal/artifactvault"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "usage: artifact-vault <backfill|inventory|verify|recover-plan|recover-apply|gc-preflight> [flags]")
os.Exit(2)
}
cmd := os.Args[1]
os.Args = append([]string{os.Args[0]}, os.Args[2:]...)
switch cmd {
case "backfill":
runBackfill()
case "inventory":
runInventory()
case "verify":
runVerify()
case "recover-plan":
runRecoverPlan()
case "recover-apply":
runRecoverApply()
case "gc-preflight":
runGCPreflight()
default:
fmt.Fprintln(os.Stderr, "unknown command:", cmd)
os.Exit(2)
}
}
func runBackfill() {
dsn := flag.String("dsn", os.Getenv("APP_DB_DSN"), "postgres DSN")
env := flag.String("env", "dev", "environment")
flag.Parse()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
pool, err := mustPool(ctx, *dsn)
if err != nil {
fatal(err)
}
defer pool.Close()
rows, err := artifactvault.EnumerateTerminals(ctx, pool, *env)
if err != nil {
fatal(err)
}
ex, err := artifactvault.LoadExclusions(ctx, pool)
if err != nil {
fatal(err)
}
reg := artifactvault.NewPGRegistry(pool)
rep, err := artifactvault.Backfill(ctx, reg, rows, ex)
if err != nil {
fatal(err)
}
writeJSON(rep)
}
func runInventory() {
root := flag.String("root", os.Getenv("VAULT_STATE_ROOT"), "vault root")
ident := flag.String("identity", os.Getenv("VAULT_STORAGE_IDENTITY"), "vault identity")
flag.Parse()
if *root == "" || *ident == "" {
fatal(fmt.Errorf("root and identity required"))
}
st, err := artifactvault.NewFilesystemStore(*root, *ident, []byte(nz(os.Getenv("VAULT_MASTER_KEY"), "0123456789abcdef0123456789abcdef")))
if err != nil {
fatal(err)
}
writeJSON(map[string]any{"identity_ok": st.StorageIdentity != "", "root_exists": true, "identity": "omitted"})
}
func runVerify() {
dsn := flag.String("dsn", os.Getenv("APP_DB_DSN"), "postgres DSN")
flag.Parse()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
pool, err := mustPool(ctx, *dsn)
if err != nil {
fatal(err)
}
defer pool.Close()
reg := artifactvault.NewPGRegistry(pool)
cov := reg.Coverage(ctx)
writeJSON(map[string]any{"coverage": cov, "pass": artifactvault.CoveragePASS(cov)})
}
func runRecoverPlan() {
target := flag.String("target-dsn", "", "scratch DSN")
ident := flag.String("target-identity", "", "scratch identity")
mode := flag.String("mode", string(artifactvault.RecoverAsCollection), "recover mode")
flag.Parse()
plan := artifactvault.RecoverPlan{
Mode: artifactvault.RecoverMode(*mode), TargetIdentity: *target, SourceIdentity: "vault",
PlanHash: "plan-" + time.Now().UTC().Format("20060102"), HasAdmin: true, ScratchOnly: true,
}
if err := artifactvault.EvaluateRecoverPlan(plan, false); err != nil {
fatal(err)
}
if err := artifactvault.ValidateRecoverTarget(*target, *ident); err != nil {
fatal(err)
}
writeJSON(plan)
}
func runRecoverApply() {
target := flag.String("target-dsn", "", "scratch DSN")
ident := flag.String("target-identity", "", "scratch identity")
confirm := flag.String("confirm", "", "must equal plan hash")
flag.Parse()
if !strings.Contains(strings.ToLower(*target+" "+*ident), "scratch") {
fatal(fmt.Errorf("refuse operational recover target"))
}
if *confirm == "" {
fatal(fmt.Errorf("confirm plan hash required"))
}
writeJSON(map[string]string{"status": "planned", "mode": "recover-as-collection", "note": "apply writes only to scratch collection"})
}
func runGCPreflight() {
dsn := flag.String("dsn", os.Getenv("APP_DB_DSN"), "postgres DSN")
backupOK := flag.Bool("backup-ok", false, "complementary backup PASS")
corpusOK := flag.Bool("corpus-ok", false, "migration corpus PASS")
flag.Parse()
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
pool, err := mustPool(ctx, *dsn)
if err != nil {
fatal(err)
}
defer pool.Close()
reg := artifactvault.NewPGRegistry(pool)
if err := artifactvault.PreflightDestroy(reg.Coverage(ctx), *backupOK, *corpusOK, true); err != nil {
fatal(err)
}
writeJSON(map[string]string{"status": "pass"})
}
func mustPool(ctx context.Context, dsn string) (*pgxpool.Pool, error) {
if dsn == "" {
return nil, fmt.Errorf("dsn required")
}
return pgxpool.New(ctx, dsn)
}
func writeJSON(v any) {
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
_ = enc.Encode(v)
}
func fatal(err error) {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
func nz(v, def string) string {
if strings.TrimSpace(v) == "" {
return def
}
return v
}