@teamscala/service-boot 0.23.334 → 0.23.335
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Lane BRIEF resolution for task-sync: a spawned lane PULLS its own brief. The
|
|
7
7
|
* lane's CLI extension reads its own session id on load, resolves the task
|
|
8
|
-
* assigned to that session, and reads the brief from that task's
|
|
8
|
+
* assigned to that session, and reads the brief from that task's FIRST comment.
|
|
9
9
|
* Nothing is pasted, typed, passed as an argument or sent over a channel
|
|
10
10
|
* (`scala-docs/reference/action-emission-architecture.md` "The lane PULLS its
|
|
11
11
|
* brief"). This file owns the readAssignedBrief ORPC handler + its pure helper;
|
|
@@ -34,7 +34,7 @@ import { type Context } from "./auth-router.ts";
|
|
|
34
34
|
*/
|
|
35
35
|
export type BriefReadStatus = "ready" | "empty_brief" | "no_comment" | "unbound";
|
|
36
36
|
/**
|
|
37
|
-
* Shape the readAssignedBrief response from a resolved task + its
|
|
37
|
+
* Shape the readAssignedBrief response from a resolved task + its first
|
|
38
38
|
* comment. Pure (no prisma) so the decision — "no task/comment ⇒ nulls, never a
|
|
39
39
|
* verdict from no data" (`no-verdict-from-no-data`) — is unit-testable.
|
|
40
40
|
*
|
|
@@ -64,13 +64,12 @@ export declare function shapeBriefResponse(task: {
|
|
|
64
64
|
status: BriefReadStatus;
|
|
65
65
|
};
|
|
66
66
|
/**
|
|
67
|
-
* Read the
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* task has no comment yet — the extension treats that as "no brief to inject".
|
|
67
|
+
* Read the immutable FIRST comment on a work_items task. It is the launch brief;
|
|
68
|
+
* later comments are conversation and must never change the launch identity.
|
|
69
|
+
* Oldest-first by created_at with id as a deterministic tie-breaker. Returns null
|
|
70
|
+
* when the task has no comment yet.
|
|
72
71
|
*/
|
|
73
|
-
export declare function
|
|
72
|
+
export declare function readFirstTaskComment(prisma: Prisma, workItemId: string): Promise<CommentRow | null>;
|
|
74
73
|
/**
|
|
75
74
|
* readAssignedBrief ORPC handler. A lane's CLI extension calls this with its
|
|
76
75
|
* own session id to pull its brief. Same transport as bindLane/readTaskList: the
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Unit tests for the self-brief leg: shapeBriefResponse (the pure
|
|
7
7
|
* no-task/no-comment ⇒ nulls decision) + source-contract assertions that
|
|
8
|
-
*
|
|
8
|
+
* readFirstTaskComment reads the FIRST launch comment and the handler resolves by
|
|
9
9
|
* session. Covers `what-must-have-a-test` for the new procedure.
|
|
10
10
|
*/
|
|
11
11
|
import { describe, it, expect } from "bun:test";
|
|
12
|
-
import { shapeBriefResponse,
|
|
12
|
+
import { shapeBriefResponse, readFirstTaskComment } from "./task-sync-brief.ts";
|
|
13
13
|
|
|
14
14
|
describe("shapeBriefResponse (no verdict from no data)", () => {
|
|
15
15
|
it("classifies a missing task as unbound (work_item_id null)", () => {
|
|
@@ -76,14 +76,13 @@ describe("shapeBriefResponse (no verdict from no data)", () => {
|
|
|
76
76
|
});
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
describe("readAssignedBrief reads the
|
|
79
|
+
describe("readAssignedBrief reads the FIRST launch comment (source contract)", () => {
|
|
80
80
|
const briefSrc = Bun.file(new URL("./task-sync-brief.ts", import.meta.url).pathname);
|
|
81
81
|
|
|
82
|
-
it("queries comments
|
|
83
|
-
// The comment
|
|
84
|
-
// LATEST comment (this run's) the answer, never a stale prior-run comment.
|
|
82
|
+
it("queries comments oldest-first with an id tie-breaker", async () => {
|
|
83
|
+
// The first comment is immutable launch identity; later comments are dialogue.
|
|
85
84
|
const text = await briefSrc.text();
|
|
86
|
-
expect(text).toContain('orderBy: { created_at: "
|
|
85
|
+
expect(text).toContain('orderBy: [{ created_at: "asc" }, { id: "asc" }]');
|
|
87
86
|
expect(text).toContain("work_item_id: workItemId");
|
|
88
87
|
});
|
|
89
88
|
|
|
@@ -111,12 +110,12 @@ describe("readAssignedBrief reads the LATEST comment (source contract)", () => {
|
|
|
111
110
|
});
|
|
112
111
|
});
|
|
113
112
|
|
|
114
|
-
describe("
|
|
113
|
+
describe("readFirstTaskComment is a single deterministic launch-comment read", () => {
|
|
115
114
|
it("returns null when the prisma client has no comments model (feature-detect)", async () => {
|
|
116
115
|
// `comments` is a universal shared model, but the access is feature-detected
|
|
117
116
|
// like the fleet_agent_runs reads so a client without it degrades to "no
|
|
118
117
|
// brief" rather than throwing.
|
|
119
|
-
const out = await
|
|
118
|
+
const out = await readFirstTaskComment({} as never, "task-1");
|
|
120
119
|
expect(out).toBe(null);
|
|
121
120
|
});
|
|
122
121
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Lane BRIEF resolution for task-sync: a spawned lane PULLS its own brief. The
|
|
7
7
|
* lane's CLI extension reads its own session id on load, resolves the task
|
|
8
|
-
* assigned to that session, and reads the brief from that task's
|
|
8
|
+
* assigned to that session, and reads the brief from that task's FIRST comment.
|
|
9
9
|
* Nothing is pasted, typed, passed as an argument or sent over a channel
|
|
10
10
|
* (`scala-docs/reference/action-emission-architecture.md` "The lane PULLS its
|
|
11
11
|
* brief"). This file owns the readAssignedBrief ORPC handler + its pure helper;
|
|
@@ -39,7 +39,7 @@ import { resolveLaneTask, resolveTaskById } from "./task-sync-lane.ts";
|
|
|
39
39
|
export type BriefReadStatus = "ready" | "empty_brief" | "no_comment" | "unbound";
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
* Shape the readAssignedBrief response from a resolved task + its
|
|
42
|
+
* Shape the readAssignedBrief response from a resolved task + its first
|
|
43
43
|
* comment. Pure (no prisma) so the decision — "no task/comment ⇒ nulls, never a
|
|
44
44
|
* verdict from no data" (`no-verdict-from-no-data`) — is unit-testable.
|
|
45
45
|
*
|
|
@@ -90,13 +90,12 @@ export function shapeBriefResponse(
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
|
-
* Read the
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* task has no comment yet — the extension treats that as "no brief to inject".
|
|
93
|
+
* Read the immutable FIRST comment on a work_items task. It is the launch brief;
|
|
94
|
+
* later comments are conversation and must never change the launch identity.
|
|
95
|
+
* Oldest-first by created_at with id as a deterministic tie-breaker. Returns null
|
|
96
|
+
* when the task has no comment yet.
|
|
98
97
|
*/
|
|
99
|
-
export async function
|
|
98
|
+
export async function readFirstTaskComment(
|
|
100
99
|
prisma: Prisma,
|
|
101
100
|
workItemId: string,
|
|
102
101
|
): Promise<CommentRow | null> {
|
|
@@ -110,7 +109,7 @@ export async function readLatestTaskComment(
|
|
|
110
109
|
if (!comments?.findFirst) return null;
|
|
111
110
|
return comments.findFirst({
|
|
112
111
|
where: { work_item_id: workItemId },
|
|
113
|
-
orderBy: { created_at: "
|
|
112
|
+
orderBy: [{ created_at: "asc" }, { id: "asc" }],
|
|
114
113
|
});
|
|
115
114
|
}
|
|
116
115
|
|
|
@@ -147,6 +146,6 @@ export const readAssignedBriefHandler = authed.handler(async ({ input, context }
|
|
|
147
146
|
task = (await resolveLaneTask(prisma, session)) as (WorkItem & { id: string }) | null;
|
|
148
147
|
}
|
|
149
148
|
if (!task) return shapeBriefResponse(null, null);
|
|
150
|
-
const comment = await
|
|
149
|
+
const comment = await readFirstTaskComment(prisma, task.id);
|
|
151
150
|
return shapeBriefResponse(task, comment);
|
|
152
151
|
});
|