feat(webui): CHAT-02 Console, read-only conversation view (#1507)
History opens a seat's conversation from the Waiting card, table row and inspector. It pages the whole branch through the CHAT-02 board routes, renders untrusted text inert, polls with the follow cursor, and marks every switch (branch, newer, reconcile, gone). The WebUI proxy passes only the two conversation routes' queries upstream. Dewey authored it. Filbert asked for changes on r1 (24b046af) and approved r2 (d06de6a7) in review 160dd68d. A relaunch shows 'newer', not 'reconcile', a deviation from brief 2.3 item 6 that Filbert accepted. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -54,6 +54,7 @@ test('proxy preserves exact request bytes, status and receipt, rejects forms and
|
||||
let body = ''; for await (const c of req) body += c;
|
||||
requests.push({ url: req.url, method: req.method, body });
|
||||
if (req.url === '/api/board') { res.writeHead(302, { location: 'http://192.0.2.1/' }); return res.end('{}'); }
|
||||
if (req.url.startsWith('/api/conversation')) { res.writeHead(404, { 'content-type': 'application/json' }); return res.end('{"error":"fixture unknown <x>","refusal":{"code":"unknown-branch","reconcile":true}}'); }
|
||||
res.writeHead(409, { 'content-type': 'application/json' }); res.end('{"error":"fixture refusal <unsafe>"}');
|
||||
});
|
||||
await new Promise(r => upstream.listen(0, '127.0.0.1', r));
|
||||
@@ -73,6 +74,21 @@ test('proxy preserves exact request bytes, status and receipt, rejects forms and
|
||||
assert.equal(requests.length, 2);
|
||||
assert.equal((await fetch(base + '/api/board')).status, 502);
|
||||
assert.equal(requests.length, 3);
|
||||
// CHAT-02 conversation routes: GET only, the query passes unchanged, the board's status and body come back as sent.
|
||||
for (const path of ['/api/conversations', '/api/conversation?id=pi-0a&branch=b.e5&cursor=c-1', '/api/conversation?id=x&id=y&unknown=%3C']) {
|
||||
const res = await fetch(base + path);
|
||||
assert.equal(res.status, 404, path);
|
||||
assert.equal(await res.text(), '{"error":"fixture unknown <x>","refusal":{"code":"unknown-branch","reconcile":true}}');
|
||||
assert.deepEqual(requests.at(-1), { url: path, method: 'GET', body: '' });
|
||||
}
|
||||
const before = requests.length;
|
||||
assert.equal((await post(base, '/api/conversation?id=x', '{}')).status, 405);
|
||||
assert.equal((await post(base, '/api/conversations', '{}')).status, 405);
|
||||
assert.equal((await fetch(base + '/api/conversation?id=x', { headers: { origin: 'https://evil.example' } })).status, 403);
|
||||
assert.equal(requests.length, before, 'refused before the board');
|
||||
// Only the conversation routes carry a query upstream.
|
||||
await fetch(base + '/api/board?x=1');
|
||||
assert.equal(requests.at(-1).url, '/api/board');
|
||||
} finally { await close(web); await close(upstream); }
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user