@cat-factory/orchestration 0.21.0 → 0.21.1

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.
@@ -2,7 +2,7 @@ import { assertFound, ValidationError } from '@cat-factory/kernel';
2
2
  import { generateText } from 'ai';
3
3
  import { catFactoryObservability, providerWebSearchTools, REVIEW_SYSTEM_PROMPT, REWORK_SYSTEM_PROMPT, WRITER_SYSTEM_PROMPT, } from '@cat-factory/agents';
4
4
  import { IterativeReviewService, } from '../review/IterativeReviewService.js';
5
- import { buildRecommendationPrompt, buildReviewPrompt, buildReworkPrompt, coerceRecommendations, extractJson, } from './requirements.logic.js';
5
+ import { buildRecommendationPrompt, buildReviewPrompt, buildReworkPrompt, coerceSingleRecommendation, extractJson, findSourceItem, } from './requirements.logic.js';
6
6
  /**
7
7
  * The requirements-review agent: a single LLM call reviews a block's collected requirements
8
8
  * (description + linked PRD/RFC docs + tracker issues) and raises questions/challenges,
@@ -69,99 +69,187 @@ export class RequirementReviewService extends IterativeReviewService {
69
69
  return this.enabled;
70
70
  }
71
71
  /**
72
- * Recommend grounded answers for a batch of findings the human marked "recommend something".
73
- * Marks those items `recommend_requested`, then runs the Requirement Writer LLM grounded on
74
- * the block's best-practice fragments (FIRST), the in-repo `spec/`/`tech-spec/`, and web search
75
- * and appends one `ready` recommendation per finding. NOT AI-reviewed; the human decides.
76
- * Runs in parallel with incorporation (the driver awaits both). Best-effort: a Writer failure
77
- * still leaves the items `recommend_requested` so the human can answer manually.
72
+ * Prepare a recommendation batch SYNCHRONOUSLY: mark the targeted findings
73
+ * `recommend_requested` and append one `pending` placeholder recommendation per finding
74
+ * (snapshotting the source finding by title/detail). The slow Writer LLM does NOT run here —
75
+ * {@link fillPendingRecommendations} fills the placeholders later, in the durable driver, so
76
+ * the human is handed straight back to the board. Returns the review with the placeholders so
77
+ * the SPA shows the "generating…" state immediately. Idempotent per finding: a finding that
78
+ * already carries a `pending` placeholder is not duplicated.
78
79
  */
79
- async recommend(workspaceId, reviewId, itemIds, note) {
80
+ async prepareRecommendations(workspaceId, reviewId, itemIds, note) {
80
81
  const targetIds = new Set(itemIds);
81
- // Mark the targeted findings `recommend_requested` up front in a fresh read-modify-write, so
82
- // the marks are durable even if the Writer LLM then fails (the human can still answer manually).
83
- const marked = await this.markRecommendRequested(workspaceId, reviewId, targetIds);
84
- const block = assertFound(await this.deps.blockRepository.get(workspaceId, marked.blockId), 'Block', marked.blockId);
85
- const findings = marked.items.filter((i) => targetIds.has(i.id) && i.status === 'recommend_requested');
86
- if (findings.length === 0)
87
- return marked;
88
- const { modelProvider, ref } = await this.resolveModel(workspaceId, block);
89
- const context = await this.gatherContext(workspaceId, block);
90
- const fragments = (await this.resolveBlockFragments?.(workspaceId, block.id)) ?? [];
91
- const grounding = await this.gatherGrounding(workspaceId, block, findings, fragments);
92
- let suggestions;
93
- try {
94
- const model = modelProvider.resolve(ref);
95
- const result = await generateText({
96
- model,
97
- system: WRITER_SYSTEM_PROMPT,
98
- prompt: buildRecommendationPrompt(context, findings, grounding, note),
99
- temperature: 0.2,
100
- maxOutputTokens: 6000,
101
- // Provider-hosted web search when the model supports it (Anthropic/OpenAI); the
102
- // gateway-RAG `webResults` already folded into the prompt cover other providers.
103
- ...(providerWebSearchTools(ref.provider)
104
- ? { tools: providerWebSearchTools(ref.provider) }
105
- : {}),
106
- providerOptions: catFactoryObservability({ agentKind: 'requirements-writer', workspaceId }),
107
- });
108
- suggestions = coerceRecommendations(extractJson(result.text));
109
- }
110
- catch (e) {
111
- throw new ValidationError(`The requirement writer (${ref.provider}:${ref.model}) failed: ${e instanceof Error ? e.message : String(e)}`);
112
- }
113
- // Re-read fresh: the Writer call above can take several seconds, during which the human may
114
- // have answered/dismissed other findings. Append our recommendations onto the LATEST review
115
- // rather than upserting the pre-LLM snapshot (which would clobber those concurrent edits).
116
82
  const review = assertFound(await this.repository.get(workspaceId, reviewId), this.entityName, reviewId);
117
83
  const now = this.deps.clock.now();
118
- const fragmentById = new Map(fragments.map((f) => [f.id, f]));
84
+ const trimmedNote = note?.trim() || null;
119
85
  const recommendations = [...review.recommendations];
120
- for (const finding of findings) {
121
- const suggestion = suggestions.get(finding.id);
122
- if (!suggestion)
86
+ let changed = false;
87
+ for (const item of review.items) {
88
+ if (!targetIds.has(item.id) || item.status === 'dismissed')
89
+ continue;
90
+ if (item.status !== 'recommend_requested') {
91
+ item.status = 'recommend_requested';
92
+ item.updatedAt = now;
93
+ changed = true;
94
+ }
95
+ // Don't queue a second placeholder for a finding the Writer is already working on. Keyed
96
+ // on the finding id so two findings that share an identical title+detail still each get
97
+ // their own placeholder.
98
+ const alreadyPending = recommendations.some((r) => r.status === 'pending' && r.sourceFinding.itemId === item.id);
99
+ if (alreadyPending)
123
100
  continue;
124
- const standard = suggestion.fromStandard
125
- ? fragmentById.get(suggestion.fromStandard)
126
- : undefined;
127
101
  recommendations.push({
128
102
  id: this.deps.idGenerator.next('rec'),
129
- sourceFinding: { title: finding.title, detail: finding.detail },
130
- recommendedText: suggestion.recommendation,
131
- status: 'ready',
132
- note: note?.trim() || null,
133
- groundedInFragment: standard ? { id: standard.id, title: standard.title } : null,
103
+ sourceFinding: { title: item.title, detail: item.detail, itemId: item.id },
104
+ recommendedText: '',
105
+ status: 'pending',
106
+ note: trimmedNote,
107
+ groundedInFragment: null,
134
108
  createdAt: now,
135
109
  updatedAt: now,
136
110
  });
111
+ changed = true;
137
112
  }
113
+ if (!changed)
114
+ return review;
138
115
  const updated = { ...review, recommendations, updatedAt: now };
139
116
  await this.repository.upsert(workspaceId, updated);
140
117
  return updated;
141
118
  }
142
119
  /**
143
- * Mark the targeted, non-dismissed findings `recommend_requested` in a fresh read-modify-write.
144
- * A standalone durable write (not folded into {@link recommend}'s trailing upsert) so the marks
145
- * survive a subsequent Writer-LLM failure.
120
+ * Fill every `pending` recommendation on a review by running the Requirement Writer once per
121
+ * finding, so progress streams in as `ready / total`. Grounding shared across findings (the
122
+ * block's best-practice fragments + the in-repo `spec/`/`tech-spec/` excerpts) is gathered
123
+ * ONCE; only web search runs per finding. Each filled recommendation is persisted and
124
+ * `onProgress` is invoked with the fresh review, so an open window tracks the count live and
125
+ * the board's "Recommending…" badge clears the moment the last placeholder settles. A
126
+ * per-finding Writer failure drops that placeholder and reopens its finding (so the human can
127
+ * answer manually) rather than wedging the whole batch. Best-effort and re-entrant: a replay
128
+ * that re-runs it simply finds no `pending` placeholders and produces nothing. Returns the
129
+ * number of recommendations produced (for the completion notification).
146
130
  */
147
- async markRecommendRequested(workspaceId, reviewId, targetIds) {
148
- const review = assertFound(await this.repository.get(workspaceId, reviewId), this.entityName, reviewId);
149
- const now = this.deps.clock.now();
150
- let changed = false;
151
- for (const item of review.items) {
152
- if (targetIds.has(item.id) &&
153
- item.status !== 'dismissed' &&
154
- item.status !== 'recommend_requested') {
155
- item.status = 'recommend_requested';
156
- item.updatedAt = now;
157
- changed = true;
158
- }
131
+ async fillPendingRecommendations(workspaceId, reviewId, opts = {}) {
132
+ const initial = assertFound(await this.repository.get(workspaceId, reviewId), this.entityName, reviewId);
133
+ const pending = initial.recommendations.filter((r) => r.status === 'pending');
134
+ if (pending.length === 0)
135
+ return { produced: 0 };
136
+ const block = assertFound(await this.deps.blockRepository.get(workspaceId, initial.blockId), 'Block', initial.blockId);
137
+ let model;
138
+ let ref;
139
+ try {
140
+ const resolved = await this.resolveModel(workspaceId, block);
141
+ ref = resolved.ref;
142
+ model = resolved.modelProvider.resolve(ref);
143
+ }
144
+ catch {
145
+ // The reviewer model can't be resolved for this deployment (no provider key / binding wired
146
+ // for the resolved ref). The Writer cannot run, so degrade gracefully exactly like a
147
+ // per-finding failure: drop every pending placeholder and reopen its finding for manual
148
+ // answering, rather than throwing. A raw throw here 500'd the off-path inline request on the
149
+ // runtime whose default resolves to an unregistered provider while the other resolved its
150
+ // binding and returned 200 — the cross-runtime divergence the conformance suite guards.
151
+ await this.dropPendingRecommendations(workspaceId, reviewId, opts.onProgress);
152
+ return { produced: 0 };
159
153
  }
160
- if (changed) {
154
+ const context = await this.gatherContext(workspaceId, block);
155
+ const fragments = (await this.resolveBlockFragments?.(workspaceId, block.id)) ?? [];
156
+ const fragmentById = new Map(fragments.map((f) => [f.id, f]));
157
+ // Shared, finding-independent grounding gathered ONCE for the whole batch (repo reads + a
158
+ // single web search over the batch's finding titles), reused across the per-finding calls.
159
+ const sharedSpecExcerpts = await this.gatherSpecExcerpts(workspaceId, block);
160
+ const sharedWebResults = await this.gatherWebResults(workspaceId, pending.map((p) => p.sourceFinding.title));
161
+ let produced = 0;
162
+ for (const placeholder of pending) {
163
+ // Re-anchor the placeholder to a LIVE finding — prefer the snapshotted finding id, falling
164
+ // back to title/detail when ids churned across a re-review. Gone → nothing to recommend for.
165
+ const before = assertFound(await this.repository.get(workspaceId, reviewId), this.entityName, reviewId);
166
+ const liveFinding = findSourceItem(before.items, placeholder.sourceFinding);
167
+ const suggestion = liveFinding
168
+ ? await this.runWriterForFinding(workspaceId, model, ref, context, liveFinding, placeholder.note ?? undefined, fragments, sharedSpecExcerpts, sharedWebResults)
169
+ : null;
170
+ // Re-read fresh each iteration: the per-finding Writer calls take seconds, during which the
171
+ // human may have answered/dismissed other findings or accepted an earlier recommendation.
172
+ const review = assertFound(await this.repository.get(workspaceId, reviewId), this.entityName, reviewId);
173
+ const rec = review.recommendations.find((r) => r.id === placeholder.id);
174
+ if (!rec || rec.status !== 'pending')
175
+ continue; // accepted/rejected/churned away meanwhile
176
+ const now = this.deps.clock.now();
177
+ if (suggestion) {
178
+ const standard = suggestion.fromStandard
179
+ ? fragmentById.get(suggestion.fromStandard)
180
+ : undefined;
181
+ rec.recommendedText = suggestion.recommendation;
182
+ rec.groundedInFragment = standard ? { id: standard.id, title: standard.title } : null;
183
+ rec.status = 'ready';
184
+ rec.updatedAt = now;
185
+ produced += 1;
186
+ }
187
+ else {
188
+ // The Writer failed for (or no longer matches) this finding: drop the dead placeholder
189
+ // and reopen its finding so the human can answer it by hand.
190
+ review.recommendations = review.recommendations.filter((r) => r.id !== placeholder.id);
191
+ const item = findSourceItem(review.items, placeholder.sourceFinding);
192
+ if (item && item.status === 'recommend_requested') {
193
+ item.status = 'open';
194
+ item.updatedAt = now;
195
+ }
196
+ }
161
197
  review.updatedAt = now;
162
198
  await this.repository.upsert(workspaceId, review);
199
+ await opts.onProgress?.(review);
163
200
  }
164
- return review;
201
+ if (produced > 0)
202
+ await this.notifyRecommendationsReady(workspaceId, block, produced);
203
+ return { produced };
204
+ }
205
+ /**
206
+ * Drop every `pending` placeholder on a review and reopen its source finding (the same cleanup
207
+ * the per-finding failure path does, applied to the whole batch). Used when the Writer can't run
208
+ * at all — the reviewer model is unresolvable — so the human gets the findings back to answer by
209
+ * hand instead of a wedged "generating…" state. Best-effort: emits progress after the cleanup.
210
+ */
211
+ async dropPendingRecommendations(workspaceId, reviewId, onProgress) {
212
+ const review = await this.repository.get(workspaceId, reviewId);
213
+ if (!review)
214
+ return;
215
+ const pending = review.recommendations.filter((r) => r.status === 'pending');
216
+ if (pending.length === 0)
217
+ return;
218
+ const now = this.deps.clock.now();
219
+ review.recommendations = review.recommendations.filter((r) => r.status !== 'pending');
220
+ for (const placeholder of pending) {
221
+ const item = findSourceItem(review.items, placeholder.sourceFinding);
222
+ if (item && item.status === 'recommend_requested') {
223
+ item.status = 'open';
224
+ item.updatedAt = now;
225
+ }
226
+ }
227
+ review.updatedAt = now;
228
+ await this.repository.upsert(workspaceId, review);
229
+ await onProgress?.(review);
230
+ }
231
+ /**
232
+ * Flip a settled recommendation back to `pending` with a fresh "do it differently" note and
233
+ * re-mark its source finding `recommend_requested`. The (slow) Writer re-runs later via
234
+ * {@link fillPendingRecommendations} in the durable driver — the SAME async path as a fresh
235
+ * batch — so a re-request never blocks the request either. Returns the review (with the
236
+ * placeholder reset). The source finding for the recommendation must still exist.
237
+ */
238
+ async markRecommendationPending(workspaceId, reviewId, recId, note) {
239
+ return this.mutateRecommendation(workspaceId, reviewId, recId, (rec, review, now) => {
240
+ rec.status = 'pending';
241
+ rec.recommendedText = '';
242
+ rec.groundedInFragment = null;
243
+ rec.note = note.trim() || null;
244
+ const item = findSourceItem(review.items, rec.sourceFinding);
245
+ if (!item) {
246
+ throw new ValidationError('The finding this recommendation answers no longer exists');
247
+ }
248
+ if (item.status !== 'recommend_requested') {
249
+ item.status = 'recommend_requested';
250
+ item.updatedAt = now;
251
+ }
252
+ });
165
253
  }
166
254
  /**
167
255
  * Accept a recommendation: it becomes the source finding's answer (the matching item flips
@@ -171,7 +259,7 @@ export class RequirementReviewService extends IterativeReviewService {
171
259
  async acceptRecommendation(workspaceId, reviewId, recId) {
172
260
  return this.mutateRecommendation(workspaceId, reviewId, recId, (rec, review, now) => {
173
261
  rec.status = 'accepted';
174
- const item = review.items.find((i) => i.title === rec.sourceFinding.title && i.detail === rec.sourceFinding.detail);
262
+ const item = findSourceItem(review.items, rec.sourceFinding);
175
263
  if (item) {
176
264
  item.reply = rec.recommendedText;
177
265
  item.status = 'answered';
@@ -179,70 +267,50 @@ export class RequirementReviewService extends IterativeReviewService {
179
267
  }
180
268
  });
181
269
  }
182
- /** Reject a recommendation (the human will dismiss / answer manually / re-request). */
270
+ /**
271
+ * Reject a recommendation and reopen its source finding (status `open`) so the human can
272
+ * answer it manually — a `recommend_requested` finding hides its answer box, so leaving it
273
+ * marked would strand the finding with no way to settle it.
274
+ */
183
275
  async rejectRecommendation(workspaceId, reviewId, recId) {
184
- return this.mutateRecommendation(workspaceId, reviewId, recId, (rec) => {
276
+ return this.mutateRecommendation(workspaceId, reviewId, recId, (rec, review, now) => {
185
277
  rec.status = 'rejected';
278
+ const item = findSourceItem(review.items, rec.sourceFinding);
279
+ if (item && item.status === 'recommend_requested') {
280
+ item.status = 'open';
281
+ item.updatedAt = now;
282
+ }
186
283
  });
187
284
  }
188
- /**
189
- * Re-request a single recommendation with a "do it differently" note: re-runs the Writer for
190
- * just that finding and replaces the suggestion text (back to `ready`).
191
- */
192
- async reRequestRecommendation(workspaceId, reviewId, recId, note) {
193
- const initial = assertFound(await this.repository.get(workspaceId, reviewId), this.entityName, reviewId);
194
- const rec0 = initial.recommendations.find((r) => r.id === recId);
195
- if (!rec0)
196
- throw new ValidationError(`Recommendation '${recId}' not found`);
197
- const item = initial.items.find((i) => i.title === rec0.sourceFinding.title && i.detail === rec0.sourceFinding.detail);
198
- if (!item)
199
- throw new ValidationError('The finding this recommendation answers no longer exists');
200
- const block = assertFound(await this.deps.blockRepository.get(workspaceId, initial.blockId), 'Block', initial.blockId);
201
- const { modelProvider, ref } = await this.resolveModel(workspaceId, block);
202
- const context = await this.gatherContext(workspaceId, block);
203
- const fragments = (await this.resolveBlockFragments?.(workspaceId, block.id)) ?? [];
204
- const grounding = await this.gatherGrounding(workspaceId, block, [item], fragments);
205
- let suggestions;
285
+ /** Run the Writer for one live finding; returns null when it fails (the caller reopens the finding). */
286
+ async runWriterForFinding(workspaceId, model, ref, context, finding, note, fragments, sharedSpecExcerpts, sharedWebResults) {
287
+ const grounding = {
288
+ fragments,
289
+ specExcerpts: sharedSpecExcerpts,
290
+ webResults: sharedWebResults,
291
+ };
206
292
  try {
207
- const model = modelProvider.resolve(ref);
208
293
  const result = await generateText({
209
294
  model,
210
295
  system: WRITER_SYSTEM_PROMPT,
211
- prompt: buildRecommendationPrompt(context, [item], grounding, note),
296
+ prompt: buildRecommendationPrompt(context, [finding], grounding, note),
212
297
  temperature: 0.2,
213
298
  maxOutputTokens: 6000,
299
+ // Provider-hosted web search when the model supports it (Anthropic/OpenAI); the
300
+ // gateway-RAG `webResults` already folded into the prompt cover other providers.
214
301
  ...(providerWebSearchTools(ref.provider)
215
302
  ? { tools: providerWebSearchTools(ref.provider) }
216
303
  : {}),
217
304
  providerOptions: catFactoryObservability({ agentKind: 'requirements-writer', workspaceId }),
218
305
  });
219
- suggestions = coerceRecommendations(extractJson(result.text));
220
- }
221
- catch (e) {
222
- throw new ValidationError(`The requirement writer (${ref.provider}:${ref.model}) failed: ${e instanceof Error ? e.message : String(e)}`);
306
+ // Single-finding call: tolerate a missing/garbled echoed itemId rather than discarding a
307
+ // valid suggestion (which would force-reopen the finding as if the Writer had failed).
308
+ return coerceSingleRecommendation(extractJson(result.text), finding.id);
223
309
  }
224
- const suggestion = suggestions.get(item.id);
225
- // Re-read fresh so concurrent answer/dismiss edits made during the (multi-second) Writer call
226
- // aren't clobbered — mutate only this recommendation on the LATEST review.
227
- const review = assertFound(await this.repository.get(workspaceId, reviewId), this.entityName, reviewId);
228
- const rec = review.recommendations.find((r) => r.id === recId);
229
- if (!rec)
230
- throw new ValidationError(`Recommendation '${recId}' not found`);
231
- const now = this.deps.clock.now();
232
- if (suggestion) {
233
- const fragmentById = new Map(fragments.map((f) => [f.id, f]));
234
- const standard = suggestion.fromStandard
235
- ? fragmentById.get(suggestion.fromStandard)
236
- : undefined;
237
- rec.recommendedText = suggestion.recommendation;
238
- rec.groundedInFragment = standard ? { id: standard.id, title: standard.title } : null;
310
+ catch {
311
+ // Best-effort per finding a failure drops just this placeholder (the caller reopens it).
312
+ return null;
239
313
  }
240
- rec.status = 'ready';
241
- rec.note = note.trim() || null;
242
- rec.updatedAt = now;
243
- review.updatedAt = now;
244
- await this.repository.upsert(workspaceId, review);
245
- return review;
246
314
  }
247
315
  async mutateRecommendation(workspaceId, reviewId, recId, mutate) {
248
316
  const review = assertFound(await this.repository.get(workspaceId, reviewId), this.entityName, reviewId);
@@ -257,11 +325,11 @@ export class RequirementReviewService extends IterativeReviewService {
257
325
  return review;
258
326
  }
259
327
  /**
260
- * Gather the Writer's grounding material: best-practice fragments (passed in), in-repo
261
- * `spec/`/`tech-spec/` overviews (via RepoFiles when wired), and gateway-RAG web snippets
262
- * (when wired). All best-effort — any source that errors or is unwired is simply omitted.
328
+ * Read the in-repo `spec/`/`tech-spec/` overviews (via RepoFiles when wired) the Writer
329
+ * grounds on. Gathered ONCE per batch (finding-independent) and reused across the per-finding
330
+ * Writer calls. Best-effort — unwired / errors an empty list.
263
331
  */
264
- async gatherGrounding(workspaceId, block, findings, fragments) {
332
+ async gatherSpecExcerpts(workspaceId, block) {
265
333
  const specExcerpts = [];
266
334
  try {
267
335
  const ctx = await this.resolveRunRepoContext?.(workspaceId, block.id);
@@ -276,17 +344,51 @@ export class RequirementReviewService extends IterativeReviewService {
276
344
  catch {
277
345
  // best-effort grounding
278
346
  }
279
- let webResults = [];
280
- if (this.webSearch) {
281
- try {
282
- const query = findings.map((f) => f.title).join('; ');
283
- webResults = await this.webSearch(workspaceId, query);
284
- }
285
- catch {
286
- webResults = [];
287
- }
347
+ return specExcerpts;
348
+ }
349
+ /**
350
+ * Gateway-RAG web snippets for a recommendation batch (when web search is wired). Gathered
351
+ * ONCE over the batch's finding titles — like the spec excerpts and fragments — so a batch of
352
+ * N findings makes a single web-search call, not N. Best-effort — unwired / errors → an empty
353
+ * list.
354
+ */
355
+ async gatherWebResults(workspaceId, findingTitles) {
356
+ if (!this.webSearch || findingTitles.length === 0)
357
+ return [];
358
+ try {
359
+ return await this.webSearch(workspaceId, findingTitles.join('; '));
360
+ }
361
+ catch {
362
+ return [];
363
+ }
364
+ }
365
+ /**
366
+ * Tell people the Requirement Writer finished a recommendation batch (so the human who walked
367
+ * away from the window is summoned back to accept/reject). Best-effort, mirrors
368
+ * {@link notifyFindings}; reuses the `requirement_review` notification type (the inbox routes it
369
+ * to the same review window).
370
+ */
371
+ async notifyRecommendationsReady(workspaceId, block, count) {
372
+ if (count <= 0 || !this.deps.notificationService)
373
+ return;
374
+ try {
375
+ await this.deps.notificationService.raise(workspaceId, {
376
+ type: 'requirement_review',
377
+ blockId: block.id,
378
+ executionId: null,
379
+ title: `Requirements recommendations: ${block.title}`,
380
+ body: `The requirement writer prepared ${count} recommendation${count === 1 ? '' : 's'} to review.`,
381
+ payload: {
382
+ findingCount: count,
383
+ ...(block.responsibleProductUserId
384
+ ? { targetUserId: block.responsibleProductUserId }
385
+ : {}),
386
+ },
387
+ });
388
+ }
389
+ catch {
390
+ // Best-effort: the recommendations are already persisted.
288
391
  }
289
- return { fragments, specExcerpts, webResults };
290
392
  }
291
393
  /** Assemble the block's collected requirements + any linked docs/issues. */
292
394
  async gatherContext(workspaceId, block) {
@@ -1 +1 @@
1
- {"version":3,"file":"RequirementReviewService.js","sourceRoot":"","sources":["../../../src/modules/requirements/RequirementReviewService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RequirementReviewService.js","sourceRoot":"","sources":["../../../src/modules/requirements/RequirementReviewService.ts"],"names":[],"mappings":"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"}
@@ -94,6 +94,30 @@ export declare function coerceRecommendations(raw: unknown): Map<string, {
94
94
  recommendation: string;
95
95
  fromStandard: string | null;
96
96
  }>;
97
+ /**
98
+ * Coerce the Writer's JSON for a SINGLE-finding call. The per-finding recommendation flow
99
+ * prompts the Writer with exactly one finding, so it must tolerate a missing/garbled `itemId`:
100
+ * single-item prompts frequently omit the echoed id, and {@link coerceRecommendations} drops
101
+ * any entry without one — which would silently discard a perfectly good suggestion and
102
+ * force-reopen the finding. So: prefer the entry whose id matches, but when the model returns a
103
+ * lone entry with a recommendation string, take it regardless of the id. Returns null only when
104
+ * there is genuinely no usable recommendation.
105
+ */
106
+ export declare function coerceSingleRecommendation(raw: unknown, itemId: string): {
107
+ recommendation: string;
108
+ fromStandard: string | null;
109
+ } | null;
110
+ /**
111
+ * Resolve the live review item a recommendation answers. Prefers the snapshotted `itemId` (the
112
+ * primary anchor, so two findings with identical title+detail stay distinct), then falls back to
113
+ * title+detail for recommendations created before the id was snapshotted or whose finding id
114
+ * churned across a re-review. Returns undefined when no finding matches.
115
+ */
116
+ export declare function findSourceItem(items: RequirementReviewItem[], source: {
117
+ title: string;
118
+ detail: string;
119
+ itemId?: string;
120
+ }): RequirementReviewItem | undefined;
97
121
  /**
98
122
  * Whether an incorporation pass has anything to fold in: at least one finding the human
99
123
  * answered/resolved with a non-empty reply, or a freeform "do it differently" feedback.
@@ -1 +1 @@
1
- {"version":3,"file":"requirements.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/requirements/requirements.logic.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"requirements.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/requirements/requirements.logic.ts"],"names":[],"mappings":"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"}
@@ -221,6 +221,50 @@ export function coerceRecommendations(raw) {
221
221
  }
222
222
  return out;
223
223
  }
224
+ /**
225
+ * Coerce the Writer's JSON for a SINGLE-finding call. The per-finding recommendation flow
226
+ * prompts the Writer with exactly one finding, so it must tolerate a missing/garbled `itemId`:
227
+ * single-item prompts frequently omit the echoed id, and {@link coerceRecommendations} drops
228
+ * any entry without one — which would silently discard a perfectly good suggestion and
229
+ * force-reopen the finding. So: prefer the entry whose id matches, but when the model returns a
230
+ * lone entry with a recommendation string, take it regardless of the id. Returns null only when
231
+ * there is genuinely no usable recommendation.
232
+ */
233
+ export function coerceSingleRecommendation(raw, itemId) {
234
+ const list = Array.isArray(raw?.recommendations)
235
+ ? raw.recommendations
236
+ : Array.isArray(raw)
237
+ ? raw
238
+ : [];
239
+ const entries = list
240
+ .filter((e) => !!e && typeof e === 'object')
241
+ .map((obj) => ({
242
+ itemId: asString(obj.itemId),
243
+ recommendation: asString(obj.recommendation),
244
+ fromStandard: asString(obj.fromStandard) || null,
245
+ }))
246
+ .filter((e) => e.recommendation);
247
+ if (entries.length === 0)
248
+ return null;
249
+ const chosen = entries.find((e) => e.itemId === itemId) ?? (entries.length === 1 ? entries[0] : null);
250
+ return chosen
251
+ ? { recommendation: chosen.recommendation, fromStandard: chosen.fromStandard }
252
+ : null;
253
+ }
254
+ /**
255
+ * Resolve the live review item a recommendation answers. Prefers the snapshotted `itemId` (the
256
+ * primary anchor, so two findings with identical title+detail stay distinct), then falls back to
257
+ * title+detail for recommendations created before the id was snapshotted or whose finding id
258
+ * churned across a re-review. Returns undefined when no finding matches.
259
+ */
260
+ export function findSourceItem(items, source) {
261
+ if (source.itemId) {
262
+ const byId = items.find((i) => i.id === source.itemId);
263
+ if (byId)
264
+ return byId;
265
+ }
266
+ return items.find((i) => i.title === source.title && i.detail === source.detail);
267
+ }
224
268
  /**
225
269
  * Whether an incorporation pass has anything to fold in: at least one finding the human
226
270
  * answered/resolved with a non-empty reply, or a freeform "do it differently" feedback.