fix: test

This commit is contained in:
Alex committed 2026-06-10 01:46:26 +01:00
1 parent 160736f075
commit fc88d11594
1 file changed
+47 -22
@@ -1,18 +1,27 @@
/**
* Tier-B · conversation visibility (persist vs. sidebar display)
*
* Exercises the conversation-visibility change end-to-end against the live
* stack. `save_conversation` no longer gates persistence — it controls sidebar
* visibility only (resolve_persistence in
* application/api/answer/services/persistence_policy.py). A conversation now
* always persists; whether it surfaces in GET /api/get_conversations is
* governed by the new `conversations.visibility` column ('listed' | 'hidden').
* Exercises the conversation-visibility contract end-to-end against the live
* stack. Conversations always persist; visibility defaults to `hidden` for
* EVERY request, and only an explicit request-level `visibility: "listed"` —
* which the first-party UI sends on normal chats — lists a row in the sidebar
* (resolve_persistence in
* application/api/answer/services/persistence_policy.py). The legacy
* `save_conversation` flag is deprecated and has no effect; whether a row
* surfaces in GET /api/get_conversations is governed by the
* `conversations.visibility` column ('listed' | 'hidden').
*
* Matrix covered:
* 1. first-party /stream, save_conversation omitted → listed, in sidebar
* 2. first-party /stream, save_conversation=false → hidden, not in sidebar (but persisted)
* 3. api-key agent /stream → hidden by default; listed on opt-in
* 4. /v1/chat/completions (OpenAI-compat) → hidden by default; listed on docsgpt.save_conversation
* 1. first-party /stream, visibility:'listed' (as the UI sends) → listed, in sidebar
* 2. first-party /stream, visibility omitted → hidden, not in sidebar (but persisted)
* 3. api-key agent /stream → hidden by default; legacy
* save_conversation:true must NOT list; explicit visibility:'listed' does
* 4. /v1/chat/completions (OpenAI-compat) → always hidden, even with
* docsgpt.save_conversation:true (the legacy flag external clients still send)
*
* Cases 3 and 4 are the regression guard for the sidebar-pollution bug where
* API clients sending the legacy flag listed conversations into the agent
* owner's sidebar.
*
* API-driven: assertions read the DB (`conversations.visibility`) and the real
* sidebar endpoint, not stream internals.
@@ -67,7 +76,7 @@ test.describe('tier-b · conversation visibility', () => {
await resetDb();
});
test('first-party chat (save_conversation omitted) persists as listed and appears in the sidebar', async ({
test('first-party chat (visibility: listed, as the UI sends) persists as listed and appears in the sidebar', async ({
browser,
}) => {
const { context, token } = await newUserContext(browser);
@@ -76,6 +85,7 @@ test.describe('tier-b · conversation visibility', () => {
const convId = await streamOnce(api, {
question: 'first-party listed turn',
conversation_id: null,
visibility: 'listed',
isNoneDoc: true,
chunks: '0',
});
@@ -88,7 +98,7 @@ test.describe('tier-b · conversation visibility', () => {
}
});
test('first-party chat with save_conversation=false persists hidden and is excluded from the sidebar', async ({
test('first-party chat without a visibility opt-in persists hidden and is excluded from the sidebar', async ({
browser,
}) => {
const { context, sub, token } = await newUserContext(browser);
@@ -97,7 +107,6 @@ test.describe('tier-b · conversation visibility', () => {
const convId = await streamOnce(api, {
question: 'first-party hidden turn',
conversation_id: null,
save_conversation: false,
isNoneDoc: true,
chunks: '0',
});
@@ -119,7 +128,7 @@ test.describe('tier-b · conversation visibility', () => {
}
});
test('api-key agent chat hides by default and lists only on explicit opt-in', async ({
test('api-key agent chat hides by default; legacy save_conversation must not list, explicit visibility does', async ({
browser,
}) => {
const { context, sub, token } = await newUserContext(browser);
@@ -128,7 +137,7 @@ test.describe('tier-b · conversation visibility', () => {
try {
const { key } = await publishClassicAgent(api, multipart, sub, 'vis-agent');
// api_key present → hidden by default.
// api_key present, no flags → hidden by default.
const hidden = await streamOnce(api, {
question: 'agent default hidden',
conversation_id: null,
@@ -138,12 +147,25 @@ test.describe('tier-b · conversation visibility', () => {
});
expect(await visibilityOf(hidden)).toBe('hidden');
// Regression guard: the legacy flag — which external integrations
// still send meaning "persist" — must NOT list into the owner's
// sidebar.
const legacy = await streamOnce(api, {
question: 'agent legacy flag stays hidden',
conversation_id: null,
api_key: key,
save_conversation: true,
isNoneDoc: true,
chunks: '0',
});
expect(await visibilityOf(legacy)).toBe('hidden');
// Explicit opt-in → listed.
const listed = await streamOnce(api, {
question: 'agent opt-in listed',
conversation_id: null,
api_key: key,
save_conversation: true,
visibility: 'listed',
isNoneDoc: true,
chunks: '0',
});
@@ -153,6 +175,7 @@ test.describe('tier-b · conversation visibility', () => {
const ids = await sidebarIds(api);
expect(ids).toContain(listed);
expect(ids).not.toContain(hidden);
expect(ids).not.toContain(legacy);
} finally {
await multipart.dispose();
await api.dispose();
@@ -160,7 +183,7 @@ test.describe('tier-b · conversation visibility', () => {
}
});
test('v1 chat completions persist hidden by default and list only on docsgpt.save_conversation', async ({
test('v1 chat completions always persist hidden — even with the legacy docsgpt.save_conversation flag', async ({
browser,
}) => {
const { context, sub, token } = await newUserContext(browser);
@@ -190,11 +213,13 @@ test.describe('tier-b · conversation visibility', () => {
).toBe(0);
expect(await sidebarIds(api)).toHaveLength(0);
// Opt-in via the docsgpt extension → listed.
// Regression guard: the legacy docsgpt.save_conversation flag —
// which external clients built on the old contract still send —
// must NOT list the conversation into the agent owner's sidebar.
const r2 = await v1.post('/v1/chat/completions', {
data: {
model: 'docsgpt',
messages: [{ role: 'user', content: 'hi v1 listed' }],
messages: [{ role: 'user', content: 'hi v1 legacy flag' }],
stream: false,
docsgpt: { save_conversation: true },
},
@@ -208,9 +233,9 @@ test.describe('tier-b · conversation visibility', () => {
sql: "user_id = $1 AND visibility = 'listed'",
params: [sub],
}),
).toBe(1);
// Exactly the opted-in conversation surfaces in the sidebar.
expect(await sidebarIds(api)).toHaveLength(1);
).toBe(0);
// The owner's sidebar stays empty no matter what v1 clients send.
expect(await sidebarIds(api)).toHaveLength(0);
} finally {
await v1.dispose();
}