Files
zopu-code/repos/web/lib/work-os/work-unit-projection.test.ts
-Puter cc47007fa9 Slice 1 polish: archive dormant code, merge work-os into primitives, add futures
- Archive dormant apps (daemon, desktop, native, tui) and superseded
  packages/server into repos/ for reference
- Archive 21 dead web components (chat page shell, work-os cluster, strays)
  into repos/web/; keep reused message-rendering primitives in components/chat
- Merge @code/work-os into @code/primitives; work.ts absorbed via ./work
  subpath and barrel export; update all four importers
- Add docs/futures.md tracking audio/video (blocked at Flue + provider),
  web layout cleanup, and message rendering quality
- Repoint dev:zopu script to @code/agents (the live Flue server)
- Note repos/ reference-code convention in AGENTS.md
2026-07-27 16:34:17 +05:30

485 lines
15 KiB
TypeScript

import type { Doc, Id } from "@code/backend/convex/_generated/dataModel";
import { describe, expect, test } from "vitest";
import {
buildActivityTimeline,
buildWorkUnitCard,
buildWorkUnitDetail,
eventsForIssue,
extractArtifactPaths,
extractLatestSummary,
extractPullRequestFromEvents,
} from "./work-unit-projection";
import type { LinkedSignal } from "./work-unit-projection";
type Issue = Doc<"projectIssues">;
type Event = Doc<"projectEvents">;
const ISSUE_A = "issue-a" as Id<"projectIssues">;
const ISSUE_B = "issue-b" as Id<"projectIssues">;
const makeLinkedSignal = (
overrides: Partial<LinkedSignal> = {}
): LinkedSignal => ({
createdAt: 5000,
signalId: "sig-1" as Id<"signals">,
sourceCount: 2,
summary: "Three users hit the same error.",
title: "OAuth crash on Safari",
...overrides,
});
const makeIssue = (overrides: Partial<Issue> = {}): Issue =>
({
_creationTime: 1,
_id: ISSUE_A,
body: "Fix the Safari OAuth callback so users can complete sign-in.",
createdAt: 1000,
number: 1,
projectId: "project-1" as Id<"projects">,
status: "open",
title: "Fix Safari OAuth callback",
updatedAt: 2000,
...overrides,
}) as Issue;
const makeEvent = (
kind: string,
data: Record<string, unknown>,
overrides: Partial<Event> = {}
): Event =>
({
_creationTime: 1,
_id: `evt-${kind}-${overrides.createdAt ?? 1000}` as Id<"projectEvents">,
createdAt: overrides.createdAt ?? 1000,
data,
issueId: ISSUE_A,
kind,
projectId: "project-1" as Id<"projects">,
...overrides,
}) as Event;
describe("eventsForIssue", () => {
test("filters to a specific issue and ignores undefined", () => {
const events: Event[] = [
makeEvent("issue.created", { number: 1 }, { createdAt: 1000 }),
makeEvent(
"issue.created",
{ number: 2 },
{ createdAt: 2000, issueId: ISSUE_B }
),
];
expect(eventsForIssue(events, ISSUE_A)).toHaveLength(1);
expect(eventsForIssue(undefined, ISSUE_A)).toEqual([]);
});
});
describe("extractArtifactPaths", () => {
test("collects distinct paths from artifact.updated events", () => {
const events: Event[] = [
makeEvent(
"artifact.updated",
{ path: "work.md", revision: 1 },
{ createdAt: 1000 }
),
makeEvent(
"artifact.updated",
{ path: "work.md", revision: 2 },
{ createdAt: 2000 }
),
makeEvent(
"artifact.updated",
{ path: "artifacts.md", revision: 1 },
{ createdAt: 3000 }
),
makeEvent("issue.created", { number: 1 }, { createdAt: 4000 }),
];
expect(extractArtifactPaths(events)).toEqual(["artifacts.md", "work.md"]);
});
test("returns empty for no artifact events", () => {
expect(extractArtifactPaths([])).toEqual([]);
});
});
describe("buildWorkUnitCard", () => {
test("projects a fresh issue with no events and no linked signals", () => {
const card = buildWorkUnitCard({
issue: makeIssue(),
issueEvents: [],
linkedSignals: [],
});
expect(card.title).toBe("Fix Safari OAuth callback");
expect(card.status).toBe("open");
expect(card.stepCount).toBe(0);
expect(card.currentActivity).toBeNull();
expect(card.needsInput).toBe(false);
expect(card.hasPullRequest).toBe(false);
expect(card.artifactCount).toBe(0);
expect(card.signalCount).toBe(0);
expect(card.summary).toContain("Fix the Safari OAuth");
});
test("counts per-issue artifacts from events, not project-wide", () => {
const events: Event[] = [
makeEvent(
"artifact.updated",
{ path: "work.md", revision: 1 },
{ createdAt: 1000 }
),
makeEvent(
"artifact.updated",
{ path: "artifacts.md", revision: 1 },
{ createdAt: 2000 }
),
];
const card = buildWorkUnitCard({
issue: makeIssue({ status: "working" }),
issueEvents: events,
linkedSignals: [],
});
expect(card.artifactCount).toBe(2);
expect(card.stepCount).toBe(2);
});
test("reflects needs-input status and activity from events", () => {
const events = [
makeEvent("issue.created", { number: 1 }, { createdAt: 1000 }),
makeEvent("issue.queued", { number: 1 }, { createdAt: 2000 }),
makeEvent("agent.needs-input", {}, { createdAt: 3000 }),
];
const card = buildWorkUnitCard({
issue: makeIssue({ status: "needs-input" }),
issueEvents: events,
linkedSignals: [],
});
expect(card.needsInput).toBe(true);
expect(card.stepCount).toBe(3);
expect(card.currentActivity).toBe("Needs your input");
});
test("detects PR from gitea event", () => {
const events = [
makeEvent("issue.created", { number: 1 }, { createdAt: 1000 }),
makeEvent(
"gitea.pull_request.created",
{
pullRequest: { number: 42, url: "https://git.example.com/pulls/42" },
},
{ createdAt: 5000 }
),
];
const card = buildWorkUnitCard({
issue: makeIssue({ status: "completed" }),
issueEvents: events,
linkedSignals: [],
});
expect(card.hasPullRequest).toBe(true);
});
});
describe("linked signal projection", () => {
test("card signalCount reflects real linked signals", () => {
const card = buildWorkUnitCard({
issue: makeIssue(),
issueEvents: [],
linkedSignals: [
makeLinkedSignal(),
makeLinkedSignal({
signalId: "sig-2" as Id<"signals">,
title: "Build error",
}),
],
});
expect(card.signalCount).toBe(2);
});
test("card signalCount is 0 when no signals are linked", () => {
const card = buildWorkUnitCard({
issue: makeIssue(),
issueEvents: [],
linkedSignals: [],
});
expect(card.signalCount).toBe(0);
});
test("detail exposes linked signals with title, summary, and source count", () => {
const detail = buildWorkUnitDetail({
issue: makeIssue(),
issueEvents: [],
linkedSignals: [
makeLinkedSignal(),
makeLinkedSignal({
signalId: "sig-2" as Id<"signals">,
sourceCount: 5,
summary: "CI broke",
}),
],
});
expect(detail.signalCount).toBe(2);
expect(detail.linkedSignals).toHaveLength(2);
expect(detail.linkedSignals[0].title).toBe("OAuth crash on Safari");
expect(detail.linkedSignals[0].sourceCount).toBe(2);
expect(detail.linkedSignals[1].sourceCount).toBe(5);
});
test("detail linked signals empty when no attachment exists", () => {
const detail = buildWorkUnitDetail({
issue: makeIssue(),
issueEvents: [],
linkedSignals: [],
});
expect(detail.signalCount).toBe(0);
expect(detail.linkedSignals).toEqual([]);
});
});
describe("extractLatestSummary", () => {
test("returns the most recent agent summary", () => {
const events = [
makeEvent("agent.working", {}, { createdAt: 1000 }),
makeEvent(
"agent.completed",
{ summary: "All tests passed." },
{ createdAt: 5000 }
),
];
expect(extractLatestSummary(events)).toBe("All tests passed.");
});
test("returns null when no terminal agent event exists", () => {
const events = [
makeEvent("issue.created", { number: 1 }, { createdAt: 1000 }),
];
expect(extractLatestSummary(events)).toBeNull();
});
test("prefers failure error over earlier completion", () => {
const events = [
makeEvent("agent.completed", { summary: "Done." }, { createdAt: 1000 }),
makeEvent(
"agent.failed",
{ error: "Tests failed." },
{ createdAt: 5000 }
),
];
expect(extractLatestSummary(events)).toBe("Tests failed.");
});
});
describe("extractPullRequestFromEvents", () => {
test("extracts URL and number from gitea event", () => {
const events = [
makeEvent(
"gitea.pull_request.created",
{ pullRequest: { number: 7, url: "https://git.example.com/pulls/7" } },
{ createdAt: 1000 }
),
];
const info = extractPullRequestFromEvents(events);
expect(info.hasPR).toBe(true);
expect(info.url).toBe("https://git.example.com/pulls/7");
expect(info.number).toBe(7);
});
test("returns false when no PR event exists", () => {
expect(extractPullRequestFromEvents([]).hasPR).toBe(false);
});
});
describe("buildActivityTimeline", () => {
test("sorts newest first and maps labels", () => {
const events = [
makeEvent("issue.created", { number: 1 }, { createdAt: 1000 }),
makeEvent("agent.completed", { summary: "Done." }, { createdAt: 5000 }),
];
const timeline = buildActivityTimeline(events);
expect(timeline).toHaveLength(2);
expect(timeline[0].kind).toBe("agent.completed");
expect(timeline[0].label).toBe("Work completed");
expect(timeline[1].kind).toBe("issue.created");
expect(timeline[1].label).toBe("Work created");
});
test("maps signal.attached event to activity", () => {
const events = [
makeEvent(
"signal.attached",
{ signalId: "sig-1", signalProblemTitle: "OAuth crash" },
{ createdAt: 3000 }
),
];
const timeline = buildActivityTimeline(events);
expect(timeline[0].label).toBe("Signal linked");
expect(timeline[0].detail).toContain("OAuth crash");
});
});
describe("buildWorkUnitDetail", () => {
test("aggregates all detail fields from per-issue events", () => {
const events: Event[] = [
makeEvent("issue.created", { number: 1 }, { createdAt: 1000 }),
makeEvent(
"artifact.updated",
{ path: "work.md", revision: 2 },
{ createdAt: 2000 }
),
makeEvent(
"artifact.updated",
{ path: "artifacts.md", revision: 1 },
{ createdAt: 2500 }
),
makeEvent(
"gitea.pull_request.created",
{ pullRequest: { number: 3, url: "https://git.example.com/pulls/3" } },
{ createdAt: 3000 }
),
];
const detail = buildWorkUnitDetail({
issue: makeIssue({ status: "completed" }),
issueEvents: events,
linkedSignals: [makeLinkedSignal()],
});
expect(detail.stepCount).toBe(4);
expect(detail.artifactCount).toBe(2);
expect(detail.artifactPaths).toEqual(["artifacts.md", "work.md"]);
expect(detail.signalCount).toBe(1);
expect(detail.hasPullRequest).toBe(true);
expect(detail.pullRequestUrl).toBe("https://git.example.com/pulls/3");
expect(detail.pullRequestNumber).toBe(3);
expect(detail.activity).toHaveLength(4);
expect(detail.activity[0].kind).toBe("gitea.pull_request.created");
});
});
// ---------------------------------------------------------------------------
// Cross-issue isolation: one issue must never inherit another issue's
// artifacts, PR, signals, or activity.
// ---------------------------------------------------------------------------
describe("cross-issue isolation", () => {
const SIGNAL_A = makeLinkedSignal({ signalId: "sig-a" as Id<"signals"> });
const SIGNAL_B = makeLinkedSignal({
signalId: "sig-b" as Id<"signals">,
title: "Different signal",
});
const sharedEvents: Event[] = [
makeEvent(
"issue.created",
{ number: 1 },
{ createdAt: 1000, issueId: ISSUE_A }
),
makeEvent(
"artifact.updated",
{ path: "work.md", revision: 1 },
{ createdAt: 2000, issueId: ISSUE_A }
),
makeEvent(
"gitea.pull_request.created",
{ pullRequest: { number: 5, url: "https://git.example.com/pulls/5" } },
{ createdAt: 3000, issueId: ISSUE_A }
),
makeEvent(
"agent.completed",
{ summary: "Done for A." },
{ createdAt: 4000, issueId: ISSUE_A }
),
// Issue B events — completely separate
makeEvent(
"issue.created",
{ number: 2 },
{ createdAt: 1500, issueId: ISSUE_B }
),
makeEvent(
"artifact.updated",
{ path: "artifacts.md", revision: 1 },
{ createdAt: 2500, issueId: ISSUE_B }
),
makeEvent(
"agent.failed",
{ error: "Failed for B." },
{ createdAt: 3500, issueId: ISSUE_B }
),
];
test("issue A does not inherit issue B's artifacts", () => {
const eventsA = eventsForIssue(sharedEvents, ISSUE_A);
const cardA = buildWorkUnitCard({
issue: makeIssue({ _id: ISSUE_A, number: 1 }),
issueEvents: eventsA,
linkedSignals: [SIGNAL_A],
});
expect(cardA.artifactCount).toBe(1);
expect(cardA.stepCount).toBe(4);
const eventsB = eventsForIssue(sharedEvents, ISSUE_B);
const cardB = buildWorkUnitCard({
issue: makeIssue({ _id: ISSUE_B, number: 2, title: "Issue B" }),
issueEvents: eventsB,
linkedSignals: [SIGNAL_B],
});
expect(cardB.artifactCount).toBe(1);
expect(cardB.stepCount).toBe(3);
});
test("issue A does not inherit issue B's PR", () => {
const eventsB = eventsForIssue(sharedEvents, ISSUE_B);
const cardB = buildWorkUnitCard({
issue: makeIssue({ _id: ISSUE_B, number: 2, title: "Issue B" }),
issueEvents: eventsB,
linkedSignals: [],
});
expect(cardB.hasPullRequest).toBe(false);
});
test("issue A does not inherit issue B's summary", () => {
const eventsA = eventsForIssue(sharedEvents, ISSUE_A);
expect(extractLatestSummary(eventsA)).toBe("Done for A.");
const eventsB = eventsForIssue(sharedEvents, ISSUE_B);
expect(extractLatestSummary(eventsB)).toBe("Failed for B.");
});
test("detail for issue A lists only issue A's artifact paths", () => {
const eventsA = eventsForIssue(sharedEvents, ISSUE_A);
const detailA = buildWorkUnitDetail({
issue: makeIssue({ _id: ISSUE_A, number: 1 }),
issueEvents: eventsA,
linkedSignals: [SIGNAL_A],
});
expect(detailA.artifactPaths).toEqual(["work.md"]);
expect(detailA.pullRequestNumber).toBe(5);
});
test("detail for issue B lists only issue B's artifact paths and no PR", () => {
const eventsB = eventsForIssue(sharedEvents, ISSUE_B);
const detailB = buildWorkUnitDetail({
issue: makeIssue({ _id: ISSUE_B, number: 2, title: "Issue B" }),
issueEvents: eventsB,
linkedSignals: [],
});
expect(detailB.artifactPaths).toEqual(["artifacts.md"]);
expect(detailB.hasPullRequest).toBe(false);
expect(detailB.pullRequestUrl).toBeNull();
});
test("issue A does not inherit issue B's linked signals", () => {
const detailA = buildWorkUnitDetail({
issue: makeIssue({ _id: ISSUE_A, number: 1 }),
issueEvents: eventsForIssue(sharedEvents, ISSUE_A),
linkedSignals: [SIGNAL_A],
});
expect(detailA.signalCount).toBe(1);
expect(detailA.linkedSignals[0].title).toBe("OAuth crash on Safari");
const detailB = buildWorkUnitDetail({
issue: makeIssue({ _id: ISSUE_B, number: 2, title: "Issue B" }),
issueEvents: eventsForIssue(sharedEvents, ISSUE_B),
linkedSignals: [SIGNAL_B],
});
expect(detailB.signalCount).toBe(1);
expect(detailB.linkedSignals[0].title).toBe("Different signal");
});
});