@@ -1099,6 +1099,30 @@ func newTrailCreateRequest(title, body, branch, base, statusStr, typeStr, priori
10991099 return req
11001100}
11011101
1102+ // resolveTrailUpdateBody returns the body text to seed the interactive update
1103+ // form with. The list resource omits the description (it lives in
1104+ // body_document, served only by the detail endpoint), so update must fetch the
1105+ // detail body — otherwise the form prefills from the empty list body and a
1106+ // user edit against that blank baseline can overwrite a description they never
1107+ // saw. Best-effort: on a failed detail fetch it returns the list body plus the
1108+ // error so the caller can warn (mirroring runTrailShow); an empty detail body
1109+ // (older/partial server) falls back to the list body with no error.
1110+ func resolveTrailUpdateBody (ctx context.Context , client * api.Client , forge , owner , repo string , found * api.TrailResource ) (string , error ) {
1111+ body := found .Body
1112+ if found .Number > 0 {
1113+ bt , err := fetchTrailDescription (ctx , client , forge , owner , repo , found .Number )
1114+ if err != nil {
1115+ return body , err
1116+ }
1117+ // fetchTrailDescription already trims; a non-empty result supersedes
1118+ // the list body, an empty one (older/partial server) leaves it intact.
1119+ if bt != "" {
1120+ body = bt
1121+ }
1122+ }
1123+ return body , nil
1124+ }
1125+
11021126func newTrailUpdateCmd () * cobra.Command {
11031127 var statusStr , title , body , branch , typeStr , priorityStr string
11041128 var labelAdd , labelRemove , assigneeAdd , assigneeRemove , reviewerAdd , reviewerRemove []string
@@ -1221,7 +1245,16 @@ func runTrailUpdate(ctx context.Context, w, errW io.Writer, insecureHTTP bool, i
12211245 }
12221246 statusStr = string (metadata .Status )
12231247 title = metadata .Title
1224- body = metadata .Body
1248+ // The list resource omits the description; fetch the detail body so
1249+ // the form prefills with the current text and change detection below
1250+ // compares against the real server value. Warn on a fetch failure so
1251+ // a blank baseline doesn't silently overwrite an unseen description.
1252+ seedBody , bodyErr := resolveTrailUpdateBody (ctx , client , forge , owner , repoName , found )
1253+ if bodyErr != nil {
1254+ fmt .Fprintf (errW , "Warning: could not load current trail body: %v\n " , bodyErr )
1255+ }
1256+ body = seedBody
1257+ origStatus , origTitle , origBody := statusStr , title , body
12251258
12261259 form := NewAccessibleForm (
12271260 huh .NewGroup (
@@ -1240,9 +1273,12 @@ func runTrailUpdate(ctx context.Context, w, errW io.Writer, insecureHTTP bool, i
12401273 if formErr := form .Run (); formErr != nil {
12411274 return handleFormCancellation (w , "Trail update" , formErr )
12421275 }
1243- inputs .StatusChanged = true
1244- inputs .TitleChanged = true
1245- inputs .BodyChanged = true
1276+ // Only mark a field changed when the user actually edited it, so an
1277+ // untouched body/title/status isn't needlessly PATCHed (a no-op body
1278+ // PATCH would otherwise rewrite the description on every update).
1279+ inputs .StatusChanged = statusStr != origStatus
1280+ inputs .TitleChanged = title != origTitle
1281+ inputs .BodyChanged = body != origBody
12461282 }
12471283
12481284 statusStr = strings .TrimSpace (statusStr )
0 commit comments