package orch import ( "fmt" "ai-workflow-skill/packages/coord-core/protocol" "ai-workflow-skill/packages/coord-core/store" "github.com/spf13/cobra" ) type verifyRecordOptions struct { runID string taskID string attemptNo int checkName string status string summary string body string bodyFile string metadataJSON string recordedBy string } type verifyStatusOptions struct { runID string taskID string attemptNo int } func newVerifyCmd(root *rootOptions) *cobra.Command { cmd := &cobra.Command{ Use: "verify", Short: "Verification gate commands", Long: helpLong( "Verification gate commands record post-implementation checks and inspect task verification state.", "Verification gates keep orch from treating a worker's done signal as final completion before the required checks pass.", ), Example: ` orch --db .agents/coord.db verify record --run blog_mvp_001 --task T1 --check lint --status passed --summary "lint clean" orch --db .agents/coord.db verify status --run blog_mvp_001 --task T1`, } cmd.AddCommand(newVerifyRecordCmd(root)) cmd.AddCommand(newVerifyStatusCmd(root)) return cmd } func newVerifyRecordCmd(root *rootOptions) *cobra.Command { opts := &verifyRecordOptions{} cmd := &cobra.Command{ Use: "record", Short: "Record one verification check result for a task attempt", Long: helpLong( "Use verify record after reconcile has moved a task into verifying, or when a prior verification failure needs an updated check result.", "record upserts one named check result for the selected attempt, then recomputes the task gate and task status.", ), Example: ` orch --db .agents/coord.db verify record --run blog_mvp_001 --task T1 --check lint --status passed --summary "lint clean" orch --db .agents/coord.db verify record --run blog_mvp_001 --task T1 --check package-consumer --status failed --summary "consumer smoke failed" --body-file ./artifacts/package-consumer.txt`, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() sqlDB, err := openOrchDB(ctx, root.dbPath) if err != nil { return err } defer sqlDB.Close() body, err := resolveBodyValue(opts.body, opts.bodyFile) if err != nil { return err } result, err := store.NewOrchStore(sqlDB).RecordCheck(ctx, store.VerifyRecordInput{ RunID: opts.runID, TaskID: opts.taskID, AttemptNo: opts.attemptNo, CheckName: opts.checkName, Status: opts.status, Summary: opts.summary, Body: body, MetadataJSON: opts.metadataJSON, RecordedBy: opts.recordedBy, }) if err != nil { return err } resp := protocol.Success{ OK: true, Command: "verify record", Data: map[string]any{ "task": result.Task, "attempt": result.Attempt, "check": result.Check, "gate": result.Gate, }, } if root.json { return protocol.WriteJSON(cmd.OutOrStdout(), resp) } _, err = fmt.Fprintf( cmd.OutOrStdout(), "recorded check %s=%s for %s/%s attempt %d\n", result.Check.CheckName, result.Check.Status, result.Task.RunID, result.Task.TaskID, result.Attempt.AttemptNo, ) return err }, } cmd.Flags().StringVar(&opts.runID, "run", "", "Run ID") cmd.Flags().StringVar(&opts.taskID, "task", "", "Task ID") cmd.Flags().IntVar(&opts.attemptNo, "attempt", 0, "Attempt number; defaults to the latest attempt") cmd.Flags().StringVar(&opts.checkName, "check", "", "Check name") cmd.Flags().StringVar(&opts.status, "status", "", "Check status: passed, failed, or skipped") cmd.Flags().StringVar(&opts.summary, "summary", "", "Short verification summary") cmd.Flags().StringVar(&opts.body, "body", "", "Optional verification details") cmd.Flags().StringVar(&opts.bodyFile, "body-file", "", "Optional path to a verification details file") cmd.Flags().StringVar(&opts.metadataJSON, "metadata-json", "", "Structured metadata JSON for the check result") cmd.Flags().StringVar(&opts.recordedBy, "recorded-by", "orch", "Recorder identity for the check result") _ = cmd.MarkFlagRequired("run") _ = cmd.MarkFlagRequired("task") _ = cmd.MarkFlagRequired("check") _ = cmd.MarkFlagRequired("status") return cmd } func newVerifyStatusCmd(root *rootOptions) *cobra.Command { opts := &verifyStatusOptions{} cmd := &cobra.Command{ Use: "status", Short: "Show the current verification state for one task", Long: helpLong( "Use verify status to inspect the task spec snapshot, the selected attempt, and the current gate state in one response.", "Prefer this when a task is stuck in verifying or failed because of gate results.", ), Example: ` orch --db .agents/coord.db verify status --run blog_mvp_001 --task T1 orch --db .agents/coord.db --json verify status --run blog_mvp_001 --task T1 --attempt 2`, RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() sqlDB, err := openOrchDB(ctx, root.dbPath) if err != nil { return err } defer sqlDB.Close() result, err := store.NewOrchStore(sqlDB).GetVerificationStatus(ctx, store.VerificationStatusInput{ RunID: opts.runID, TaskID: opts.taskID, AttemptNo: opts.attemptNo, }) if err != nil { return err } resp := protocol.Success{ OK: true, Command: "verify status", Data: map[string]any{ "task": result.Task, "attempt": result.Attempt, "spec": result.Spec, "gate": result.Gate, }, } if root.json { return protocol.WriteJSON(cmd.OutOrStdout(), resp) } if result.Gate == nil { _, err = fmt.Fprintf(cmd.OutOrStdout(), "%s/%s has no verification gate\n", result.Task.RunID, result.Task.TaskID) return err } _, err = fmt.Fprintf(cmd.OutOrStdout(), "%s/%s verification status %s\n", result.Task.RunID, result.Task.TaskID, result.Gate.Status) return err }, } cmd.Flags().StringVar(&opts.runID, "run", "", "Run ID") cmd.Flags().StringVar(&opts.taskID, "task", "", "Task ID") cmd.Flags().IntVar(&opts.attemptNo, "attempt", 0, "Attempt number; defaults to the latest attempt") _ = cmd.MarkFlagRequired("run") _ = cmd.MarkFlagRequired("task") return cmd }