Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 55 additions & 29 deletions desktop/tests/e2e/channel-agent-presence.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const AGENT_PUBKEY =
"554cef57437abac34522ac2c9f0490d685b72c80478cf9f7ed6f9570ee8624ea";
const CHANNEL_ID = "94a444a4-c0a3-5966-ab05-530c6ddc2301";
const CONVERSATION_ID = "afab2e62-a520-f16b-e63d-b291c2f679c9";
const USER_INPUT_EVENT_ID = "c".repeat(64);
const USER_INPUT_ROOT_EVENT_ID = "c".repeat(64);
const USER_INPUT_REQUEST_ID = "d".repeat(64);

function seedAgent() {
return {
Expand Down Expand Up @@ -49,7 +50,11 @@ async function seedTurn(
kind: "turn_started" | "turn_completed";
}) => void;
};
win.__BUZZ_E2E_SEED_ACTIVE_TURNS__?.({
const seed = win.__BUZZ_E2E_SEED_ACTIVE_TURNS__;
if (!seed) {
throw new Error("E2E active-turn seed bridge is unavailable");
}
seed({
agentPubkey,
channelId,
turnId: "presence-turn-1",
Expand Down Expand Up @@ -111,19 +116,62 @@ test.describe("channel header agent presence", () => {
kind: 46040,
}),
);
await page.waitForFunction(
() => typeof window.__BUZZ_E2E_EMIT_MOCK_MESSAGE__ === "function",
);
await page.evaluate(
({ agentPubkey, channelId, conversationId, eventId }) => {
({ agentPubkey, rootEventId }) => {
const win = window as Window & {
__BUZZ_E2E_EMIT_MOCK_MESSAGE__?: (input: {
channelName: string;
content: string;
id: string;
kind: number;
pubkey: string;
mentionPubkeys?: string[];
pubkey?: string;
}) => unknown;
};
const emit = win.__BUZZ_E2E_EMIT_MOCK_MESSAGE__;
if (!emit) {
throw new Error("E2E mock message bridge is unavailable");
}
emit({
channelName: "agents",
content: "Mock channel question parent",
id: rootEventId,
kind: 9,
mentionPubkeys: [agentPubkey],
});
},
{
agentPubkey: AGENT_PUBKEY,
rootEventId: USER_INPUT_ROOT_EVENT_ID,
},
);
await page.waitForFunction(
() => typeof window.__BUZZ_E2E_EMIT_MOCK_USER_INPUT__ === "function",
);
await page.evaluate(
({ agentPubkey, channelId, conversationId, requestId, rootEventId }) => {
const win = window as Window & {
__BUZZ_E2E_EMIT_MOCK_USER_INPUT__?: (input: {
channelName: string;
requestId?: string;
rootEventId: string;
parentEventId?: string;
content: string;
pubkey?: string;
}) => unknown;
};
win.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
const emit = win.__BUZZ_E2E_EMIT_MOCK_USER_INPUT__;
if (!emit) {
throw new Error("E2E user-input bridge is unavailable");
}
emit({
channelName: "agents",
requestId,
rootEventId,
parentEventId: rootEventId,
content: JSON.stringify({
request_id: "presence-question",
session_id: "presence-session",
Expand All @@ -141,38 +189,16 @@ test.describe("channel header agent presence", () => {
},
],
}),
id: eventId,
kind: 46040,
pubkey: agentPubkey,
});
},
{
agentPubkey: AGENT_PUBKEY,
channelId: CHANNEL_ID,
conversationId: CONVERSATION_ID,
eventId: USER_INPUT_EVENT_ID,
},
);
await page.evaluate(
({ agentPubkey, eventId }) => {
const win = window as Window & {
__BUZZ_E2E_EMIT_MOCK_MESSAGE__?: (input: {
channelName: string;
content: string;
id: string;
kind: number;
pubkey: string;
}) => unknown;
};
win.__BUZZ_E2E_EMIT_MOCK_MESSAGE__?.({
channelName: "agents",
content: "Choose a deployment target",
id: eventId,
kind: 9,
pubkey: agentPubkey,
});
requestId: USER_INPUT_REQUEST_ID,
rootEventId: USER_INPUT_ROOT_EVENT_ID,
},
{ agentPubkey: AGENT_PUBKEY, eventId: USER_INPUT_EVENT_ID },
);
await expect(
page.getByText("Choose a deployment target", { exact: true }),
Expand Down
13 changes: 13 additions & 0 deletions docs/crew/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,19 @@ stay fixed until another input changes. The desktop caller passes no clock and
the home surface has no ticker, so ages already only refresh when a store
changes. A caller that wants clock-driven recomputation passes `now`.

## D-040 — Keep E2E mock fixtures production-authorizable

- **Status:** Accepted
- **Date:** 2026-08-11
- **Links:** [`userInputAttentionProjection.ts`](../../desktop/src/features/agents/userInputAttentionProjection.ts), [`userInput.ts`](../../desktop/src/features/channels/lib/userInput.ts), issues #110 and #130

E2E mock fixtures must emit only events that production could actually
produce. A fixture must not bypass authority rules—owner `p` tag, canonical
`e` causal parent and ancestry, 64-hex ids, or an owned-agent profile—to make
a red spec green. When production rejects a mock event, fix the fixture for
fidelity, reusing the shared `__BUZZ_E2E_EMIT_MOCK_USER_INPUT__` helper, rather
than weakening the production rule or the spec.

## D-041 — The E2E mock bridge mirrors relay event semantics, not per-surface shortcuts

- **Status:** Accepted
Expand Down
3 changes: 3 additions & 0 deletions docs/crew/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ and in flight.
channel question card accepts an answer` passes again (issue #110); the two
remaining `channels.spec.ts` failures (sticky date divider, channel agent
activity indicators) are unrelated and predate this change on `main`.
- `channel-agent-presence.spec.ts` now passes its needs-you smoke-shard
scenario in 12/12 clean runs; the fix was an E2E fixture-fidelity gap, not
a product break (issue #130).
- Earlier focused live relay test: `1/1` passed with an isolated Buzz relay.
- Typecheck, file-size gate, Biome checks, production build, and
`git diff --check` passed.
Expand Down
Loading