refactor(web): share the composer's failed-send settlement

Reference serialization and transport failures dispatched the same
sink-settled failure inline; route both through one failSink method so the
duplication gate passes.
This commit is contained in:
Yichen Jiang committed 2026-10-19 23:03:43 +08:00
1 parent 882b9dad5b
commit b97a88f22e
1 file changed
+10 -12
@@ -709,12 +709,7 @@ export class SessionInputShell implements SessionInput {
out += draft.slice(cursor)
this.settleSink(attempt, this.deps.defaultSink(out.trim(), attachmentIds, mode, attempt.signal))
},
(error: unknown) => {
if (this.dead(attempt)) return
this.dispatchRun(({
type: 'sink-settled', attempt, ok: false, command: this.projection.command, message: errorText(error),
}))
},
(error: unknown) => { this.failSink(attempt, error) },
)
}
@@ -744,15 +739,18 @@ export class SessionInputShell implements SessionInput {
}
this.dispatchRun(({ type: 'sink-settled', attempt, ok: accepted, command: this.projection.command, outcome }))
},
(error: unknown) => {
if (this.dead(attempt)) return
this.dispatchRun(({
type: 'sink-settled', attempt, ok: false, command: this.projection.command, message: errorText(error),
}))
},
(error: unknown) => { this.failSink(attempt, error) },
)
}
/** Settle a send that ended without a Host outcome; the draft stays for correction. */
private failSink(attempt: SubmitAttempt, error: unknown): void {
if (this.dead(attempt)) return
this.dispatchRun(({
type: 'sink-settled', attempt, ok: false, command: this.projection.command, message: errorText(error),
}))
}
/** Enter adjudication: poll the session controller; failure = notice + draft retained (never a silent downgrade). */
private adjudicate(attempt: SubmitAttempt, draft: string): void {
const inputTriggers = this.deps.inputTriggers?.()