@@ -29,7 +29,9 @@ type uiAIJobsPage struct {
2929}
3030
3131type uiAIJobPage struct {
32- Header * uiHeader
32+ Header * uiHeader
33+ Job * uiAIJob
34+ // The slice contains the same single Job, just for HTML templates convenience.
3335 Jobs []* uiAIJob
3436 Results []* uiAIResult
3537 Trajectory []* uiAITrajectorySpan
@@ -49,6 +51,7 @@ type uiAIJob struct {
4951 CodeRevision string
5052 CodeRevisionLink string
5153 Error string
54+ Correct string
5255}
5356
5457type uiAIResult struct {
@@ -103,6 +106,22 @@ func handleAIJobPage(ctx context.Context, w http.ResponseWriter, r *http.Request
103106 if err != nil {
104107 return err
105108 }
109+ if correct := r .FormValue ("correct" ); correct != "" {
110+ if ! job .Finished .Valid || job .Error != "" {
111+ return fmt .Errorf ("job is in wrong state to set correct status" )
112+ }
113+ switch correct {
114+ case aiCorrectnessCorrect :
115+ job .Correct = spanner.NullBool {Bool : true , Valid : true }
116+ case aiCorrectnessIncorrect :
117+ job .Correct = spanner.NullBool {Bool : false , Valid : true }
118+ default :
119+ job .Correct = spanner.NullBool {}
120+ }
121+ if err := aidb .UpdateJob (ctx , job ); err != nil {
122+ return err
123+ }
124+ }
106125 trajectory , err := aidb .LoadTrajectory (ctx , job .ID )
107126 if err != nil {
108127 return err
@@ -111,9 +130,11 @@ func handleAIJobPage(ctx context.Context, w http.ResponseWriter, r *http.Request
111130 if err != nil {
112131 return err
113132 }
133+ uiJob := makeUIAIJob (job )
114134 page := & uiAIJobPage {
115135 Header : hdr ,
116- Jobs : []* uiAIJob {makeUIAIJob (job )},
136+ Job : uiJob ,
137+ Jobs : []* uiAIJob {uiJob },
117138 Trajectory : makeUIAITrajectory (trajectory ),
118139 }
119140 if m , ok := job .Results .Value .(map [string ]any ); ok && job .Results .Valid {
@@ -131,6 +152,16 @@ func handleAIJobPage(ctx context.Context, w http.ResponseWriter, r *http.Request
131152}
132153
133154func makeUIAIJob (job * aidb.Job ) * uiAIJob {
155+ correct := aiCorrectnessIncorrect
156+ if ! job .Finished .Valid {
157+ correct = aiCorrectnessPending
158+ } else if job .Error != "" {
159+ correct = aiCorrectnessErrored
160+ } else if ! job .Correct .Valid {
161+ correct = aiCorrectnessUnset
162+ } else if job .Correct .Bool {
163+ correct = aiCorrectnessCorrect
164+ }
134165 return & uiAIJob {
135166 ID : job .ID ,
136167 Link : fmt .Sprintf ("/ai_job?id=%v" , job .ID ),
@@ -144,6 +175,7 @@ func makeUIAIJob(job *aidb.Job) *uiAIJob {
144175 CodeRevision : job .CodeRevision ,
145176 CodeRevisionLink : vcs .LogLink (vcs .SyzkallerRepo , job .CodeRevision ),
146177 Error : job .Error ,
178+ Correct : correct ,
147179 }
148180}
149181
@@ -447,6 +479,14 @@ func workflowsForBug(bug *Bug, manual bool) map[ai.WorkflowType]bool {
447479 return workflows
448480}
449481
482+ const (
483+ aiCorrectnessCorrect = "✅"
484+ aiCorrectnessIncorrect = "❌"
485+ aiCorrectnessUnset = "❓"
486+ aiCorrectnessPending = "⏳"
487+ aiCorrectnessErrored = "💥"
488+ )
489+
450490func nullTime (v spanner.NullTime ) time.Time {
451491 if ! v .Valid {
452492 return time.Time {}
0 commit comments