diff --git a/apps/web/app/lib/daemon-images.test.tsx b/apps/web/app/lib/daemon-images.test.tsx
index 1fb4379fc..f8cb376c5 100644
--- a/apps/web/app/lib/daemon-images.test.tsx
+++ b/apps/web/app/lib/daemon-images.test.tsx
@@ -152,7 +152,6 @@ describe('Markdown の画像(デーモンの添付)', () => {
expect(stub.calls).toEqual([]);
expect(createObjectURL).not.toHaveBeenCalled();
- // remoteImages={false} は今までどおり文字とリンク
expect(screen.getByRole('link', { name: '画像: y' })).toBeTruthy();
});
diff --git a/apps/web/app/lib/daemon-images.tsx b/apps/web/app/lib/daemon-images.tsx
index 9e376be54..713f81290 100644
--- a/apps/web/app/lib/daemon-images.tsx
+++ b/apps/web/app/lib/daemon-images.tsx
@@ -6,7 +6,6 @@ import { DaemonImagesProvider } from '@alteroid/ui';
import type { DaemonImages } from '@alteroid/ui';
/**
- * Markdown の画像の `src` が、いま接続しているデーモンの添付(`/attachments/`)なら id を返す。それ以外は `undefined`。
* 資格(Bearer)を送ってよいかの線はここだけに置く:
* - 絶対 URL に加え、`/attachments/` と `attachments/` の相対パスも、デーモンの base の下のものとして扱う:
* 取りに行く先は `src` ではなく接続中の base URL と id から組むので、資格がよそへ行く経路にならない。
diff --git a/apps/web/app/routes/chat.follow-up-order.test.tsx b/apps/web/app/routes/chat.follow-up-order.test.tsx
index 4da80095f..e1164572a 100644
--- a/apps/web/app/routes/chat.follow-up-order.test.tsx
+++ b/apps/web/app/routes/chat.follow-up-order.test.tsx
@@ -8,15 +8,11 @@ import { json, Providers, sse, storeTestBaseUrl, stubFetch } from '~/test-suppor
import Chat from './chat';
-// #4391: 返信の本文が流れ終わってもターンが続いているあいだに人間が続けて発言すると、その発言が返信より上に出ていた。
-// デーモンは発言を記録するとき、それまでの返信を先に日誌へ書き、同じ同期区間で `queued` を流す。画面はその `queued` で返信の行を分ける。
-
const ID = 'conv-follow-up-order';
const QUESTION = '二つ目の質問';
const REPLY = 'AIの回答2の本文';
const FOLLOW = '回答2への返事';
const TAIL = '返事を受けた続き';
-// 道具を挟んで再開した本文: 日誌では区切りの空行(#4339)を挟んで TAIL と1発言になる
const AFTER_TOOL = '道具の後の本文';
const ChatRoute = Chat as unknown as (props: {
@@ -80,7 +76,6 @@ describe.each([
{
label: '割るデーモン(#4391 以降)',
split: true,
- // 発言の記録の前に、そこまでの返信が書かれる
whenQueued: [
question,
{ id: 'm2', at: '2026-10-10T01:00:19.000Z', role: 'outbound', text: REPLY },
@@ -105,7 +100,6 @@ describe.each([
whenDone: [
question,
follow,
- // 追送の割り目には区切りが入らず、道具の境目にだけ入る
{
id: 'm4',
at: '2026-10-10T01:00:40.000Z',
@@ -193,7 +187,6 @@ describe.each([
expect(chatCalls).toBe(2);
});
- // デーモンが追送を記録した: 返信の行が分かれ、履歴に追送が入る
messages = whenQueued;
queued.open();
recorded.open();
@@ -211,7 +204,6 @@ describe.each([
const shown = items();
expect(countOf(shown, TAIL)).toBe(1);
expect(countOf(shown, AFTER_TOOL)).toBe(1);
- // 追送の後に流れた続きは、追送より下に出る
expect(indexOf(shown, FOLLOW)).toBeLessThan(indexOf(shown, TAIL));
});
diff --git a/apps/web/app/routes/chat.reply-segment-separator.test.tsx b/apps/web/app/routes/chat.reply-segment-separator.test.tsx
index aa0708581..1ec65f1b9 100644
--- a/apps/web/app/routes/chat.reply-segment-separator.test.tsx
+++ b/apps/web/app/routes/chat.reply-segment-separator.test.tsx
@@ -8,10 +8,6 @@ import { json, Providers, sse, storeTestBaseUrl, stubFetch } from '~/test-suppor
import Chat from './chat';
-// デーモンは、1つのターンの中で本文が道具を挟んで再開したとき、日誌の本文の境目に空行を入れる(#4339)。
-// 画面へ流れる SSE の text には空行が入らないので、pendingOwnLines は分かれた返信の行を
-// 区切りあり(空行)と区切りなし(古いデーモン)の両方で日誌の1発言と照合する。どちらでも確定後に写しが末尾に残らない。
-
const ID = 'conv-tail';
const BEFORE_HEAD = '待ち時間を 35 秒ほどにすれば、必ず Gotenberg が先に切れて';
const BEFORE_TAIL = '、その理由を受け取れます。';
@@ -188,7 +184,6 @@ describe.each([
afterTool.open();
await screen.findByText(AFTER);
- // 道具の前の行は、末尾まで書かれている
expect(items().some((text) => text.includes(BEFORE_HEAD + BEFORE_TAIL))).toBe(true);
replied = true;
@@ -199,7 +194,6 @@ describe.each([
const shown = items();
expect(shown.filter((text) => text.includes(AFTER))).toHaveLength(1);
expect(shown.filter((text) => text.includes(BEFORE_HEAD))).toHaveLength(1);
- // 確定した1発言が最後に在り、手元の写しが後ろに居座らない
expect(shown.at(-1)).toContain(BEFORE_HEAD + BEFORE_TAIL);
expect(shown.at(-1)).toContain(AFTER);
});
diff --git a/apps/web/app/routes/chat.reply-segment-tail.test.tsx b/apps/web/app/routes/chat.reply-segment-tail.test.tsx
index b80e3fe14..3e7c609e0 100644
--- a/apps/web/app/routes/chat.reply-segment-tail.test.tsx
+++ b/apps/web/app/routes/chat.reply-segment-tail.test.tsx
@@ -8,10 +8,6 @@ import { json, Providers, sse, storeTestBaseUrl, stubFetch } from '~/test-suppor
import Chat from './chat';
-// 道具の直前の本文の末尾と `tool` が同じ網の塊で届くと、末尾が画面の行に書かれないまま落ちていた。
-// 行の本文が日誌の本文(ターンの本文を区切りなしで連結した1発言)と食い違い、pendingOwnLines の照合に永久に当たらず、
-// 前半(途中で切れた版)と後半が会話の末尾に居座った(会話 82d90cd7 の返答 36291767、2026-10-09)。
-
const ID = 'conv-tail';
const BEFORE_HEAD = '待ち時間を 35 秒ほどにすれば、必ず Gotenberg が先に切れて';
const BEFORE_TAIL = '、その理由を受け取れます。';
@@ -149,7 +145,6 @@ describe('道具の直前の本文の末尾と tool が同じ塊で届く(会
id: 'm2',
at: '2026-10-09T08:27:32.000Z',
role: 'outbound',
- // 日誌はターンの本文を区切りなしで連結した1発言として載せる
text: BEFORE_HEAD + BEFORE_TAIL + AFTER,
},
]
@@ -185,7 +180,6 @@ describe('道具の直前の本文の末尾と tool が同じ塊で届く(会
afterTool.open();
await screen.findByText(AFTER);
- // 道具の前の行は、末尾まで書かれている
expect(items().some((text) => text.includes(BEFORE_HEAD + BEFORE_TAIL))).toBe(true);
replied = true;
@@ -196,7 +190,6 @@ describe('道具の直前の本文の末尾と tool が同じ塊で届く(会
const shown = items();
expect(shown.filter((text) => text.includes(AFTER))).toHaveLength(1);
expect(shown.filter((text) => text.includes(BEFORE_HEAD))).toHaveLength(1);
- // 確定した1発言が最後に在り、手元の写しが後ろに居座らない
expect(shown.at(-1)).toContain(BEFORE_HEAD + BEFORE_TAIL + AFTER);
});
});
diff --git a/apps/web/app/routes/chat.tsx b/apps/web/app/routes/chat.tsx
index 3527c2463..1d27d70b7 100644
--- a/apps/web/app/routes/chat.tsx
+++ b/apps/web/app/routes/chat.tsx
@@ -293,7 +293,7 @@ interface Line {
turnFailure?: 'failed' | 'held';
turnFailureKind?: TurnFailureKind;
replyGroup?: string;
- // 返信の途中に人間の発言が届いて(`queued`)分けた行の印: デーモンはそこで返信を割って日誌へ書くので(#4391)、割らない古いデーモンの本文と照合するときはこの境目に区切りを入れない
+ // 返信の途中に人間の発言が届いて(`queued`)分けた行の印: デーモンはそこで返信を割って日誌へ書くので、割らない古いデーモンの本文と照合するときはこの境目に区切りを入れない
splitByHuman?: true;
journalId?: string;
attachments?: readonly MessageAttachment[];
@@ -449,7 +449,7 @@ export function pendingOwnLines(
if (line.approval !== undefined) historyApprovals.set(line.approval.id, line.approval);
}
// 分かれた返信は連結した本文で照合する: 日誌はターンの本文を1つの発言として載せるので、行ごとだと二重に出る。
- // 連続した行の並びごとに照合する(長い並びを先に当てる): デーモンは承認カードやターン中に届いた人間の発言(#4391)でターンの本文を割って書くので、1ターンが日誌の複数の発言になる
+ // 連続した行の並びごとに照合する(長い並びを先に当てる): デーモンは承認カードやターン中に届いた人間の発言でターンの本文を割って書くので、1ターンが日誌の複数の発言になる
const groups = new Map();
for (const line of owned) {
if (line.replyGroup === undefined || line.role !== 'clone') continue;
@@ -462,7 +462,7 @@ export function pendingOwnLines(
let next = start + 1;
for (let end = members.length; end > start + 1; end -= 1) {
const run = members.slice(start, end);
- // 区切りあり(#4339 以降のデーモン: メッセージの境目に空行)と区切りなし(古いデーモン)の両方を受ける: Web とデーモンは版がずれる。
+ // 区切りあり(メッセージの境目に空行)と区切りなし(古いデーモン)の両方を受ける: Web とデーモンは版がずれる。
// 区切りありを先に当てる。どちらも履歴に在るなら、区切りありのほうが新しい形
const key = REPLY_SEGMENT_JOINERS.map(
(joiner) =>
@@ -1822,7 +1822,7 @@ export function ChatPane({
};
const apply = (event: ChatStreamEvent) => {
switch (event.type) {
- // 返信の行をここで分ける(#4391): デーモンは人間の発言を記録するとき、それまでの返信を先に日誌へ書く。続きを同じ行へ足すと、その発言より上に出るうえ、日誌の本文とも合わない
+ // 返信の行をここで分ける:デーモンは人間の発言を記録するとき、それまでの返信を先に日誌へ書く。続きを同じ行へ足すと、その発言より上に出るうえ、日誌の本文とも合わない
case 'queued': {
// 続けて届いた2通目でも印を落とさない: 1通目で行は既に閉じている
const split = replyKey !== undefined || splitByHuman;
@@ -2785,7 +2785,7 @@ export function ChatPane({
first.at,
);
const open = data.reachedStart === false;
- // 取り下げた発言は数えない(#4357): 吹き出しとして出していないため
+ // 取り下げた発言は数えない:吹き出しとして出していないため
const counted = visible.filter((message) => message.delivery !== 'withdrawn').length;
return `${formatDateTime(startedAt)}${open ? ' 以降' : ' に開始'} · 発言 ${counted} 件${open ? '以上' : ''}`;
})();
diff --git a/apps/web/app/routes/env-vars.test.tsx b/apps/web/app/routes/env-vars.test.tsx
index a870f4352..a0610fefc 100644
--- a/apps/web/app/routes/env-vars.test.tsx
+++ b/apps/web/app/routes/env-vars.test.tsx
@@ -470,7 +470,6 @@ describe('/env-vars 画面 — 置く・編集・削除', () => {
fireEvent.change(within(dialog).getByLabelText('値'), { target: { value: 'half-typed' } });
fireEvent.change(within(dialog).getByLabelText('渡す先'), { target: { value: 'app' } });
fireEvent.click(within(dialog).getByRole('button', { name: 'やめる' }));
- // 書きかけがあるので確認を挟む(#3418)。ここでは破棄を選んで閉じる
fireEvent.click(await screen.findByRole('button', { name: '破棄して閉じる' }));
await waitFor(() => expect(screen.queryByRole('dialog')).toBeNull());