package main import ( "fmt" "os" "fn-registry/functions/infra" ) // runPropose invokes the proposal generator pipeline and persists drafts // into registry.db.proposals (INSERT OR IGNORE — never overwrites reviewed). func runPropose(rootOverride string, dryRun bool) { root := resolveRegistryRoot(rootOverride) if _, err := os.Stat(rootOverride + "/registry.db"); err != nil && rootOverride != "" { // fall back to walk-up root = resolveRegistryRoot("") } if _, err := os.Stat(root + "/registry.db"); err != nil { fmt.Fprintf(os.Stderr, "error: registry.db not found under %s\n", root) os.Exit(1) } drafts, err := infra.GenerateProposalsFromTelemetry(root) if err != nil { fmt.Fprintf(os.Stderr, "error: generate: %v\n", err) os.Exit(1) } if len(drafts) == 0 { fmt.Println("propose: no proposal drafts generated (insufficient telemetry or all rules pass).") return } // Group by rule for the summary byRule := map[string]int{} for _, d := range drafts { byRule[d.RuleID]++ } fmt.Printf("propose: %d draft(s) generated\n", len(drafts)) for rule, n := range byRule { fmt.Printf(" %s: %d\n", rule, n) } if dryRun { fmt.Println("\nDRY RUN — drafts NOT persisted. Sample (first 5):") for i, d := range drafts { if i >= 5 { break } fmt.Printf(" [%s] %s → %s\n", d.RuleID, d.ID, d.Title) } return } inserted, total, err := infra.PersistProposalDrafts(root, drafts) if err != nil { fmt.Fprintf(os.Stderr, "error: persist: %v\n", err) os.Exit(1) } fmt.Printf("\npersisted: %d new, %d total (idempotent — existing IDs skipped)\n", inserted, total) }