Preserve relocation context for conflicted AI outputs
This commit is contained in:
@@ -136,6 +136,7 @@ func (s *service) finishCanvasStepOutput(ctx context.Context, run canvasQueueRun
|
||||
eventBoard = step.BoardID
|
||||
}
|
||||
var appliedBoard any
|
||||
var appliedEvent response
|
||||
var output any
|
||||
var version any
|
||||
if code == "" && started {
|
||||
@@ -158,9 +159,6 @@ func (s *service) finishCanvasStepOutput(ctx context.Context, run canvasQueueRun
|
||||
patch["text"] = generated.Text
|
||||
}
|
||||
|
||||
if err = appendAIEvent(ctx, tx, run.Project, run.Workspace, run.ID, "step.output", response{"step_id": step.ID, "board_id": eventBoard, "origin_board_id": step.BoardID, "canonical_root": step.CanonicalRoot, "target_incarnation": step.TargetIncarnation, "node_id": step.NodeID, "output": output}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, role, permissionErr := lockCanvasAIRunRoute(ctx, tx, run.Project, run.Workspace, eventBoard, run.Account)
|
||||
if permissionErr != nil && permissionErr != sql.ErrNoRows {
|
||||
return "", permissionErr
|
||||
@@ -196,13 +194,29 @@ func (s *service) finishCanvasStepOutput(ctx context.Context, run canvasQueueRun
|
||||
appliedBoard = eventBoard
|
||||
applied := response{"step_id": step.ID, "board_id": eventBoard, "node_id": step.NodeID, "patch": patch, "canvas_version": change.Snapshot.Version}
|
||||
change.addTargetContext(applied, step)
|
||||
if err = appendAIEvent(ctx, tx, run.Project, run.Workspace, run.ID, "step.applied", applied); err != nil {
|
||||
return "", err
|
||||
}
|
||||
appliedEvent = applied
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if output != nil {
|
||||
event := response{"step_id": step.ID, "board_id": eventBoard, "origin_board_id": step.BoardID, "canonical_root": step.CanonicalRoot, "target_incarnation": step.TargetIncarnation, "node_id": step.NodeID, "output": output}
|
||||
if status == "conflict" && identityOK && step.CanonicalRoot != "" && eventBoard != step.BoardID {
|
||||
model, e := loadCanvasModel(ctx, tx, run.Project, run.Workspace, step.CanonicalRoot)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
event["model"], event["document_format_version"], event["canvas_version"] = model.view(nil), canvasModelFormat, model.Versions[eventBoard]
|
||||
}
|
||||
if err = appendAIEvent(ctx, tx, run.Project, run.Workspace, run.ID, "step.output", event); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if appliedEvent != nil {
|
||||
if err = appendAIEvent(ctx, tx, run.Project, run.Workspace, run.ID, "step.applied", appliedEvent); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
var outputJSON any
|
||||
if output != nil {
|
||||
encoded, _ := json.Marshal(output)
|
||||
|
||||
@@ -43,7 +43,9 @@ func validCanvasAI(value any, kind string) bool {
|
||||
}
|
||||
|
||||
// Fingerprints exclude geometry and visual styles so a result can be applied
|
||||
// after a concurrent drag. Content/configuration edits invalidate the result.
|
||||
// after a concurrent drag. The board is the immutable plan origin, not the
|
||||
// current canonical owner; canonical target identity is checked separately.
|
||||
// Content/configuration edits invalidate the result.
|
||||
func canvasTargetFingerprint(board, node string, data map[string]any) string {
|
||||
target := map[string]any{"board_id": board, "node_id": node, "kind": data["kind"], "ai": data["ai"]}
|
||||
if canvasChoice(data["kind"], "image", "plain-image") {
|
||||
|
||||
Reference in New Issue
Block a user