mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(desktop): scope thread typing to the thread root, not reply parent
getTypingScopeId keyed typing entries on the reply parent tag, so an agent working deep in a thread produced a threadHeadId that matched no ingress row (and missed the open-thread composer filter). Typing and completion events already carry a root tag for nested replies — prefer it, falling back to the parent for direct replies where root === parent and no root tag is emitted. Both the registration and post-message suppression paths flow through the same helper, so suppression keys stay consistent. Exported for tests. Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
co-authored by
Taylor Ho
parent
1f5ba5bb27
commit
e20408e053
@@ -0,0 +1,42 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
|
||||
import { getTypingScopeId } from "./useChannelTyping.ts";
|
||||
|
||||
const ROOT = "aaaa".repeat(16);
|
||||
const PARENT = "bbbb".repeat(16);
|
||||
const CHANNEL = "11111111-1111-1111-1111-111111111111";
|
||||
|
||||
describe("getTypingScopeId", () => {
|
||||
it("returns null for channel-scoped typing (no e tags)", () => {
|
||||
assert.equal(getTypingScopeId({ tags: [["h", CHANNEL]] }), null);
|
||||
});
|
||||
|
||||
it("uses the reply parent for direct replies to the thread head", () => {
|
||||
// Direct replies tag only the parent (root === parent, so no root tag).
|
||||
assert.equal(
|
||||
getTypingScopeId({
|
||||
tags: [
|
||||
["h", CHANNEL],
|
||||
["e", ROOT, "", "reply"],
|
||||
],
|
||||
}),
|
||||
ROOT,
|
||||
);
|
||||
});
|
||||
|
||||
it("prefers the thread root over the reply parent for nested replies", () => {
|
||||
// Nested replies tag both root and their immediate parent; thread
|
||||
// surfaces (ingress badge, open-thread composer) key on the root.
|
||||
assert.equal(
|
||||
getTypingScopeId({
|
||||
tags: [
|
||||
["h", CHANNEL],
|
||||
["e", ROOT, "", "root"],
|
||||
["e", PARENT, "", "reply"],
|
||||
],
|
||||
}),
|
||||
ROOT,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -57,8 +57,15 @@ function isTypingCompletionEvent(event: RelayEvent | null | undefined) {
|
||||
);
|
||||
}
|
||||
|
||||
function getTypingScopeId(event: RelayEvent) {
|
||||
return getThreadReference(event.tags).parentId ?? null;
|
||||
/**
|
||||
* Thread scope for a typing/completion event: the thread root, not the
|
||||
* immediate reply parent. Agents replying deep in a thread tag their nested
|
||||
* parent, but every thread surface (ingress badge, open-thread composer)
|
||||
* keys on the thread head id. Exported for tests.
|
||||
*/
|
||||
export function getTypingScopeId(event: Pick<RelayEvent, "tags">) {
|
||||
const reference = getThreadReference(event.tags);
|
||||
return reference.rootId ?? reference.parentId ?? null;
|
||||
}
|
||||
|
||||
function getTypingStateKey(pubkey: string, threadHeadId: string | null) {
|
||||
|
||||
Reference in New Issue
Block a user