@undefineds.co/linx 0.3.16 → 0.3.17
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.
- package/dist/generated/version.js +1 -1
- package/dist/lib/auto-mode/secretary.js +2 -2
- package/dist/lib/auto-mode/secretary.js.map +1 -1
- package/dist/lib/models.js +2 -3
- package/dist/lib/models.js.map +1 -1
- package/dist/lib/pi-adapter/session.js +17 -13
- package/dist/lib/pi-adapter/session.js.map +1 -1
- package/dist/lib/symphony/pod-projection.js +526 -12
- package/dist/lib/symphony/pod-projection.js.map +1 -1
- package/dist/skills/symphony/SKILL.md +50 -0
- package/package.json +2 -2
- package/vendor/agent-runtime/dist/index.d.ts +0 -2
- package/vendor/agent-runtime/dist/index.js +0 -2
- package/vendor/agent-runtime/dist/reconciler.js +2 -2
- package/vendor/agent-runtime/dist/symphony.js +6 -5
- package/vendor/agent-runtime/package.json +1 -3
- package/dist/lib/pi-adapter/auth.js +0 -68
- package/dist/lib/pi-adapter/auth.js.map +0 -1
- package/dist/lib/pi-adapter/pod-tools.js +0 -140
- package/dist/lib/pi-adapter/pod-tools.js.map +0 -1
- package/dist/lib/resource-identity.js +0 -2
- package/dist/lib/resource-identity.js.map +0 -1
- package/vendor/agent-runtime/dist/pod-resource-identity.d.ts +0 -17
- package/vendor/agent-runtime/dist/pod-resource-identity.js +0 -54
- package/vendor/agent-runtime/dist/workspace.d.ts +0 -33
- package/vendor/agent-runtime/dist/workspace.js +0 -80
|
@@ -7,7 +7,7 @@ import { decideThreadControlEvent } from '../../../vendor/agent-runtime/dist/thr
|
|
|
7
7
|
import { createLinxPodSyncScope } from '../../../vendor/agent-runtime/dist/sync.js';
|
|
8
8
|
import { insertExactRecordOnce, resolvePodResourceTemplateValue, upsertExactRecord, } from '@undefineds.co/drizzle-solid';
|
|
9
9
|
import { getDefaultPodDataSession } from '../pod-data-session.js';
|
|
10
|
-
import { ContactClass, ContactType, chatRepository, agentResource, contactResource, deliveryResource, ideaResource, issueResource, messageResource, runResource, runStepResource, sessionResource, taskResource, threadRepository, } from '../models.js';
|
|
10
|
+
import { ContactClass, ContactType, EvidenceKind, chatRepository, agentResource, contactResource, deliveryResource, evidenceResource, ideaResource, issueResource, messageResource, reportResource, runResource, runStepResource, sessionResource, taskResource, threadRepository, } from '../models.js';
|
|
11
11
|
import { pathToWorkspaceUri } from '../pi-adapter/pod-mirror-mapping.js';
|
|
12
12
|
import { getSymphonyHome } from './archive.js';
|
|
13
13
|
const SYMPHONY_CHAT_ID = 'symphony';
|
|
@@ -16,6 +16,240 @@ const SYMPHONY_CONTACT_ID = 'symphony';
|
|
|
16
16
|
const SYMPHONY_POLICY_VERSION = 'linx-symphony-session/v1';
|
|
17
17
|
const SYMPHONY_WORKER_POD_ACCESS_POLICY_VERSION = 'linx-symphony-worker-pod-access/v1';
|
|
18
18
|
const SYMPHONY_ARCHIVE_PROVENANCE_VERSION = 'linx-symphony-archive/v1';
|
|
19
|
+
function ensureTrailingSlash(value) {
|
|
20
|
+
return value.endsWith('/') ? value : `${value}/`;
|
|
21
|
+
}
|
|
22
|
+
function podBaseUrlFromWebId(webId) {
|
|
23
|
+
const marker = '/profile/card#me';
|
|
24
|
+
if (webId.includes(marker)) {
|
|
25
|
+
return `${webId.slice(0, webId.indexOf(marker) + 1)}`;
|
|
26
|
+
}
|
|
27
|
+
const url = new URL(webId);
|
|
28
|
+
return `${url.origin}/`;
|
|
29
|
+
}
|
|
30
|
+
function podFileUrlFromWebId(webId, path) {
|
|
31
|
+
return new URL(path.replace(/^\/+/, ''), podBaseUrlFromWebId(webId)).toString();
|
|
32
|
+
}
|
|
33
|
+
function podFileUrl(podSession, path) {
|
|
34
|
+
return new URL(path.replace(/^\/+/, ''), ensureTrailingSlash(podSession.podUrl)).toString();
|
|
35
|
+
}
|
|
36
|
+
async function writePodFileToSession(session, file) {
|
|
37
|
+
const url = podFileUrl(session, file.path);
|
|
38
|
+
await ensurePodResourceContainers(session.fetch, url);
|
|
39
|
+
const response = await session.fetch(url, {
|
|
40
|
+
method: 'PUT',
|
|
41
|
+
headers: { 'Content-Type': file.contentType },
|
|
42
|
+
body: file.content.endsWith('\n') ? file.content : `${file.content}\n`,
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const details = await response.text().catch(() => '');
|
|
46
|
+
const suffix = details.trim() ? ` - ${details.trim().slice(0, 500)}` : '';
|
|
47
|
+
throw new Error(`Failed to write Symphony Pod file ${url}: ${response.status} ${response.statusText}${suffix}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function ensurePodResourceContainers(fetcher, resourceUrl) {
|
|
51
|
+
for (const containerUrl of containerUrlsForResource(resourceUrl)) {
|
|
52
|
+
const existing = await fetcher(containerUrl, { method: 'HEAD' }).catch(() => null);
|
|
53
|
+
if (existing?.ok)
|
|
54
|
+
continue;
|
|
55
|
+
if (existing && existing.status !== 404 && existing.status !== 405)
|
|
56
|
+
continue;
|
|
57
|
+
const response = await fetcher(containerUrl, {
|
|
58
|
+
method: 'PUT',
|
|
59
|
+
headers: {
|
|
60
|
+
Link: '<http://www.w3.org/ns/ldp#BasicContainer>; rel="type"',
|
|
61
|
+
'Content-Type': 'text/turtle; charset=utf-8',
|
|
62
|
+
},
|
|
63
|
+
body: '',
|
|
64
|
+
});
|
|
65
|
+
if (!response.ok && response.status !== 409) {
|
|
66
|
+
throw new Error(`Failed to ensure Symphony Pod container ${containerUrl}: ${response.status} ${response.statusText}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function containerUrlsForResource(resourceUrl) {
|
|
71
|
+
const url = new URL(resourceUrl);
|
|
72
|
+
const parts = url.pathname.split('/').filter(Boolean);
|
|
73
|
+
const containers = [];
|
|
74
|
+
let path = '/';
|
|
75
|
+
for (let index = 0; index < parts.length - 1; index += 1) {
|
|
76
|
+
path += `${parts[index]}/`;
|
|
77
|
+
containers.push(new URL(path, url.origin).toString());
|
|
78
|
+
}
|
|
79
|
+
return containers;
|
|
80
|
+
}
|
|
81
|
+
function datePathParts(input) {
|
|
82
|
+
const date = safeDate(input);
|
|
83
|
+
return {
|
|
84
|
+
yyyy: String(date.getUTCFullYear()),
|
|
85
|
+
MM: String(date.getUTCMonth() + 1).padStart(2, '0'),
|
|
86
|
+
dd: String(date.getUTCDate()).padStart(2, '0'),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function buildSymphonyIssueDocumentPath(issue) {
|
|
90
|
+
return `/.data/issues/${buildSymphonyIssueId(issue)}/issue.md`;
|
|
91
|
+
}
|
|
92
|
+
function buildSymphonyIdeaDocumentPath(idea) {
|
|
93
|
+
const { yyyy, MM, dd } = datePathParts(idea.createdAt);
|
|
94
|
+
return `/.data/ideas/${yyyy}/${MM}/${dd}/${getSymphonyArchiveKey(idea.uri)}/idea.md`;
|
|
95
|
+
}
|
|
96
|
+
function buildSymphonyReportDocumentPath(worker) {
|
|
97
|
+
const { yyyy, MM, dd } = datePathParts(worker.session.completedAt ?? worker.session.updatedAt);
|
|
98
|
+
return `/.data/reports/${yyyy}/${MM}/${dd}/${getSymphonyArchiveKey(worker.session.uri)}-report.md`;
|
|
99
|
+
}
|
|
100
|
+
function buildSymphonyEvidenceDocumentPath(worker, stage) {
|
|
101
|
+
const { yyyy, MM, dd } = datePathParts(worker.session.completedAt ?? worker.session.updatedAt);
|
|
102
|
+
return `/.data/evidence/${yyyy}/${MM}/${dd}/${getSymphonyArchiveKey(worker.session.uri)}-${stage}-evidence.md`;
|
|
103
|
+
}
|
|
104
|
+
function renderMarkdownList(items) {
|
|
105
|
+
const values = (items ?? []).map((item) => item.trim()).filter(Boolean);
|
|
106
|
+
return values.length > 0 ? values.map((item) => `- ${item}`).join('\n') : '- None recorded.';
|
|
107
|
+
}
|
|
108
|
+
function renderSymphonyIssueMarkdown(plan) {
|
|
109
|
+
const issue = plan.issue;
|
|
110
|
+
const sections = [
|
|
111
|
+
`# ${issue.title || buildSymphonyIssueId(issue)}`,
|
|
112
|
+
'',
|
|
113
|
+
'## Summary',
|
|
114
|
+
issue.description?.trim() || issue.title || 'No summary recorded.',
|
|
115
|
+
'',
|
|
116
|
+
'## Status',
|
|
117
|
+
`- Status: ${issue.status}`,
|
|
118
|
+
`- Priority: ${issue.priority}`,
|
|
119
|
+
`- Source: ${issue.source}`,
|
|
120
|
+
'',
|
|
121
|
+
'## Acceptance Criteria',
|
|
122
|
+
renderMarkdownList(plan.workers.flatMap((worker) => worker.taskRecord.acceptanceCriteria ?? [])),
|
|
123
|
+
'',
|
|
124
|
+
'## Tasks',
|
|
125
|
+
renderMarkdownList(plan.workers.map((worker) => `${worker.taskRecord.title}: ${worker.taskRecord.objective}`)),
|
|
126
|
+
'',
|
|
127
|
+
'## Source Context',
|
|
128
|
+
`- Chat: ${issue.chat ?? plan.session.chat ?? 'not recorded'}`,
|
|
129
|
+
`- Thread: ${issue.thread ?? plan.session.thread ?? 'not recorded'}`,
|
|
130
|
+
`- Messages: ${(issue.messages ?? []).join(', ') || 'not recorded'}`,
|
|
131
|
+
'',
|
|
132
|
+
'## Control Records',
|
|
133
|
+
`- Issue: ${issue.uri}`,
|
|
134
|
+
...plan.workers.flatMap((worker) => [
|
|
135
|
+
`- Task: ${worker.task}`,
|
|
136
|
+
`- Delivery: ${worker.delivery.uri}`,
|
|
137
|
+
`- Session: ${worker.session.uri}`,
|
|
138
|
+
]),
|
|
139
|
+
];
|
|
140
|
+
return sections.join('\n');
|
|
141
|
+
}
|
|
142
|
+
function renderSymphonyIdeaMarkdown(idea) {
|
|
143
|
+
return [
|
|
144
|
+
`# ${idea.summary || getSymphonyArchiveKey(idea.uri)}`,
|
|
145
|
+
'',
|
|
146
|
+
'## Input',
|
|
147
|
+
idea.input?.trim() || idea.summary || 'No input recorded.',
|
|
148
|
+
'',
|
|
149
|
+
'## Current Understanding',
|
|
150
|
+
idea.currentUnderstanding?.trim() || 'No current understanding recorded.',
|
|
151
|
+
'',
|
|
152
|
+
'## Open Questions',
|
|
153
|
+
renderMarkdownList(idea.openQuestions),
|
|
154
|
+
'',
|
|
155
|
+
'## Conflicts',
|
|
156
|
+
renderMarkdownList(idea.conflicts),
|
|
157
|
+
'',
|
|
158
|
+
'## Next Step',
|
|
159
|
+
idea.nextStep?.trim() || 'No next step recorded.',
|
|
160
|
+
'',
|
|
161
|
+
'## Source Context',
|
|
162
|
+
`- Status: ${idea.status}`,
|
|
163
|
+
`- Commitment: ${idea.commitment}`,
|
|
164
|
+
`- Chat: ${idea.chat ?? 'not recorded'}`,
|
|
165
|
+
`- Thread: ${idea.thread ?? 'not recorded'}`,
|
|
166
|
+
`- Messages: ${(idea.messages ?? []).join(', ') || 'not recorded'}`,
|
|
167
|
+
`- Idea: ${idea.uri}`,
|
|
168
|
+
].join('\n');
|
|
169
|
+
}
|
|
170
|
+
function renderSymphonyReportMarkdown(plan, worker, stage) {
|
|
171
|
+
const status = worker.session.status === 'failed' || stage === 'failed' ? 'failed' : 'completed';
|
|
172
|
+
const summary = status === 'completed'
|
|
173
|
+
? `${worker.taskRecord.title} completed.`
|
|
174
|
+
: `${worker.taskRecord.title} failed: ${worker.session.error ?? worker.delivery.error ?? 'worker did not complete successfully.'}`;
|
|
175
|
+
return [
|
|
176
|
+
`# ${worker.taskRecord.title} — ${status}`,
|
|
177
|
+
'',
|
|
178
|
+
'## Summary',
|
|
179
|
+
summary,
|
|
180
|
+
'',
|
|
181
|
+
'## Outcome',
|
|
182
|
+
`- Status: ${status}`,
|
|
183
|
+
`- Backend: ${worker.session.backend}`,
|
|
184
|
+
`- Agent: ${worker.session.target.agent ?? worker.delivery.targetAgent}`,
|
|
185
|
+
`- Auto mode session: ${worker.session.autoModeSessionId ?? 'not recorded'}`,
|
|
186
|
+
`- Exit code: ${worker.session.exitCode ?? 'not recorded'}`,
|
|
187
|
+
'',
|
|
188
|
+
'## Task',
|
|
189
|
+
worker.taskRecord.objective,
|
|
190
|
+
'',
|
|
191
|
+
'## Acceptance Criteria',
|
|
192
|
+
renderMarkdownList(worker.taskRecord.acceptanceCriteria),
|
|
193
|
+
'',
|
|
194
|
+
'## Linked Control Records',
|
|
195
|
+
`- Issue: ${buildSymphonyIssueId(plan.issue)}`,
|
|
196
|
+
`- Task: ${worker.task}`,
|
|
197
|
+
`- Delivery: ${worker.delivery.uri}`,
|
|
198
|
+
`- Session: ${worker.session.uri}`,
|
|
199
|
+
`- Run status: ${worker.session.status}`,
|
|
200
|
+
'',
|
|
201
|
+
'## Post-Run Reconciliation',
|
|
202
|
+
'- Secretary must review this report and linked Evidence before closing the task.',
|
|
203
|
+
'- Classify any follow-up as same_issue_task, new_issue, idea, evidence_only, or ask_user.',
|
|
204
|
+
'',
|
|
205
|
+
...(worker.session.error || worker.delivery.error || worker.taskRecord.error ? [
|
|
206
|
+
'## Error',
|
|
207
|
+
worker.session.error ?? worker.delivery.error ?? worker.taskRecord.error ?? '',
|
|
208
|
+
'',
|
|
209
|
+
] : []),
|
|
210
|
+
].join('\n');
|
|
211
|
+
}
|
|
212
|
+
function renderSymphonyEvidenceMarkdown(plan, webId, worker, stage) {
|
|
213
|
+
const status = worker.session.status === 'failed' || stage === 'failed' ? 'failed' : 'completed';
|
|
214
|
+
const summary = status === 'completed'
|
|
215
|
+
? `${worker.taskRecord.title} completed with runtime status ${worker.session.status}.`
|
|
216
|
+
: `${worker.taskRecord.title} failed: ${worker.session.error ?? worker.delivery.error ?? worker.taskRecord.error ?? 'worker did not complete successfully.'}`;
|
|
217
|
+
const run = buildSymphonyRunIri(webId, worker);
|
|
218
|
+
const runStep = buildSymphonyRunStepIri(webId, worker, stage);
|
|
219
|
+
return [
|
|
220
|
+
`# ${worker.taskRecord.title} — ${status} evidence`,
|
|
221
|
+
'',
|
|
222
|
+
'## Summary',
|
|
223
|
+
summary,
|
|
224
|
+
'',
|
|
225
|
+
'## Runtime Facts',
|
|
226
|
+
`- Backend: ${worker.session.backend}`,
|
|
227
|
+
`- Agent: ${worker.session.target.agent ?? worker.delivery.targetAgent}`,
|
|
228
|
+
`- Model: ${worker.session.model ?? 'not recorded'}`,
|
|
229
|
+
`- Auto mode session: ${worker.session.autoModeSessionId ?? 'not recorded'}`,
|
|
230
|
+
`- Exit code: ${worker.session.exitCode ?? 'not recorded'}`,
|
|
231
|
+
`- Run status: ${worker.session.status}`,
|
|
232
|
+
'',
|
|
233
|
+
'## Acceptance Criteria',
|
|
234
|
+
renderMarkdownList(worker.taskRecord.acceptanceCriteria),
|
|
235
|
+
'',
|
|
236
|
+
'## Linked Control Records',
|
|
237
|
+
`- Issue: ${buildSymphonyIssueIri(webId, plan.issue)}`,
|
|
238
|
+
`- Task: ${buildSymphonyTaskIri(webId, worker.task)}`,
|
|
239
|
+
`- Delivery: ${buildSymphonyDeliveryIri(webId, worker)}`,
|
|
240
|
+
`- Run: ${run}`,
|
|
241
|
+
`- Source RunStep: ${runStep}`,
|
|
242
|
+
`- Worker Thread: ${selectWorkerThreadIri(plan, webId, worker)}`,
|
|
243
|
+
'',
|
|
244
|
+
...(worker.session.error || worker.delivery.error || worker.taskRecord.error ? [
|
|
245
|
+
'## Error',
|
|
246
|
+
worker.session.error ?? worker.delivery.error ?? worker.taskRecord.error ?? '',
|
|
247
|
+
'',
|
|
248
|
+
] : []),
|
|
249
|
+
'## Secretary Follow-Up Review',
|
|
250
|
+
'This Evidence is append-only proof/finding material. Secretary must use it with the Report and RunSteps to decide acceptance and whether follow-up work should be captured.',
|
|
251
|
+
].join('\n');
|
|
252
|
+
}
|
|
19
253
|
function normalizeSymphonyRunPlan(plan) {
|
|
20
254
|
const workers = Array.isArray(plan.workers) && plan.workers.length > 0
|
|
21
255
|
? plan.workers
|
|
@@ -119,12 +353,15 @@ async function createDefaultRuntime() {
|
|
|
119
353
|
issueResource: models.issueResource,
|
|
120
354
|
taskResource: models.taskResource,
|
|
121
355
|
deliveryResource: models.deliveryResource,
|
|
356
|
+
evidenceResource: models.evidenceResource,
|
|
357
|
+
reportResource: models.reportResource,
|
|
122
358
|
runResource: models.runResource,
|
|
123
359
|
runStepResource: models.runStepResource,
|
|
124
360
|
agentResource: models.agentResource,
|
|
125
|
-
contactResource: models.
|
|
361
|
+
contactResource: models.contactTable,
|
|
126
362
|
auditResource: models.auditResource,
|
|
127
363
|
inboxNotificationResource: models.inboxNotificationResource,
|
|
364
|
+
writePodFile: writePodFileToSession,
|
|
128
365
|
};
|
|
129
366
|
}
|
|
130
367
|
function selectTargetChatIri(value, webId, plan) {
|
|
@@ -211,6 +448,19 @@ function buildSymphonyReportDeliveryIri(webId, worker) {
|
|
|
211
448
|
createdAt: safeDate(worker.session.completedAt ?? worker.session.updatedAt),
|
|
212
449
|
});
|
|
213
450
|
}
|
|
451
|
+
function buildSymphonyReportIri(webId, worker) {
|
|
452
|
+
return reportResource.buildIri(webId, {
|
|
453
|
+
id: `${getSymphonyArchiveKey(worker.session.uri)}-report`,
|
|
454
|
+
task: buildSymphonyTaskIri(webId, worker.task),
|
|
455
|
+
createdAt: safeDate(worker.session.completedAt ?? worker.session.updatedAt),
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
function buildSymphonyEvidenceIri(webId, worker, stage) {
|
|
459
|
+
return evidenceResource.buildIri(webId, {
|
|
460
|
+
id: `${getSymphonyArchiveKey(worker.session.uri)}-${stage}`,
|
|
461
|
+
createdAt: safeDate(worker.session.completedAt ?? worker.session.updatedAt),
|
|
462
|
+
});
|
|
463
|
+
}
|
|
214
464
|
function buildSymphonyRunIri(webId, worker) {
|
|
215
465
|
return runResource.buildIri(webId, {
|
|
216
466
|
id: getSymphonyArchiveKey(worker.session.uri),
|
|
@@ -808,8 +1058,11 @@ function buildSymphonyIssueRow(plan, webId) {
|
|
|
808
1058
|
const updatedAt = safeDate(plan.issue.updatedAt);
|
|
809
1059
|
return {
|
|
810
1060
|
id: buildSymphonyIssueId(plan.issue),
|
|
1061
|
+
// File-primary: title remains a compact index label for existing Issue schemas.
|
|
1062
|
+
// The full problem statement and acceptance narrative live in issue.md.
|
|
811
1063
|
title: plan.issue.title,
|
|
812
|
-
|
|
1064
|
+
document: podFileUrlFromWebId(webId, buildSymphonyIssueDocumentPath(plan.issue)),
|
|
1065
|
+
description: undefined,
|
|
813
1066
|
status: plan.issue.status,
|
|
814
1067
|
priority: plan.issue.priority,
|
|
815
1068
|
labels: ['symphony'],
|
|
@@ -830,15 +1083,17 @@ function buildSymphonyIdeaRow(idea, webId) {
|
|
|
830
1083
|
return {
|
|
831
1084
|
id: getSymphonyArchiveKey(idea.uri),
|
|
832
1085
|
summary: idea.summary,
|
|
833
|
-
|
|
1086
|
+
document: podFileUrlFromWebId(webId, buildSymphonyIdeaDocumentPath(idea)),
|
|
1087
|
+
// File-primary: the source text lives in idea.md; TTL keeps only routing/index facts.
|
|
1088
|
+
input: undefined,
|
|
834
1089
|
status: idea.status,
|
|
835
1090
|
commitment: idea.commitment,
|
|
836
1091
|
affectedArea: idea.affectedArea,
|
|
837
|
-
currentUnderstanding:
|
|
838
|
-
openQuestions:
|
|
1092
|
+
currentUnderstanding: undefined,
|
|
1093
|
+
openQuestions: undefined,
|
|
839
1094
|
related: idea.relatedRecords,
|
|
840
|
-
conflicts:
|
|
841
|
-
nextStep:
|
|
1095
|
+
conflicts: undefined,
|
|
1096
|
+
nextStep: undefined,
|
|
842
1097
|
promotedTo: idea.promotedTo,
|
|
843
1098
|
chat: idea.chat,
|
|
844
1099
|
thread: idea.thread,
|
|
@@ -846,6 +1101,8 @@ function buildSymphonyIdeaRow(idea, webId) {
|
|
|
846
1101
|
createdBy: webId,
|
|
847
1102
|
metadata: {
|
|
848
1103
|
surface: 'symphony',
|
|
1104
|
+
filePrimary: true,
|
|
1105
|
+
documentPath: buildSymphonyIdeaDocumentPath(idea),
|
|
849
1106
|
...buildSymphonyArchiveMetadata({ idea: idea.uri }),
|
|
850
1107
|
},
|
|
851
1108
|
createdAt,
|
|
@@ -965,6 +1222,138 @@ function buildSymphonyDeliveryRow(plan, webId, worker) {
|
|
|
965
1222
|
updatedAt,
|
|
966
1223
|
};
|
|
967
1224
|
}
|
|
1225
|
+
function buildSymphonyReportRow(plan, webId, worker, stage) {
|
|
1226
|
+
const completedAt = safeDate(worker.session.completedAt ?? worker.session.updatedAt);
|
|
1227
|
+
const workerAgent = agentResource.buildIri(webId, {
|
|
1228
|
+
id: buildWorkerAgentId(worker.session.backend, worker.session.target.agent),
|
|
1229
|
+
});
|
|
1230
|
+
const run = buildSymphonyRunIri(webId, worker);
|
|
1231
|
+
const task = buildSymphonyTaskIri(webId, worker.task);
|
|
1232
|
+
const status = worker.session.status === 'failed' || stage === 'failed' ? 'failed' : 'completed';
|
|
1233
|
+
const summary = status === 'completed'
|
|
1234
|
+
? `${worker.taskRecord.title} completed.`
|
|
1235
|
+
: `${worker.taskRecord.title} failed: ${worker.session.error ?? worker.delivery.error ?? 'worker did not complete successfully.'}`;
|
|
1236
|
+
const evidence = buildSymphonyEvidenceIri(webId, worker, stage);
|
|
1237
|
+
return {
|
|
1238
|
+
id: reportResource.buildId({
|
|
1239
|
+
id: `${getSymphonyArchiveKey(worker.session.uri)}-report`,
|
|
1240
|
+
task,
|
|
1241
|
+
createdAt: completedAt,
|
|
1242
|
+
}),
|
|
1243
|
+
reportKind: 'handoff',
|
|
1244
|
+
status: 'published',
|
|
1245
|
+
outcome: status === 'completed' ? 'accepted' : 'blocked',
|
|
1246
|
+
about: run,
|
|
1247
|
+
issue: buildSymphonyIssueIri(webId, plan.issue),
|
|
1248
|
+
task,
|
|
1249
|
+
delivery: buildSymphonyDeliveryIri(webId, worker),
|
|
1250
|
+
run,
|
|
1251
|
+
thread: selectWorkerThreadIri(plan, webId, worker),
|
|
1252
|
+
evidence: [
|
|
1253
|
+
evidence,
|
|
1254
|
+
],
|
|
1255
|
+
summary,
|
|
1256
|
+
actor: workerAgent,
|
|
1257
|
+
source: podFileUrlFromWebId(webId, buildSymphonyReportDocumentPath(worker)),
|
|
1258
|
+
metricFacts: {
|
|
1259
|
+
backend: worker.session.backend,
|
|
1260
|
+
agent: worker.session.target.agent,
|
|
1261
|
+
autoModeSessionId: worker.session.autoModeSessionId,
|
|
1262
|
+
exitCode: worker.session.exitCode,
|
|
1263
|
+
},
|
|
1264
|
+
metadata: {
|
|
1265
|
+
surface: 'symphony',
|
|
1266
|
+
filePrimary: true,
|
|
1267
|
+
reportFile: buildSymphonyReportDocumentPath(worker),
|
|
1268
|
+
reportDelivery: buildSymphonyReportDeliveryIri(webId, worker),
|
|
1269
|
+
postRunReconciliation: buildPostRunReconciliationMetadata(plan, webId, worker, stage),
|
|
1270
|
+
...buildSymphonyArchiveMetadata({
|
|
1271
|
+
issue: plan.issue.uri,
|
|
1272
|
+
task: worker.task,
|
|
1273
|
+
delivery: worker.delivery.uri,
|
|
1274
|
+
session: worker.session.uri,
|
|
1275
|
+
}),
|
|
1276
|
+
},
|
|
1277
|
+
createdAt: completedAt,
|
|
1278
|
+
publishedAt: completedAt,
|
|
1279
|
+
updatedAt: completedAt,
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
function buildSymphonyEvidenceRow(plan, webId, worker, stage) {
|
|
1283
|
+
const createdAt = safeDate(worker.session.completedAt ?? worker.session.updatedAt);
|
|
1284
|
+
const status = worker.session.status === 'failed' || stage === 'failed' ? 'failed' : 'completed';
|
|
1285
|
+
const run = buildSymphonyRunIri(webId, worker);
|
|
1286
|
+
const task = buildSymphonyTaskIri(webId, worker.task);
|
|
1287
|
+
const delivery = buildSymphonyDeliveryIri(webId, worker);
|
|
1288
|
+
const runStep = buildSymphonyRunStepIri(webId, worker, stage);
|
|
1289
|
+
const workerAgent = agentResource.buildIri(webId, {
|
|
1290
|
+
id: buildWorkerAgentId(worker.session.backend, worker.session.target.agent),
|
|
1291
|
+
});
|
|
1292
|
+
return {
|
|
1293
|
+
id: evidenceResource.buildId({
|
|
1294
|
+
id: `${getSymphonyArchiveKey(worker.session.uri)}-${stage}`,
|
|
1295
|
+
createdAt,
|
|
1296
|
+
}),
|
|
1297
|
+
evidenceKind: EvidenceKind.RUNTIME_LOG,
|
|
1298
|
+
about: run,
|
|
1299
|
+
issue: buildSymphonyIssueIri(webId, plan.issue),
|
|
1300
|
+
task,
|
|
1301
|
+
delivery,
|
|
1302
|
+
run,
|
|
1303
|
+
thread: selectWorkerThreadIri(plan, webId, worker),
|
|
1304
|
+
summary: status === 'completed'
|
|
1305
|
+
? `${worker.taskRecord.title} completed with runtime status ${worker.session.status}.`
|
|
1306
|
+
: `${worker.taskRecord.title} failed: ${worker.session.error ?? worker.delivery.error ?? worker.taskRecord.error ?? 'worker did not complete successfully.'}`,
|
|
1307
|
+
source: podFileUrlFromWebId(webId, buildSymphonyEvidenceDocumentPath(worker, stage)),
|
|
1308
|
+
actor: workerAgent,
|
|
1309
|
+
outcome: status,
|
|
1310
|
+
metadata: {
|
|
1311
|
+
surface: 'symphony',
|
|
1312
|
+
filePrimary: true,
|
|
1313
|
+
evidenceFile: buildSymphonyEvidenceDocumentPath(worker, stage),
|
|
1314
|
+
sourceRunStep: runStep,
|
|
1315
|
+
report: buildSymphonyReportIri(webId, worker),
|
|
1316
|
+
reportDelivery: buildSymphonyReportDeliveryIri(webId, worker),
|
|
1317
|
+
postRunReconciliation: buildPostRunReconciliationMetadata(plan, webId, worker, stage),
|
|
1318
|
+
runtime: {
|
|
1319
|
+
backend: worker.session.backend,
|
|
1320
|
+
model: worker.session.model,
|
|
1321
|
+
autoModeSessionId: worker.session.autoModeSessionId,
|
|
1322
|
+
exitCode: worker.session.exitCode,
|
|
1323
|
+
status: worker.session.status,
|
|
1324
|
+
},
|
|
1325
|
+
...buildSymphonyArchiveMetadata({
|
|
1326
|
+
issue: plan.issue.uri,
|
|
1327
|
+
task: worker.task,
|
|
1328
|
+
delivery: worker.delivery.uri,
|
|
1329
|
+
session: worker.session.uri,
|
|
1330
|
+
}),
|
|
1331
|
+
},
|
|
1332
|
+
createdAt,
|
|
1333
|
+
};
|
|
1334
|
+
}
|
|
1335
|
+
function buildPostRunReconciliationMetadata(plan, webId, worker, stage) {
|
|
1336
|
+
return {
|
|
1337
|
+
required: true,
|
|
1338
|
+
status: 'pending_secretary_review',
|
|
1339
|
+
owner: agentResource.buildIri(webId, { id: SYMPHONY_SECRETARY_AGENT_ID }),
|
|
1340
|
+
sourceIssue: buildSymphonyIssueIri(webId, plan.issue),
|
|
1341
|
+
sourceTask: buildSymphonyTaskIri(webId, worker.task),
|
|
1342
|
+
sourceDelivery: buildSymphonyDeliveryIri(webId, worker),
|
|
1343
|
+
sourceRun: buildSymphonyRunIri(webId, worker),
|
|
1344
|
+
sourceRunStep: buildSymphonyRunStepIri(webId, worker, stage),
|
|
1345
|
+
sourceEvidence: buildSymphonyEvidenceIri(webId, worker, stage),
|
|
1346
|
+
sourceReport: buildSymphonyReportIri(webId, worker),
|
|
1347
|
+
classifications: [
|
|
1348
|
+
'same_issue_task',
|
|
1349
|
+
'new_issue',
|
|
1350
|
+
'idea',
|
|
1351
|
+
'evidence_only',
|
|
1352
|
+
'ask_user',
|
|
1353
|
+
],
|
|
1354
|
+
rule: 'Secretary must reconcile acceptance and follow-up before task closure.',
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
968
1357
|
function buildSymphonyReportDeliveryRow(plan, webId, worker, stage) {
|
|
969
1358
|
const completedAt = safeDate(worker.session.completedAt ?? worker.session.updatedAt);
|
|
970
1359
|
const workerAgent = agentResource.buildIri(webId, {
|
|
@@ -972,12 +1361,15 @@ function buildSymphonyReportDeliveryRow(plan, webId, worker, stage) {
|
|
|
972
1361
|
});
|
|
973
1362
|
const secretaryAgent = agentResource.buildIri(webId, { id: SYMPHONY_SECRETARY_AGENT_ID });
|
|
974
1363
|
const run = buildSymphonyRunIri(webId, worker);
|
|
1364
|
+
const report = buildSymphonyReportIri(webId, worker);
|
|
975
1365
|
const task = buildSymphonyTaskIri(webId, worker.task);
|
|
976
1366
|
const originalDelivery = buildSymphonyDeliveryIri(webId, worker);
|
|
977
1367
|
const status = worker.session.status === 'failed' || stage === 'failed' ? 'failed' : 'completed';
|
|
978
1368
|
const summary = status === 'completed'
|
|
979
1369
|
? `${worker.taskRecord.title} completed.`
|
|
980
1370
|
: `${worker.taskRecord.title} failed: ${worker.session.error ?? worker.delivery.error ?? 'worker did not complete successfully.'}`;
|
|
1371
|
+
const evidence = buildSymphonyEvidenceIri(webId, worker, stage);
|
|
1372
|
+
const sourceRunStep = buildSymphonyRunStepIri(webId, worker, stage);
|
|
981
1373
|
return {
|
|
982
1374
|
id: deliveryResource.buildId({
|
|
983
1375
|
id: `${getSymphonyArchiveKey(worker.session.uri)}-report`,
|
|
@@ -994,7 +1386,7 @@ function buildSymphonyReportDeliveryRow(plan, webId, worker, stage) {
|
|
|
994
1386
|
targetThread: selectTargetThreadIri(plan.issue.thread ?? worker.session.target?.thread, webId, plan),
|
|
995
1387
|
targetSession: buildSymphonyControlSessionUri(webId, plan),
|
|
996
1388
|
actor: workerAgent,
|
|
997
|
-
object:
|
|
1389
|
+
object: report,
|
|
998
1390
|
objective: summary,
|
|
999
1391
|
payload: {
|
|
1000
1392
|
kind: 'symphony_report',
|
|
@@ -1003,6 +1395,7 @@ function buildSymphonyReportDeliveryRow(plan, webId, worker, stage) {
|
|
|
1003
1395
|
issue: buildSymphonyIssueIri(webId, plan.issue),
|
|
1004
1396
|
task,
|
|
1005
1397
|
delivery: originalDelivery,
|
|
1398
|
+
report,
|
|
1006
1399
|
reportDelivery: buildSymphonyReportDeliveryIri(webId, worker),
|
|
1007
1400
|
session: buildSymphonyControlSessionUri(webId, plan),
|
|
1008
1401
|
run,
|
|
@@ -1011,9 +1404,13 @@ function buildSymphonyReportDeliveryRow(plan, webId, worker, stage) {
|
|
|
1011
1404
|
autoModeSessionId: worker.session.autoModeSessionId,
|
|
1012
1405
|
exitCode: worker.session.exitCode,
|
|
1013
1406
|
error: worker.session.error ?? worker.delivery.error ?? worker.taskRecord.error,
|
|
1407
|
+
reportFile: buildSymphonyReportDocumentPath(worker),
|
|
1408
|
+
evidenceFile: buildSymphonyEvidenceDocumentPath(worker, stage),
|
|
1409
|
+
postRunReconciliation: buildPostRunReconciliationMetadata(plan, webId, worker, stage),
|
|
1014
1410
|
evidence: {
|
|
1015
1411
|
statusMessage: buildSymphonyMessageUri(webId, plan, buildStatusMessageRow(plan, webId, stage)),
|
|
1016
|
-
|
|
1412
|
+
sourceRunStep,
|
|
1413
|
+
evidence,
|
|
1017
1414
|
},
|
|
1018
1415
|
},
|
|
1019
1416
|
projection: {
|
|
@@ -1030,6 +1427,11 @@ function buildSymphonyReportDeliveryRow(plan, webId, worker, stage) {
|
|
|
1030
1427
|
session: worker.session.uri,
|
|
1031
1428
|
}),
|
|
1032
1429
|
reportKind: 'worker-completion',
|
|
1430
|
+
filePrimary: true,
|
|
1431
|
+
reportFile: buildSymphonyReportDocumentPath(worker),
|
|
1432
|
+
evidence,
|
|
1433
|
+
evidenceFile: buildSymphonyEvidenceDocumentPath(worker, stage),
|
|
1434
|
+
postRunReconciliation: buildPostRunReconciliationMetadata(plan, webId, worker, stage),
|
|
1033
1435
|
},
|
|
1034
1436
|
error: status === 'failed' ? worker.session.error ?? worker.delivery.error ?? worker.taskRecord.error : undefined,
|
|
1035
1437
|
createdAt: completedAt,
|
|
@@ -1371,6 +1773,7 @@ async function upsertIssue(db, runtime, row) {
|
|
|
1371
1773
|
await upsertExactRecord(db, runtime.issueResource, { id: row.id }, row, {
|
|
1372
1774
|
title: row.title,
|
|
1373
1775
|
description: row.description,
|
|
1776
|
+
document: row.document,
|
|
1374
1777
|
status: row.status,
|
|
1375
1778
|
priority: row.priority,
|
|
1376
1779
|
labels: row.labels,
|
|
@@ -1385,6 +1788,7 @@ async function upsertIssue(db, runtime, row) {
|
|
|
1385
1788
|
async function upsertIdea(db, runtime, row) {
|
|
1386
1789
|
await upsertExactRecord(db, runtime.ideaResource, { id: row.id }, row, {
|
|
1387
1790
|
summary: row.summary,
|
|
1791
|
+
document: row.document,
|
|
1388
1792
|
input: row.input,
|
|
1389
1793
|
status: row.status,
|
|
1390
1794
|
commitment: row.commitment,
|
|
@@ -1419,6 +1823,51 @@ async function upsertTask(db, runtime, row) {
|
|
|
1419
1823
|
updatedAt: row.updatedAt,
|
|
1420
1824
|
});
|
|
1421
1825
|
}
|
|
1826
|
+
async function upsertReport(db, runtime, row) {
|
|
1827
|
+
await upsertExactRecord(db, runtime.reportResource, {
|
|
1828
|
+
id: row.id,
|
|
1829
|
+
task: row.task,
|
|
1830
|
+
createdAt: row.createdAt,
|
|
1831
|
+
}, row, {
|
|
1832
|
+
reportKind: row.reportKind,
|
|
1833
|
+
status: row.status,
|
|
1834
|
+
outcome: row.outcome,
|
|
1835
|
+
about: row.about,
|
|
1836
|
+
issue: row.issue,
|
|
1837
|
+
task: row.task,
|
|
1838
|
+
delivery: row.delivery,
|
|
1839
|
+
run: row.run,
|
|
1840
|
+
thread: row.thread,
|
|
1841
|
+
evidence: row.evidence,
|
|
1842
|
+
summary: row.summary,
|
|
1843
|
+
reviewer: row.reviewer,
|
|
1844
|
+
actor: row.actor,
|
|
1845
|
+
source: row.source,
|
|
1846
|
+
metricFacts: row.metricFacts,
|
|
1847
|
+
metadata: row.metadata,
|
|
1848
|
+
publishedAt: row.publishedAt,
|
|
1849
|
+
updatedAt: row.updatedAt,
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1852
|
+
async function upsertEvidence(db, runtime, row) {
|
|
1853
|
+
await upsertExactRecord(db, runtime.evidenceResource, {
|
|
1854
|
+
id: row.id,
|
|
1855
|
+
createdAt: row.createdAt,
|
|
1856
|
+
}, row, {
|
|
1857
|
+
evidenceKind: row.evidenceKind,
|
|
1858
|
+
about: row.about,
|
|
1859
|
+
issue: row.issue,
|
|
1860
|
+
task: row.task,
|
|
1861
|
+
delivery: row.delivery,
|
|
1862
|
+
run: row.run,
|
|
1863
|
+
thread: row.thread,
|
|
1864
|
+
summary: row.summary,
|
|
1865
|
+
source: row.source,
|
|
1866
|
+
actor: row.actor,
|
|
1867
|
+
outcome: row.outcome,
|
|
1868
|
+
metadata: row.metadata,
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1422
1871
|
async function upsertDelivery(db, runtime, row) {
|
|
1423
1872
|
await upsertExactRecord(db, runtime.deliveryResource, { id: row.id }, row, {
|
|
1424
1873
|
kind: row.kind,
|
|
@@ -1538,6 +1987,9 @@ function collectSymphonyProjectionResources(webId, plan, stages) {
|
|
|
1538
1987
|
add('runStep', buildSymphonyRunStepIri(webId, worker, stage));
|
|
1539
1988
|
}
|
|
1540
1989
|
if (worker.session.status === 'completed' || worker.session.status === 'failed') {
|
|
1990
|
+
const terminalStage = worker.session.status === 'failed' ? 'failed' : 'completed';
|
|
1991
|
+
add('evidence', buildSymphonyEvidenceIri(webId, worker, terminalStage));
|
|
1992
|
+
add('report', buildSymphonyReportIri(webId, worker));
|
|
1541
1993
|
add('delivery', buildSymphonyReportDeliveryIri(webId, worker));
|
|
1542
1994
|
}
|
|
1543
1995
|
}
|
|
@@ -1612,6 +2064,7 @@ export async function persistSymphonyControlStateToPod(plan, options = {}) {
|
|
|
1612
2064
|
stages,
|
|
1613
2065
|
latestMessage,
|
|
1614
2066
|
shouldUpsertChat: !normalizedPlan.session.target?.chat,
|
|
2067
|
+
podSession,
|
|
1615
2068
|
}),
|
|
1616
2069
|
});
|
|
1617
2070
|
return {
|
|
@@ -1685,6 +2138,10 @@ function resolveProjectionResourceModel(runtime, kind) {
|
|
|
1685
2138
|
return runtime.taskResource;
|
|
1686
2139
|
if (kind === 'delivery')
|
|
1687
2140
|
return runtime.deliveryResource;
|
|
2141
|
+
if (kind === 'evidence')
|
|
2142
|
+
return runtime.evidenceResource;
|
|
2143
|
+
if (kind === 'report')
|
|
2144
|
+
return runtime.reportResource;
|
|
1688
2145
|
if (kind === 'run')
|
|
1689
2146
|
return runtime.runResource;
|
|
1690
2147
|
if (kind === 'runStep')
|
|
@@ -1822,7 +2279,18 @@ export async function persistSymphonyIdeaToPod(idea, options = {}) {
|
|
|
1822
2279
|
},
|
|
1823
2280
|
},
|
|
1824
2281
|
{
|
|
1825
|
-
id: 'symphony.idea.
|
|
2282
|
+
id: 'symphony.idea.write-file-primary-document',
|
|
2283
|
+
kind: 'upsert',
|
|
2284
|
+
apply: async () => {
|
|
2285
|
+
await runtime.writePodFile?.(podSession, {
|
|
2286
|
+
path: buildSymphonyIdeaDocumentPath(idea),
|
|
2287
|
+
content: renderSymphonyIdeaMarkdown(idea),
|
|
2288
|
+
contentType: 'text/markdown; charset=utf-8',
|
|
2289
|
+
});
|
|
2290
|
+
},
|
|
2291
|
+
},
|
|
2292
|
+
{
|
|
2293
|
+
id: 'symphony.idea.upsert-meta',
|
|
1826
2294
|
kind: 'upsert',
|
|
1827
2295
|
apply: () => upsertIdea(db, runtime, buildSymphonyIdeaRow(idea, podSession.webId)),
|
|
1828
2296
|
},
|
|
@@ -2102,6 +2570,8 @@ function buildSymphonyProjectionOperations(input) {
|
|
|
2102
2570
|
input.runtime.issueResource,
|
|
2103
2571
|
input.runtime.taskResource,
|
|
2104
2572
|
input.runtime.deliveryResource,
|
|
2573
|
+
input.runtime.evidenceResource,
|
|
2574
|
+
input.runtime.reportResource,
|
|
2105
2575
|
input.runtime.runResource,
|
|
2106
2576
|
input.runtime.runStepResource,
|
|
2107
2577
|
input.runtime.agentResource,
|
|
@@ -2112,7 +2582,18 @@ function buildSymphonyProjectionOperations(input) {
|
|
|
2112
2582
|
},
|
|
2113
2583
|
},
|
|
2114
2584
|
{
|
|
2115
|
-
id: 'symphony.
|
|
2585
|
+
id: 'symphony.write-file-primary-documents',
|
|
2586
|
+
kind: 'upsert',
|
|
2587
|
+
apply: async () => {
|
|
2588
|
+
await input.runtime.writePodFile?.(input.podSession, {
|
|
2589
|
+
path: buildSymphonyIssueDocumentPath(input.plan.issue),
|
|
2590
|
+
content: renderSymphonyIssueMarkdown(input.plan),
|
|
2591
|
+
contentType: 'text/markdown; charset=utf-8',
|
|
2592
|
+
});
|
|
2593
|
+
},
|
|
2594
|
+
},
|
|
2595
|
+
{
|
|
2596
|
+
id: 'symphony.upsert-issue-meta',
|
|
2116
2597
|
kind: 'upsert',
|
|
2117
2598
|
apply: () => upsertIssue(input.db, input.runtime, buildSymphonyIssueRow(input.plan, input.webId)),
|
|
2118
2599
|
},
|
|
@@ -2185,6 +2666,38 @@ function buildSymphonyReportOperations(input) {
|
|
|
2185
2666
|
}
|
|
2186
2667
|
const terminalStage = input.stage;
|
|
2187
2668
|
return input.plan.workers.flatMap((worker, index) => [
|
|
2669
|
+
{
|
|
2670
|
+
id: `symphony.write-evidence-file:${index + 1}`,
|
|
2671
|
+
kind: 'upsert',
|
|
2672
|
+
apply: async () => {
|
|
2673
|
+
await input.runtime.writePodFile?.(input.podSession, {
|
|
2674
|
+
path: buildSymphonyEvidenceDocumentPath(worker, terminalStage),
|
|
2675
|
+
content: renderSymphonyEvidenceMarkdown(input.plan, input.webId, worker, terminalStage),
|
|
2676
|
+
contentType: 'text/markdown; charset=utf-8',
|
|
2677
|
+
});
|
|
2678
|
+
},
|
|
2679
|
+
},
|
|
2680
|
+
{
|
|
2681
|
+
id: `symphony.upsert-evidence:${index + 1}`,
|
|
2682
|
+
kind: 'upsert',
|
|
2683
|
+
apply: () => upsertEvidence(input.db, input.runtime, buildSymphonyEvidenceRow(input.plan, input.webId, worker, terminalStage)),
|
|
2684
|
+
},
|
|
2685
|
+
{
|
|
2686
|
+
id: `symphony.write-report-file:${index + 1}`,
|
|
2687
|
+
kind: 'upsert',
|
|
2688
|
+
apply: async () => {
|
|
2689
|
+
await input.runtime.writePodFile?.(input.podSession, {
|
|
2690
|
+
path: buildSymphonyReportDocumentPath(worker),
|
|
2691
|
+
content: renderSymphonyReportMarkdown(input.plan, worker, terminalStage),
|
|
2692
|
+
contentType: 'text/markdown; charset=utf-8',
|
|
2693
|
+
});
|
|
2694
|
+
},
|
|
2695
|
+
},
|
|
2696
|
+
{
|
|
2697
|
+
id: `symphony.upsert-report:${index + 1}`,
|
|
2698
|
+
kind: 'upsert',
|
|
2699
|
+
apply: () => upsertReport(input.db, input.runtime, buildSymphonyReportRow(input.plan, input.webId, worker, terminalStage)),
|
|
2700
|
+
},
|
|
2188
2701
|
{
|
|
2189
2702
|
id: `symphony.upsert-report-delivery:${index + 1}`,
|
|
2190
2703
|
kind: 'upsert',
|
|
@@ -2218,6 +2731,7 @@ export const __symphonyPodProjectionInternal = {
|
|
|
2218
2731
|
buildSymphonyIdeaRow,
|
|
2219
2732
|
buildSymphonyTaskRow,
|
|
2220
2733
|
buildSymphonyDeliveryRow,
|
|
2734
|
+
buildSymphonyEvidenceRow,
|
|
2221
2735
|
buildSymphonyReportDeliveryRow,
|
|
2222
2736
|
buildSymphonyReportInboxNotificationRow,
|
|
2223
2737
|
buildSymphonyRunRow,
|