Skip to content

Commit b8cf83a

Browse files
committed
fix(qa): keep Matrix mention preview finals strict
1 parent 2f1e314 commit b8cf83a

2 files changed

Lines changed: 55 additions & 3 deletions

File tree

extensions/qa-matrix/src/runners/contract/scenario-runtime-room.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,7 @@ async function runMatrixToolProgressScenario(
868868
expectedPreviewKind: MatrixQaObservedEvent["kind"];
869869
finalText: string;
870870
allowFinalOnly?: boolean;
871+
allowFinalBeforeProgress?: boolean;
871872
allowTopLevelFinalWithProgress?: boolean;
872873
label: string;
873874
allowGenericProgressLine?: boolean;
@@ -926,7 +927,9 @@ async function runMatrixToolProgressScenario(
926927
observedEvents: context.observedEvents,
927928
predicate: (event) =>
928929
isProgressEvent(event) ||
929-
((params.allowFinalOnly === true || params.allowTopLevelFinalWithProgress === true) &&
930+
((params.allowFinalOnly === true ||
931+
params.allowFinalBeforeProgress === true ||
932+
params.allowTopLevelFinalWithProgress === true) &&
930933
isFinalReply(event)),
931934
roomId: context.roomId,
932935
since: startSince,
@@ -946,7 +949,10 @@ async function runMatrixToolProgressScenario(
946949
);
947950
});
948951
if (isFinalReply(preview.event)) {
949-
if (params.allowTopLevelFinalWithProgress === true && params.allowFinalOnly !== true) {
952+
if (
953+
(params.allowFinalBeforeProgress === true || params.allowTopLevelFinalWithProgress === true) &&
954+
params.allowFinalOnly !== true
955+
) {
950956
const progressAfterFinal = await client
951957
.waitForRoomEvent({
952958
observedEvents: context.observedEvents,
@@ -1230,7 +1236,7 @@ export async function runToolProgressMentionSafetyScenario(context: MatrixQaScen
12301236
expectedPreviewKind: "message",
12311237
finalText: buildMatrixQaToken("MATRIX_QA_TOOL_PROGRESS_MENTION_SAFE"),
12321238
label: "tool progress mention safety",
1233-
allowTopLevelFinalWithProgress: true,
1239+
allowFinalBeforeProgress: true,
12341240
mentionSafety: true,
12351241
progressPattern: /@room|@alice:matrix-qa\.test|!room:matrix-qa\.test/i,
12361242
triggerBodyBuilder: buildMatrixToolProgressMentionSafetyPrompt,

extensions/qa-matrix/src/runners/contract/scenarios.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3982,6 +3982,52 @@ describe("matrix live qa scenarios", () => {
39823982
);
39833983
});
39843984

3985+
it("does not accept top-level finals after a Matrix mention-safety preview", async () => {
3986+
const context = matrixQaScenarioContext();
3987+
const primeRoom = vi.fn().mockResolvedValue("driver-sync-start");
3988+
const sendTextMessage = vi.fn().mockResolvedValue("$tool-progress-mention-stale-trigger");
3989+
const previewEvent = matrixQaMessageEvent({
3990+
kind: "message",
3991+
eventId: "$tool-progress-mention-stale-preview",
3992+
body:
3993+
"Working...\n- `read matrix-progress-@room-@alice:matrix-qa.test-!room:matrix-qa.test.txt failed`",
3994+
formattedBody:
3995+
"Working...<br><ul><li><code>read matrix-progress-@room-@alice:matrix-qa.test-!room:matrix-qa.test.txt failed</code></li></ul>",
3996+
mentions: {},
3997+
});
3998+
const waitForRoomEvent = vi
3999+
.fn()
4000+
.mockImplementationOnce(async () => {
4001+
context.observedEvents.push(previewEvent);
4002+
return { event: previewEvent, since: "driver-sync-preview" };
4003+
})
4004+
.mockImplementationOnce(async (params: { predicate: (event: MatrixQaObservedEvent) => boolean }) => {
4005+
const topLevelFinal = matrixQaMessageEvent({
4006+
kind: "message",
4007+
eventId: "$tool-progress-mention-stale-final",
4008+
body: readMatrixQaReplyDirective(
4009+
mockMessageBody(sendTextMessage, "sendTextMessage"),
4010+
"MATRIX_QA_TOOL_PROGRESS_MENTION_SAFE_FIXED",
4011+
),
4012+
});
4013+
expect(params.predicate(topLevelFinal)).toBe(false);
4014+
context.observedEvents.push(topLevelFinal);
4015+
throw new Error("timed out after 8000ms waiting for Matrix room event");
4016+
});
4017+
createMatrixQaClient.mockReturnValue({
4018+
primeRoom,
4019+
sendTextMessage,
4020+
waitForRoomEvent,
4021+
});
4022+
4023+
const scenario = requireMatrixQaScenario("matrix-room-tool-progress-mention-safety");
4024+
4025+
await expect(runMatrixQaScenario(scenario, context)).rejects.toThrow(
4026+
/timed out after 8000ms waiting for Matrix room event/,
4027+
);
4028+
expect(waitForRoomEvent).toHaveBeenCalledTimes(2);
4029+
});
4030+
39854031
it("preserves separate finalized block events when Matrix block streaming is enabled", async () => {
39864032
const primeRoom = vi.fn().mockResolvedValue("driver-sync-start");
39874033
const sendTextMessage = vi.fn().mockResolvedValue("$block-stream-trigger");

0 commit comments

Comments
 (0)