@rhei-team/rhei 1.0.0-beta.0
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/README.md +1048 -0
- package/bin/rhei-mcp.js +3 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +86366 -0
- package/dist/premium/contracts.d.ts +445 -0
- package/dist/premium/contracts.js +97 -0
- package/dist/vendor/rhei-core/briefs.js +1276 -0
- package/dist/vendor/rhei-core/codeAgent.js +615 -0
- package/dist/vendor/rhei-core/codeEditSession.js +293 -0
- package/dist/vendor/rhei-core/codeIntelligence.js +4287 -0
- package/dist/vendor/rhei-core/codeMarket.js +8946 -0
- package/dist/vendor/rhei-core/codeReviewIntelligence.js +5918 -0
- package/dist/vendor/rhei-core/codeSemantics.js +172427 -0
- package/dist/vendor/rhei-core/codeStory.js +667 -0
- package/dist/vendor/rhei-core/codeStrategyPlan.js +663 -0
- package/dist/vendor/rhei-core/codeTrail.js +2781 -0
- package/dist/vendor/rhei-core/codeWorkHandoff.js +281 -0
- package/dist/vendor/rhei-core/contextQuery.js +1119 -0
- package/dist/vendor/rhei-core/contextRouting.js +2052 -0
- package/dist/vendor/rhei-core/evidenceLedger.js +5336 -0
- package/dist/vendor/rhei-core/executionSafety.js +0 -0
- package/dist/vendor/rhei-core/goalIntelligence.js +2218 -0
- package/dist/vendor/rhei-core/model-lanes.js +75 -0
- package/dist/vendor/rhei-core/now.js +127 -0
- package/dist/vendor/rhei-core/package.json +29 -0
- package/dist/vendor/rhei-core/programPlan.js +3153 -0
- package/dist/vendor/rhei-core/search.js +196 -0
- package/dist/vendor/rhei-core/serviceIntelligence.js +1734 -0
- package/dist/vendor/rhei-core/workflowPlan.js +1660 -0
- package/package.json +41 -0
|
@@ -0,0 +1,2218 @@
|
|
|
1
|
+
// ../core/src/goalIntelligence/types.ts
|
|
2
|
+
var GOAL_INTELLIGENCE_SCHEMA_VERSION = 1;
|
|
3
|
+
var GOAL_INTELLIGENCE_COMPACT_REF_LIMIT = 12;
|
|
4
|
+
var GOAL_STEWARD_DECISION_VALUES = [
|
|
5
|
+
"continue_active_goal",
|
|
6
|
+
"replace_active_goal",
|
|
7
|
+
"branch_goal",
|
|
8
|
+
"start_goal",
|
|
9
|
+
"ask_for_goal_boundary"
|
|
10
|
+
];
|
|
11
|
+
var GOAL_MEMORY_CANDIDATE_KIND_VALUES = [
|
|
12
|
+
"style_preference",
|
|
13
|
+
"code_rewrite_preference",
|
|
14
|
+
"outcome_pattern",
|
|
15
|
+
"lifecycle_file_pattern",
|
|
16
|
+
"lifecycle_worktask_pattern",
|
|
17
|
+
"validation_practice",
|
|
18
|
+
"risk_pattern",
|
|
19
|
+
"proof_requirement",
|
|
20
|
+
"review_process"
|
|
21
|
+
];
|
|
22
|
+
var GOAL_MEMORY_CANDIDATE_SOURCE_KIND_VALUES = [
|
|
23
|
+
"goal_lifecycle",
|
|
24
|
+
"outcome_feedback",
|
|
25
|
+
"learn_from_outcome",
|
|
26
|
+
"preference_replay",
|
|
27
|
+
"pr_review",
|
|
28
|
+
"code_trail",
|
|
29
|
+
"om_entry",
|
|
30
|
+
"manual",
|
|
31
|
+
"goal_outcome_feedback",
|
|
32
|
+
"goal_lifecycle_observation",
|
|
33
|
+
"code_review",
|
|
34
|
+
"observational_memory",
|
|
35
|
+
"explicit"
|
|
36
|
+
];
|
|
37
|
+
var GOAL_MEMORY_CANDIDATE_STATUS_VALUES = [
|
|
38
|
+
"candidate",
|
|
39
|
+
"needs_more_evidence",
|
|
40
|
+
"ready_for_review",
|
|
41
|
+
"rejected",
|
|
42
|
+
"promoted_to_learning",
|
|
43
|
+
"submitted_to_truth",
|
|
44
|
+
"truth_approved",
|
|
45
|
+
"truth_rejected"
|
|
46
|
+
];
|
|
47
|
+
// ../core/src/goalIntelligence/candidateHelpers.ts
|
|
48
|
+
var GOAL_MEMORY_HASH_PREFIX = "goal-memory";
|
|
49
|
+
function buildGoalMemoryCandidateIdentityV1(args) {
|
|
50
|
+
const normalizedGoal = normalizeGoalMemoryTextV1(args.goal);
|
|
51
|
+
const goalHash = normalizedGoal ? `${GOAL_MEMORY_HASH_PREFIX}:goal:${stableHash(normalizedGoal)}` : undefined;
|
|
52
|
+
const sourceEventId = cleanString(args.sourceEventId) ?? firstString(args.sourceIds) ?? `${GOAL_MEMORY_HASH_PREFIX}:source-event:${stableHash({
|
|
53
|
+
sourceKind: args.sourceKind,
|
|
54
|
+
candidateKind: args.candidateKind,
|
|
55
|
+
title: normalizeGoalMemoryTextV1(args.title),
|
|
56
|
+
summary: normalizeGoalMemoryTextV1(args.summary),
|
|
57
|
+
goalHash,
|
|
58
|
+
goalSessionId: cleanString(args.goalSessionId),
|
|
59
|
+
targetRefs: normalizedStringSet(args.targetRefs),
|
|
60
|
+
filePaths: normalizedStringSet(args.filePaths),
|
|
61
|
+
evidenceRefs: normalizedStringSet(args.evidenceRefs),
|
|
62
|
+
observationRefs: normalizedStringSet(args.observationRefs),
|
|
63
|
+
taskRefs: normalizedStringSet(args.taskRefs)
|
|
64
|
+
})}`;
|
|
65
|
+
const sourceHash = `${GOAL_MEMORY_HASH_PREFIX}:source:${stableHash({
|
|
66
|
+
sourceKind: args.sourceKind,
|
|
67
|
+
sourceEventId,
|
|
68
|
+
sourceIds: normalizedStringSet(args.sourceIds),
|
|
69
|
+
candidateKind: args.candidateKind,
|
|
70
|
+
title: normalizeGoalMemoryTextV1(args.title),
|
|
71
|
+
summary: normalizeGoalMemoryTextV1(args.summary),
|
|
72
|
+
normalizedRule: normalizeGoalMemoryTextV1(args.normalizedRule),
|
|
73
|
+
goalHash,
|
|
74
|
+
goalSessionId: cleanString(args.goalSessionId),
|
|
75
|
+
filePaths: normalizedStringSet(args.filePaths),
|
|
76
|
+
targetRefs: normalizedStringSet(args.targetRefs),
|
|
77
|
+
evidenceRefs: normalizedStringSet(args.evidenceRefs),
|
|
78
|
+
observationRefs: normalizedStringSet(args.observationRefs),
|
|
79
|
+
taskRefs: normalizedStringSet(args.taskRefs),
|
|
80
|
+
serviceConnectionIds: normalizedStringSet(args.serviceConnectionIds)
|
|
81
|
+
})}`;
|
|
82
|
+
const dedupeKey = `${GOAL_MEMORY_HASH_PREFIX}:dedupe:${stableHash({
|
|
83
|
+
sourceKind: args.sourceKind,
|
|
84
|
+
candidateKind: args.candidateKind,
|
|
85
|
+
goalHash: goalHash ?? cleanString(args.goalSessionId),
|
|
86
|
+
goalSessionId: cleanString(args.goalSessionId),
|
|
87
|
+
activeGoalId: cleanString(args.activeGoalId),
|
|
88
|
+
parentGoalId: cleanString(args.parentGoalId),
|
|
89
|
+
supersedesGoalId: cleanString(args.supersedesGoalId),
|
|
90
|
+
filePaths: normalizedStringSet(args.filePaths),
|
|
91
|
+
targetRefs: normalizedStringSet(args.targetRefs),
|
|
92
|
+
normalizedRule: normalizeGoalMemoryTextV1(args.normalizedRule ?? args.summary ?? args.title),
|
|
93
|
+
serviceConnectionIds: normalizedStringSet(args.serviceConnectionIds)
|
|
94
|
+
})}`;
|
|
95
|
+
return {
|
|
96
|
+
candidateId: `${GOAL_MEMORY_HASH_PREFIX}:candidate:${stableHash(dedupeKey)}`,
|
|
97
|
+
dedupeKey,
|
|
98
|
+
sourceHash,
|
|
99
|
+
sourceEventId,
|
|
100
|
+
goalHash
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function normalizeGoalMemoryTextV1(value) {
|
|
104
|
+
const text = cleanString(value);
|
|
105
|
+
if (!text)
|
|
106
|
+
return;
|
|
107
|
+
return text.toLowerCase().replace(/\s+/g, " ").trim();
|
|
108
|
+
}
|
|
109
|
+
function collectGoalMemoryFilePathsV1(values) {
|
|
110
|
+
return uniqueStrings(values.flatMap((value) => stringList(value)).filter(looksLikeFilePath));
|
|
111
|
+
}
|
|
112
|
+
function goalMemoryCandidateSourceIdsV1(values) {
|
|
113
|
+
return uniqueStrings(values.flatMap((value) => stringList(value))).slice(0, 24);
|
|
114
|
+
}
|
|
115
|
+
function normalizedStringSet(values) {
|
|
116
|
+
return uniqueStrings(values ?? []).map((value) => normalizeGoalMemoryTextV1(value) ?? value).sort();
|
|
117
|
+
}
|
|
118
|
+
function firstString(values) {
|
|
119
|
+
return uniqueStrings(values ?? [])[0];
|
|
120
|
+
}
|
|
121
|
+
function stringList(value) {
|
|
122
|
+
if (Array.isArray(value))
|
|
123
|
+
return value.map((item) => cleanString(item)).filter((item) => Boolean(item));
|
|
124
|
+
const text = cleanString(value);
|
|
125
|
+
return text ? [text] : [];
|
|
126
|
+
}
|
|
127
|
+
function uniqueStrings(values) {
|
|
128
|
+
return Array.from(new Set(values.map((value) => value?.trim()).filter((value) => Boolean(value))));
|
|
129
|
+
}
|
|
130
|
+
function looksLikeFilePath(value) {
|
|
131
|
+
if (!value.includes("/"))
|
|
132
|
+
return false;
|
|
133
|
+
if (/^(https?:|git:|diff:|trail:|vitest:|test:|validation:|receipt:|goal:|goal-session:|service:)/i.test(value))
|
|
134
|
+
return false;
|
|
135
|
+
return /\.[a-z0-9]+($|[:#])/i.test(value) || value.startsWith("packages/") || value.startsWith("apps/") || value.startsWith("convex/") || value.startsWith("docs/") || value.startsWith("src/");
|
|
136
|
+
}
|
|
137
|
+
function cleanString(value) {
|
|
138
|
+
if (typeof value !== "string")
|
|
139
|
+
return;
|
|
140
|
+
const text = value.trim();
|
|
141
|
+
return text.length > 0 ? text : undefined;
|
|
142
|
+
}
|
|
143
|
+
function stableHash(value) {
|
|
144
|
+
const text = stableJson(value);
|
|
145
|
+
let hash = 2166136261;
|
|
146
|
+
for (let index = 0;index < text.length; index += 1) {
|
|
147
|
+
hash ^= text.charCodeAt(index);
|
|
148
|
+
hash = Math.imul(hash, 16777619);
|
|
149
|
+
}
|
|
150
|
+
return (hash >>> 0).toString(16).padStart(8, "0").slice(0, 12);
|
|
151
|
+
}
|
|
152
|
+
function stableJson(value) {
|
|
153
|
+
if (Array.isArray(value))
|
|
154
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
155
|
+
if (value && typeof value === "object") {
|
|
156
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
|
|
157
|
+
}
|
|
158
|
+
return JSON.stringify(value);
|
|
159
|
+
}
|
|
160
|
+
// ../core/src/goalIntelligence/builders.ts
|
|
161
|
+
var COMPACT_REF_LIMIT = 12;
|
|
162
|
+
var CLOSED_OUTCOMES = new Set(["accepted", "closed", "fixed", "passed", "pass"]);
|
|
163
|
+
var GOAL_INTELLIGENCE_GUARDRAILS = {
|
|
164
|
+
reportOnly: true,
|
|
165
|
+
advisoryOnly: true,
|
|
166
|
+
noAuthority: true,
|
|
167
|
+
noHiddenExecution: true,
|
|
168
|
+
noProviderCalls: true,
|
|
169
|
+
noGraphMutation: true,
|
|
170
|
+
noMemoryPromotion: true,
|
|
171
|
+
noTranscriptReplay: true,
|
|
172
|
+
noServiceWrite: true,
|
|
173
|
+
memoryPromotionRequiresExplicitPath: true,
|
|
174
|
+
compactContinuityOnly: true,
|
|
175
|
+
serviceConnectionsAreEvidenceOnly: true,
|
|
176
|
+
appendRequiresExplicitIntent: true
|
|
177
|
+
};
|
|
178
|
+
function buildGoalIntelligenceGuardrailsV1() {
|
|
179
|
+
return { ...GOAL_INTELLIGENCE_GUARDRAILS };
|
|
180
|
+
}
|
|
181
|
+
function buildGoalSessionV1({ args, goal }) {
|
|
182
|
+
const session = asRecord(args["goalSession"]) ?? {};
|
|
183
|
+
const steering = asRecord(args["steering"]) ?? {};
|
|
184
|
+
const goalSessionId = cleanString2(session["goalSessionId"]) ?? cleanString2(steering["goalSessionId"]) ?? cleanString2(args["goalSessionId"]);
|
|
185
|
+
const activeGoalId = cleanString2(session["activeGoalId"]) ?? cleanString2(steering["activeGoalId"]) ?? cleanString2(args["activeGoalId"]);
|
|
186
|
+
const incomingGoalId = cleanString2(session["incomingGoalId"]) ?? cleanString2(steering["incomingGoalId"]) ?? cleanString2(args["incomingGoalId"]);
|
|
187
|
+
const parentGoalId = cleanString2(session["parentGoalId"]) ?? cleanString2(steering["parentGoalId"]) ?? activeGoalId;
|
|
188
|
+
const supersedesGoalId = cleanString2(session["supersedesGoalId"]) ?? cleanString2(steering["supersedesGoalId"]);
|
|
189
|
+
const activeGoal = cleanString2(session["activeGoal"]) ?? cleanString2(steering["activeGoal"]) ?? cleanString2(args["activeGoal"]);
|
|
190
|
+
const incomingGoal = cleanString2(session["incomingGoal"]) ?? cleanString2(steering["incomingGoal"]) ?? goal;
|
|
191
|
+
return removeUndefined({
|
|
192
|
+
schemaVersion: 1,
|
|
193
|
+
kind: "goal_session",
|
|
194
|
+
goalSessionId,
|
|
195
|
+
activeGoalId,
|
|
196
|
+
incomingGoalId,
|
|
197
|
+
parentGoalId,
|
|
198
|
+
supersedesGoalId,
|
|
199
|
+
activeGoal,
|
|
200
|
+
incomingGoal,
|
|
201
|
+
contextRunIds: uniqueStrings2(stringList2(session["contextRunIds"])),
|
|
202
|
+
codeMarketSnapshotIds: uniqueStrings2(stringList2(session["codeMarketSnapshotIds"])),
|
|
203
|
+
codeWorkroomSessionId: cleanString2(session["codeWorkroomSessionId"]),
|
|
204
|
+
codeTrailRefs: uniqueStrings2(stringList2(session["codeTrailRefs"])),
|
|
205
|
+
prReviewRefs: uniqueStrings2(stringList2(session["prReviewRefs"])),
|
|
206
|
+
commitRefs: uniqueStrings2(stringList2(session["commitRefs"])),
|
|
207
|
+
validationRefs: uniqueStrings2(stringList2(session["validationRefs"])),
|
|
208
|
+
outcomeFeedbackRefs: uniqueStrings2(stringList2(session["outcomeFeedbackRefs"])),
|
|
209
|
+
serviceConnectionIds: uniqueStrings2(stringList2(session["serviceConnectionIds"])),
|
|
210
|
+
staleRefs: uniqueStrings2(stringList2(session["staleRefs"])),
|
|
211
|
+
openQuestions: uniqueStrings2(stringList2(session["openQuestions"])),
|
|
212
|
+
completedSteps: uniqueStrings2(stringList2(session["completedSteps"])),
|
|
213
|
+
remainingSteps: uniqueStrings2(stringList2(session["remainingSteps"])),
|
|
214
|
+
boundaryPolicy: "new_goal_requires_explicit_steer_decision",
|
|
215
|
+
refsOnly: true,
|
|
216
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function goalSessionHasContinuityV1(goalSession) {
|
|
220
|
+
if (!goalSession)
|
|
221
|
+
return false;
|
|
222
|
+
return [
|
|
223
|
+
"completedSteps",
|
|
224
|
+
"remainingSteps",
|
|
225
|
+
"contextRunIds",
|
|
226
|
+
"codeMarketSnapshotIds",
|
|
227
|
+
"codeTrailRefs",
|
|
228
|
+
"prReviewRefs",
|
|
229
|
+
"commitRefs",
|
|
230
|
+
"validationRefs",
|
|
231
|
+
"outcomeFeedbackRefs",
|
|
232
|
+
"staleRefs",
|
|
233
|
+
"openQuestions"
|
|
234
|
+
].some((field) => stringList2(goalSession[field]).length > 0);
|
|
235
|
+
}
|
|
236
|
+
function collectGoalServiceConnectionIdsV1(args) {
|
|
237
|
+
const outcomeFeedback = asRecord(args["outcomeFeedback"]);
|
|
238
|
+
const steering = asRecord(args["steering"]);
|
|
239
|
+
const intelligenceCommit = asRecord(args["intelligenceCommit"]);
|
|
240
|
+
const preferenceReplay = asRecord(args["preferenceReplay"]);
|
|
241
|
+
const diagnosticClosure = asRecord(args["diagnosticClosure"]);
|
|
242
|
+
const serviceImpact = asRecord(args["serviceImpact"]);
|
|
243
|
+
return uniqueStrings2([
|
|
244
|
+
...stringList2(args["serviceConnectionIds"]),
|
|
245
|
+
...stringList2(outcomeFeedback?.["serviceConnectionIds"]),
|
|
246
|
+
...stringList2(steering?.["serviceConnectionIds"]),
|
|
247
|
+
...stringList2(intelligenceCommit?.["serviceConnectionIds"]),
|
|
248
|
+
...stringList2(preferenceReplay?.["serviceConnectionIds"]),
|
|
249
|
+
...stringList2(diagnosticClosure?.["serviceConnectionIds"]),
|
|
250
|
+
...stringList2(serviceImpact?.["serviceConnectionIds"]),
|
|
251
|
+
...serviceConnectionIdsFromEvidence(args["serviceConnections"])
|
|
252
|
+
]);
|
|
253
|
+
}
|
|
254
|
+
function buildGoalOutcomeFeedbackV1({ args, goal, serviceConnectionIds }) {
|
|
255
|
+
const feedback = asRecord(args["outcomeFeedback"]) ?? {};
|
|
256
|
+
const correctionKind = cleanString2(feedback["correctionKind"]) ?? cleanString2(feedback["kind"]) ?? inferCorrectionKind(feedback);
|
|
257
|
+
const outcome = cleanString2(feedback["outcome"]) ?? cleanString2(feedback["status"]);
|
|
258
|
+
const before = cleanString2(feedback["before"]) ?? cleanString2(feedback["original"]);
|
|
259
|
+
const after = cleanString2(feedback["after"]) ?? cleanString2(feedback["rewrite"]) ?? cleanString2(feedback["humanRewrite"]) ?? cleanString2(feedback["corrected"]);
|
|
260
|
+
const stylePreference = cleanString2(feedback["stylePreference"]) ?? cleanString2(feedback["preference"]);
|
|
261
|
+
const rationale = cleanString2(feedback["rationale"]) ?? cleanString2(feedback["reason"]);
|
|
262
|
+
const acceptedRefs = collectAcceptedRefsV1(args, feedback);
|
|
263
|
+
const rejectedRefs = collectRejectedRefsV1(args, feedback);
|
|
264
|
+
const missingRefs = collectMissingRefsV1(args, feedback);
|
|
265
|
+
const evidenceRefs = uniqueStrings2([
|
|
266
|
+
...stringList2(args["evidenceRefs"]),
|
|
267
|
+
...stringList2(feedback["evidenceRefs"]),
|
|
268
|
+
...acceptedRefs,
|
|
269
|
+
...rejectedRefs,
|
|
270
|
+
...missingRefs,
|
|
271
|
+
...stringList2(args["exactRefs"])
|
|
272
|
+
]);
|
|
273
|
+
const goalSession = asRecord(args["goalSession"]);
|
|
274
|
+
const outcomeFeedbackRefs = uniqueStrings2([
|
|
275
|
+
...stringList2(args["outcomeFeedbackRefs"]),
|
|
276
|
+
...stringList2(feedback["outcomeFeedbackRefs"])
|
|
277
|
+
]);
|
|
278
|
+
const targetRefs = uniqueStrings2([
|
|
279
|
+
...evidenceRefs,
|
|
280
|
+
...stringList2(args["refs"]),
|
|
281
|
+
...stringList2(args["refIds"]),
|
|
282
|
+
...stringList2(args["selectedRefs"]),
|
|
283
|
+
...stringList2(args["requiredRefs"]),
|
|
284
|
+
...stringList2(args["candidateRefs"])
|
|
285
|
+
]).slice(0, COMPACT_REF_LIMIT);
|
|
286
|
+
const filePaths = collectGoalMemoryFilePathsV1([
|
|
287
|
+
args["changedFiles"],
|
|
288
|
+
args["paths"],
|
|
289
|
+
args["files"],
|
|
290
|
+
args["exactRefs"],
|
|
291
|
+
acceptedRefs,
|
|
292
|
+
rejectedRefs,
|
|
293
|
+
missingRefs,
|
|
294
|
+
evidenceRefs
|
|
295
|
+
]).slice(0, COMPACT_REF_LIMIT);
|
|
296
|
+
const taskRefs = uniqueStrings2([
|
|
297
|
+
...stringList2(args["validationRefs"]),
|
|
298
|
+
...stringList2(args["diffRefs"]),
|
|
299
|
+
...stringList2(args["codeTrailRefs"]),
|
|
300
|
+
...stringList2(args["prReviewRefs"]),
|
|
301
|
+
...outcomeFeedbackRefs
|
|
302
|
+
]).slice(0, COMPACT_REF_LIMIT);
|
|
303
|
+
const preferenceSignals = buildPreferenceSignals({ outcome, correctionKind, before, after, stylePreference, rationale, evidenceRefs });
|
|
304
|
+
const memoryCandidates = buildOutcomeMemoryCandidates({
|
|
305
|
+
goal,
|
|
306
|
+
goalSessionId: cleanString2(goalSession?.["goalSessionId"]),
|
|
307
|
+
activeGoalId: cleanString2(goalSession?.["activeGoalId"]),
|
|
308
|
+
parentGoalId: cleanString2(goalSession?.["parentGoalId"]),
|
|
309
|
+
supersedesGoalId: cleanString2(goalSession?.["supersedesGoalId"]),
|
|
310
|
+
correctionKind,
|
|
311
|
+
outcome,
|
|
312
|
+
after,
|
|
313
|
+
stylePreference,
|
|
314
|
+
rationale,
|
|
315
|
+
acceptedRefs,
|
|
316
|
+
evidenceRefs,
|
|
317
|
+
targetRefs,
|
|
318
|
+
filePaths,
|
|
319
|
+
taskRefs,
|
|
320
|
+
outcomeFeedbackRefs,
|
|
321
|
+
serviceConnectionIds
|
|
322
|
+
});
|
|
323
|
+
return removeUndefined({
|
|
324
|
+
kind: "rhei_code_goal_outcome_feedback",
|
|
325
|
+
schemaVersion: 1,
|
|
326
|
+
correctionKind,
|
|
327
|
+
outcome,
|
|
328
|
+
rationale,
|
|
329
|
+
evidenceRefs,
|
|
330
|
+
acceptedRefs,
|
|
331
|
+
rejectedRefs,
|
|
332
|
+
missingRefs,
|
|
333
|
+
preferenceSignals,
|
|
334
|
+
memoryCandidates,
|
|
335
|
+
serviceConnectionIds,
|
|
336
|
+
closedLoops: uniqueStrings2([
|
|
337
|
+
"feedback:outcome_captured",
|
|
338
|
+
memoryCandidates.length > 0 ? "feedback:memory_candidate_emitted" : undefined,
|
|
339
|
+
evidenceRefs.length > 0 ? "feedback:evidence_refs_linked" : undefined
|
|
340
|
+
]),
|
|
341
|
+
noMemoryWrite: true,
|
|
342
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
function buildGoalStewardDecisionV1({ args, goal }) {
|
|
346
|
+
const steering = asRecord(args["steering"]) ?? {};
|
|
347
|
+
const goalSession = asRecord(args["goalSession"]) ?? {};
|
|
348
|
+
const activeGoal = cleanString2(steering["activeGoal"]) ?? cleanString2(goalSession["activeGoal"]) ?? cleanString2(args["activeGoal"]);
|
|
349
|
+
const incomingGoal = cleanString2(steering["incomingGoal"]) ?? cleanString2(goalSession["incomingGoal"]) ?? goal;
|
|
350
|
+
const allowAppend = booleanValue(steering["allowAppend"]) ?? booleanValue(args["allowAppend"]) ?? false;
|
|
351
|
+
const forceNewGoal = booleanValue(steering["forceNewGoal"]) ?? booleanValue(args["forceNewGoal"]) ?? false;
|
|
352
|
+
const replaceActiveGoal = booleanValue(steering["replaceActiveGoal"]) ?? booleanValue(args["replaceActiveGoal"]) ?? false;
|
|
353
|
+
const similarity = activeGoal && incomingGoal ? goalSimilarity(activeGoal, incomingGoal) : undefined;
|
|
354
|
+
const decision = steeringDecision({ activeGoal, incomingGoal, allowAppend, forceNewGoal, replaceActiveGoal, similarity });
|
|
355
|
+
const reasonCodes = steeringReasonCodes({ activeGoal, incomingGoal, allowAppend, forceNewGoal, replaceActiveGoal, similarity, decision });
|
|
356
|
+
return removeUndefined({
|
|
357
|
+
kind: "rhei_code_goal_steering",
|
|
358
|
+
schemaVersion: 1,
|
|
359
|
+
decision,
|
|
360
|
+
policy: "latest_explicit_goal_wins_unless_append_is_explicit",
|
|
361
|
+
activeGoal,
|
|
362
|
+
incomingGoal,
|
|
363
|
+
activeGoalId: cleanString2(steering["activeGoalId"]) ?? cleanString2(goalSession["activeGoalId"]) ?? cleanString2(args["activeGoalId"]),
|
|
364
|
+
incomingGoalId: cleanString2(steering["incomingGoalId"]) ?? cleanString2(goalSession["incomingGoalId"]) ?? cleanString2(args["incomingGoalId"]),
|
|
365
|
+
parentGoalId: cleanString2(steering["parentGoalId"]) ?? cleanString2(goalSession["parentGoalId"]),
|
|
366
|
+
supersedesGoalId: cleanString2(steering["supersedesGoalId"]) ?? cleanString2(goalSession["supersedesGoalId"]),
|
|
367
|
+
similarity,
|
|
368
|
+
appendAllowed: allowAppend,
|
|
369
|
+
activeGoalShouldChange: decision === "start_goal" || decision === "branch_goal" || decision === "replace_active_goal",
|
|
370
|
+
requiresExplicitUserConfirmation: decision === "ask_for_goal_boundary" || decision === "branch_goal",
|
|
371
|
+
reasonCodes,
|
|
372
|
+
recommendedNextStep: steeringNextStep(decision),
|
|
373
|
+
serviceConnectionIds: collectGoalServiceConnectionIdsV1(args),
|
|
374
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
function buildGoalResumeV1({ args, goal, goalSession, serviceConnectionIds: baseServiceConnectionIds }) {
|
|
378
|
+
const resume = asRecord(args["resume"]) ?? {};
|
|
379
|
+
const normalizedSession = normalizedGoalSession(goalSession, goal, resume);
|
|
380
|
+
const serviceConnectionIds = uniqueStrings2([
|
|
381
|
+
...baseServiceConnectionIds,
|
|
382
|
+
...stringList2(resume["serviceConnectionIds"]),
|
|
383
|
+
...normalizedSession.serviceConnectionIds
|
|
384
|
+
]);
|
|
385
|
+
const exactRefs = uniqueStrings2([...stringList2(args["exactRefs"]), ...stringList2(resume["exactRefs"])]);
|
|
386
|
+
const evidenceRefs = collectGoalEvidenceRefsV1(args, resume);
|
|
387
|
+
const continuityPacket = buildGoalContinuityPacketV1({
|
|
388
|
+
goal,
|
|
389
|
+
goalSession: normalizedSession,
|
|
390
|
+
resume,
|
|
391
|
+
exactRefs,
|
|
392
|
+
evidenceRefs
|
|
393
|
+
});
|
|
394
|
+
const commitRefs = uniqueStrings2([...normalizedSession.commitRefs, ...stringList2(resume["commitRefs"])]);
|
|
395
|
+
return {
|
|
396
|
+
kind: "rhei_code_goal_resume",
|
|
397
|
+
schemaVersion: 1,
|
|
398
|
+
goalSession: normalizedSession,
|
|
399
|
+
goalSessionId: normalizedSession.goalSessionId,
|
|
400
|
+
activeGoalId: normalizedSession.activeGoalId,
|
|
401
|
+
parentGoalId: normalizedSession.parentGoalId,
|
|
402
|
+
supersedesGoalId: normalizedSession.supersedesGoalId,
|
|
403
|
+
continuityPacket,
|
|
404
|
+
intelligenceBackends: {
|
|
405
|
+
codeMarket: {
|
|
406
|
+
contextRunIds: uniqueStrings2([...normalizedSession.contextRunIds, ...stringList2(resume["contextRunIds"])]),
|
|
407
|
+
snapshotIds: uniqueStrings2([...normalizedSession.codeMarketSnapshotIds, ...stringList2(resume["codeMarketSnapshotIds"])])
|
|
408
|
+
},
|
|
409
|
+
codeTrail: { refs: uniqueStrings2([...normalizedSession.codeTrailRefs, ...stringList2(resume["codeTrailRefs"])]) },
|
|
410
|
+
prReview: { refs: uniqueStrings2([...normalizedSession.prReviewRefs, ...stringList2(resume["prReviewRefs"])]) },
|
|
411
|
+
git: { commitRefs },
|
|
412
|
+
repoIntelligence: { evidenceRefs: evidenceRefs.slice(0, COMPACT_REF_LIMIT) }
|
|
413
|
+
},
|
|
414
|
+
serviceConnectionIds,
|
|
415
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
function buildGoalContinuityPacketV1({
|
|
419
|
+
goal,
|
|
420
|
+
goalSession,
|
|
421
|
+
resume = {},
|
|
422
|
+
exactRefs = [],
|
|
423
|
+
evidenceRefs = [],
|
|
424
|
+
maxRefs = COMPACT_REF_LIMIT
|
|
425
|
+
}) {
|
|
426
|
+
const completedSteps = uniqueStrings2([
|
|
427
|
+
...goalSession.completedSteps,
|
|
428
|
+
...stringList2(resume["completedSteps"])
|
|
429
|
+
]);
|
|
430
|
+
const remainingSteps = uniqueStrings2([
|
|
431
|
+
...goalSession.remainingSteps,
|
|
432
|
+
...stringList2(resume["remainingSteps"])
|
|
433
|
+
]);
|
|
434
|
+
const commitRefs = uniqueStrings2([...goalSession.commitRefs, ...stringList2(resume["commitRefs"])]);
|
|
435
|
+
const validationRefs = uniqueStrings2([...goalSession.validationRefs, ...stringList2(resume["validationRefs"])]);
|
|
436
|
+
const outcomeFeedbackRefs = uniqueStrings2([...goalSession.outcomeFeedbackRefs, ...stringList2(resume["outcomeFeedbackRefs"])]);
|
|
437
|
+
const done = uniqueStrings2([
|
|
438
|
+
...completedSteps,
|
|
439
|
+
...commitRefs.map((ref) => `commit:${ref}`),
|
|
440
|
+
...validationRefs.map((ref) => `validation:${ref}`),
|
|
441
|
+
...outcomeFeedbackRefs.map((ref) => `outcome:${ref}`)
|
|
442
|
+
]);
|
|
443
|
+
const staleRefs = uniqueStrings2([...goalSession.staleRefs, ...stringList2(resume["staleRefs"])]);
|
|
444
|
+
const currentRefs = uniqueStrings2([...exactRefs, ...evidenceRefs]);
|
|
445
|
+
return removeUndefined({
|
|
446
|
+
schemaVersion: 1,
|
|
447
|
+
kind: "goal_continuity_packet",
|
|
448
|
+
goal,
|
|
449
|
+
done: done.slice(0, maxRefs),
|
|
450
|
+
doneOmitted: omittedAfterLimit(done.length, maxRefs),
|
|
451
|
+
currentRefs: currentRefs.slice(0, maxRefs),
|
|
452
|
+
currentRefsOmitted: omittedAfterLimit(currentRefs.length, maxRefs),
|
|
453
|
+
openQuestions: uniqueStrings2([...goalSession.openQuestions, ...stringList2(resume["openQuestions"])]),
|
|
454
|
+
remainingSteps,
|
|
455
|
+
staleRefs,
|
|
456
|
+
staleWarnings: staleRefs.map((ref) => `${ref} must be revalidated before reuse.`),
|
|
457
|
+
contextEngineering: "Resume from compact receipts and ranked deltas only; do not replay full transcripts into the next context window.",
|
|
458
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
function buildGoalIntelligenceCommitV1({ args, goal, goalSession, serviceConnectionIds: baseServiceConnectionIds }) {
|
|
462
|
+
const input = asRecord(args["intelligenceCommit"]) ?? {};
|
|
463
|
+
const normalizedSession = normalizedGoalSession(goalSession, goal, input);
|
|
464
|
+
const commitRefs = uniqueStrings2([...stringList2(input["commitRefs"]), ...normalizedSession.commitRefs]);
|
|
465
|
+
const contextRunIds = uniqueStrings2([...stringList2(input["contextRunIds"]), ...normalizedSession.contextRunIds]);
|
|
466
|
+
const codeMarketSnapshotIds = uniqueStrings2([...stringList2(input["codeMarketSnapshotIds"]), ...normalizedSession.codeMarketSnapshotIds]);
|
|
467
|
+
const codeTrailRefs = uniqueStrings2([...stringList2(input["codeTrailRefs"]), ...normalizedSession.codeTrailRefs]);
|
|
468
|
+
const prReviewRefs = uniqueStrings2([...stringList2(input["prReviewRefs"]), ...normalizedSession.prReviewRefs]);
|
|
469
|
+
const validationRefs = uniqueStrings2([...stringList2(input["validationRefs"]), ...normalizedSession.validationRefs]);
|
|
470
|
+
const outcomeFeedbackRefs = uniqueStrings2([...stringList2(input["outcomeFeedbackRefs"]), ...normalizedSession.outcomeFeedbackRefs]);
|
|
471
|
+
const evidenceRefs = uniqueStrings2([
|
|
472
|
+
...collectGoalEvidenceRefsV1(args, input),
|
|
473
|
+
...commitRefs.map((ref) => `git:${ref}`),
|
|
474
|
+
...validationRefs,
|
|
475
|
+
...codeTrailRefs,
|
|
476
|
+
...prReviewRefs,
|
|
477
|
+
...outcomeFeedbackRefs
|
|
478
|
+
]);
|
|
479
|
+
const intelligenceCommitId = cleanString2(input["intelligenceCommitId"]) ?? cleanString2(input["id"]) ?? `intel-commit:${goalStableHash({ goal, commitRefs, validationRefs, codeTrailRefs, prReviewRefs, evidenceRefs })}`;
|
|
480
|
+
return removeUndefined({
|
|
481
|
+
kind: "rhei_code_goal_intelligence_commit",
|
|
482
|
+
schemaVersion: 1,
|
|
483
|
+
intelligenceCommitId,
|
|
484
|
+
summary: cleanString2(input["summary"]) ?? "Report-only intelligence receipt linking source commits to context, validation, review, and outcome evidence.",
|
|
485
|
+
goal,
|
|
486
|
+
goalSession: normalizedSession,
|
|
487
|
+
gitCommitRefs: commitRefs,
|
|
488
|
+
contextRunIds,
|
|
489
|
+
codeMarketSnapshotIds,
|
|
490
|
+
codeTrailRefs,
|
|
491
|
+
prReviewRefs,
|
|
492
|
+
validationRefs,
|
|
493
|
+
outcomeFeedbackRefs,
|
|
494
|
+
evidenceRefs: evidenceRefs.slice(0, COMPACT_REF_LIMIT),
|
|
495
|
+
evidenceRefsOmitted: omittedAfterLimit(evidenceRefs.length, COMPACT_REF_LIMIT),
|
|
496
|
+
compareToGit: "Git records source diff history; this receipt records why-context, diagnostic, validation, PR review, service, and outcome evidence around that diff.",
|
|
497
|
+
serviceConnectionIds: uniqueStrings2([...baseServiceConnectionIds, ...stringList2(input["serviceConnectionIds"])]),
|
|
498
|
+
noSourceMutation: true,
|
|
499
|
+
noMemoryWrite: true,
|
|
500
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
function buildPreferenceReplayV1({ args, goal, serviceConnectionIds }) {
|
|
504
|
+
const replay = asRecord(args["preferenceReplay"]) ?? {};
|
|
505
|
+
const outcomeFeedback = buildGoalOutcomeFeedbackV1({ args, goal, serviceConnectionIds });
|
|
506
|
+
const preferences = uniqueStrings2([
|
|
507
|
+
...stringList2(replay["preferences"]),
|
|
508
|
+
cleanString2(replay["preference"]),
|
|
509
|
+
cleanString2(replay["stylePreference"]),
|
|
510
|
+
cleanString2(outcomeFeedback.rationale),
|
|
511
|
+
...outcomeFeedback.preferenceSignals.flatMap((signal) => signal.kind === "style_preference" ? [signal.summary] : [])
|
|
512
|
+
]);
|
|
513
|
+
const acceptedRefs = uniqueStrings2([
|
|
514
|
+
...stringList2(args["acceptedRefs"]),
|
|
515
|
+
...stringList2(replay["acceptedRefs"]),
|
|
516
|
+
...outcomeFeedback.acceptedRefs
|
|
517
|
+
]);
|
|
518
|
+
const rejectedRefs = uniqueStrings2([
|
|
519
|
+
...stringList2(args["rejectedRefs"]),
|
|
520
|
+
...stringList2(replay["rejectedRefs"]),
|
|
521
|
+
...outcomeFeedback.rejectedRefs
|
|
522
|
+
]);
|
|
523
|
+
const evidenceRefs = uniqueStrings2([
|
|
524
|
+
...collectGoalEvidenceRefsV1(args, replay),
|
|
525
|
+
...outcomeFeedback.evidenceRefs,
|
|
526
|
+
...acceptedRefs,
|
|
527
|
+
...rejectedRefs
|
|
528
|
+
]);
|
|
529
|
+
return removeUndefined({
|
|
530
|
+
kind: "rhei_code_goal_preference_replay",
|
|
531
|
+
schemaVersion: 1,
|
|
532
|
+
goal,
|
|
533
|
+
preferences,
|
|
534
|
+
acceptedRefs,
|
|
535
|
+
rejectedRefs,
|
|
536
|
+
memoryCandidates: outcomeFeedback.memoryCandidates,
|
|
537
|
+
replayPlan: [
|
|
538
|
+
"Bias future proposals toward accepted human rewrites and explicit style preferences.",
|
|
539
|
+
"Keep rejected refs as negative examples for ranking only.",
|
|
540
|
+
"Promote memory only through the governed memory path after repeated evidence."
|
|
541
|
+
],
|
|
542
|
+
evaluation: {
|
|
543
|
+
expectedSignals: uniqueStrings2([
|
|
544
|
+
preferences.length > 0 ? "style_preference_reused" : undefined,
|
|
545
|
+
outcomeFeedback.memoryCandidates.length > 0 ? "human_rewrite_pattern_matched" : undefined,
|
|
546
|
+
acceptedRefs.length > 0 ? "accepted_refs_ranked_higher" : undefined,
|
|
547
|
+
rejectedRefs.length > 0 ? "rejected_refs_ranked_lower" : undefined
|
|
548
|
+
]),
|
|
549
|
+
trialFootprintRefs: evidenceRefs.slice(0, COMPACT_REF_LIMIT),
|
|
550
|
+
trialFootprintRefsOmitted: omittedAfterLimit(evidenceRefs.length, COMPACT_REF_LIMIT),
|
|
551
|
+
status: "replay_plan_ready_report_only"
|
|
552
|
+
},
|
|
553
|
+
rankingBiasEvidence: {
|
|
554
|
+
status: "advisory_only_no_memory_write",
|
|
555
|
+
acceptedRefs,
|
|
556
|
+
rejectedRefs,
|
|
557
|
+
evidenceRefs: evidenceRefs.slice(0, COMPACT_REF_LIMIT)
|
|
558
|
+
},
|
|
559
|
+
serviceConnectionIds,
|
|
560
|
+
noMemoryWrite: true,
|
|
561
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
function buildDiagnosticClosureV1({ args, goal, serviceConnectionIds }) {
|
|
565
|
+
const closure = asRecord(args["diagnosticClosure"]) ?? {};
|
|
566
|
+
const diagnosticRefs = uniqueStrings2([...stringList2(closure["diagnosticRefs"]), ...stringList2(args["diagnosticRefs"])]);
|
|
567
|
+
const fixRefs = uniqueStrings2([...stringList2(closure["fixRefs"]), ...stringList2(args["fixRefs"])]);
|
|
568
|
+
const validationRefs = uniqueStrings2([
|
|
569
|
+
...stringList2(closure["validationRefs"]),
|
|
570
|
+
...stringList2(args["validationRefs"]),
|
|
571
|
+
...stringList2(asRecord(args["goalSession"])?.["validationRefs"])
|
|
572
|
+
]);
|
|
573
|
+
const outcome = cleanString2(closure["outcome"]) ?? cleanString2(closure["status"]) ?? cleanString2(args["outcome"]);
|
|
574
|
+
const evidenceRefs = uniqueStrings2([
|
|
575
|
+
...collectGoalEvidenceRefsV1(args, closure),
|
|
576
|
+
...diagnosticRefs,
|
|
577
|
+
...fixRefs,
|
|
578
|
+
...validationRefs
|
|
579
|
+
]);
|
|
580
|
+
const closed = validationRefs.length > 0 && CLOSED_OUTCOMES.has((outcome ?? "").toLowerCase());
|
|
581
|
+
const status = closed ? "closed_with_validation" : validationRefs.length > 0 ? "validation_linked" : "needs_validation";
|
|
582
|
+
return removeUndefined({
|
|
583
|
+
kind: "rhei_code_goal_diagnostic_closure",
|
|
584
|
+
schemaVersion: 1,
|
|
585
|
+
goal,
|
|
586
|
+
status,
|
|
587
|
+
outcome,
|
|
588
|
+
diagnosticRefs,
|
|
589
|
+
fixRefs,
|
|
590
|
+
validationRefs,
|
|
591
|
+
evidenceRefs: evidenceRefs.slice(0, COMPACT_REF_LIMIT),
|
|
592
|
+
evidenceRefsOmitted: omittedAfterLimit(evidenceRefs.length, COMPACT_REF_LIMIT),
|
|
593
|
+
closedLoops: closed ? ["diagnostic:validated_fix", "diagnostic:outcome_captured"] : [],
|
|
594
|
+
nextAction: closed ? {
|
|
595
|
+
tool: "rhei_code_goal",
|
|
596
|
+
mode: "intelligence_commit",
|
|
597
|
+
reason: "Diagnostic evidence has validation; emit a compact intelligence receipt for future resume and replay."
|
|
598
|
+
} : {
|
|
599
|
+
tool: "rhei_code_context_for_goal",
|
|
600
|
+
input: "evidenceIntake",
|
|
601
|
+
reason: "Validation evidence is still required before the diagnostic loop can close."
|
|
602
|
+
},
|
|
603
|
+
serviceConnectionIds,
|
|
604
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
function buildServiceImpactV1({ args, goal, serviceConnectionIds: baseServiceConnectionIds }) {
|
|
608
|
+
const impact = asRecord(args["serviceImpact"]) ?? {};
|
|
609
|
+
const serviceConnectionIds = uniqueStrings2([
|
|
610
|
+
...baseServiceConnectionIds,
|
|
611
|
+
...stringList2(impact["serviceConnectionIds"]),
|
|
612
|
+
...serviceConnectionIdsFromEvidence(args["serviceConnections"])
|
|
613
|
+
]);
|
|
614
|
+
const evidenceRefs = collectGoalEvidenceRefsV1(args, impact);
|
|
615
|
+
const impactedRefs = uniqueStrings2([
|
|
616
|
+
...stringList2(impact["impactedRefs"]),
|
|
617
|
+
...stringList2(impact["impactRefs"]),
|
|
618
|
+
...stringList2(args["exactRefs"]),
|
|
619
|
+
...evidenceRefs
|
|
620
|
+
]);
|
|
621
|
+
const backendRefs = uniqueStrings2(stringList2(impact["backendRefs"]));
|
|
622
|
+
const uiRefs = uniqueStrings2(stringList2(impact["uiRefs"]));
|
|
623
|
+
const testRefs = uniqueStrings2(stringList2(impact["testRefs"]));
|
|
624
|
+
const docsRefs = uniqueStrings2(stringList2(impact["docsRefs"]));
|
|
625
|
+
return removeUndefined({
|
|
626
|
+
kind: "rhei_code_goal_service_impact",
|
|
627
|
+
schemaVersion: 1,
|
|
628
|
+
goal,
|
|
629
|
+
serviceConnectionIds,
|
|
630
|
+
serviceConnectionRefs: uniqueStrings2([
|
|
631
|
+
...stringList2(impact["serviceConnectionRefs"]),
|
|
632
|
+
...serviceConnectionIds
|
|
633
|
+
]).slice(0, COMPACT_REF_LIMIT),
|
|
634
|
+
impactedRefs: impactedRefs.slice(0, COMPACT_REF_LIMIT),
|
|
635
|
+
impactedRefsOmitted: omittedAfterLimit(impactedRefs.length, COMPACT_REF_LIMIT),
|
|
636
|
+
impactedServices: serviceConnectionIds,
|
|
637
|
+
impactStatus: "evidence_linked_only",
|
|
638
|
+
promotionPath: "rhei_service_intelligence_for_goal",
|
|
639
|
+
nextSlice: {
|
|
640
|
+
backendRefs,
|
|
641
|
+
uiRefs,
|
|
642
|
+
testRefs,
|
|
643
|
+
docsRefs,
|
|
644
|
+
steps: [
|
|
645
|
+
"Run rhei_service_intelligence_for_goal with the same service evidence.",
|
|
646
|
+
"Choose the smallest backend, UI, test, or docs slice after service evidence is summarized.",
|
|
647
|
+
"Return validation refs to rhei_code_goal before any memory, service, or graph promotion path."
|
|
648
|
+
],
|
|
649
|
+
guardrails: [
|
|
650
|
+
"No connector sync from service_impact.",
|
|
651
|
+
"No service write from service_impact.",
|
|
652
|
+
"No graph mutation from service_impact."
|
|
653
|
+
]
|
|
654
|
+
},
|
|
655
|
+
nextAction: {
|
|
656
|
+
tool: "rhei_service_intelligence_for_goal",
|
|
657
|
+
reason: "Service impact is evidence-linked only; use the service intelligence bridge for impacted service/resource mapping."
|
|
658
|
+
},
|
|
659
|
+
gates: {
|
|
660
|
+
noConnectorSync: true,
|
|
661
|
+
noServiceWrite: true,
|
|
662
|
+
noGraphMutation: true,
|
|
663
|
+
requiresGovernedServiceIntelligencePromotion: true
|
|
664
|
+
},
|
|
665
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
function buildGoalFeedbackLoopsV1(args) {
|
|
669
|
+
const loops = [];
|
|
670
|
+
if (args.mode === "edit") {
|
|
671
|
+
loops.push({
|
|
672
|
+
kind: "edit_loop",
|
|
673
|
+
status: "transaction_receipts_ready",
|
|
674
|
+
nextEvidenceLane: "rhei_code_goal mode=outcome_feedback or rhei_code_trail_export",
|
|
675
|
+
summary: "Edit transaction linked context, reads, proposal, dry-run, diff, validation, AgentEditSession receipt, and Trail evidence without apply authority."
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
if (args.mode === "verify") {
|
|
679
|
+
loops.push({
|
|
680
|
+
kind: "verify_loop",
|
|
681
|
+
status: "search_read_absence_receipts_ready",
|
|
682
|
+
nextEvidenceLane: "rhei_code_goal mode=edit or rhei_code_goal mode=report",
|
|
683
|
+
summary: "Verify transaction linked scoped search, exact reads, searched scopes/counts/confidence, caveats, absence proof, and Trail evidence without source writes."
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
if (args.mode === "trail") {
|
|
687
|
+
loops.push({
|
|
688
|
+
kind: "trail_loop",
|
|
689
|
+
status: "session_history_receipts_ready",
|
|
690
|
+
nextEvidenceLane: "rhei_code_goal mode=outcome_feedback or rhei_code_goal mode=report",
|
|
691
|
+
summary: "Trail transaction linked session reads, proposals, dry-runs, diffs, reverse diffs, validations, human decisions, replay refs, and CodeTrail export evidence without apply authority."
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
if (args.mode === "learn_from_outcome") {
|
|
695
|
+
loops.push({
|
|
696
|
+
kind: "learn_from_outcome_loop",
|
|
697
|
+
status: "replay_evidence_ready",
|
|
698
|
+
nextEvidenceLane: "rhei_code_goal mode=preference_replay or governed memory promotion",
|
|
699
|
+
summary: "Accepted/rejected outcomes and human rewrites are captured as replay evidence and memory candidates only; memory promotion remains explicitly gated."
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
if (args.mode === "report") {
|
|
703
|
+
loops.push({
|
|
704
|
+
kind: "report_loop",
|
|
705
|
+
status: "markdown_diff_receipt_ready",
|
|
706
|
+
nextEvidenceLane: "rhei_code_goal mode=intelligence_commit",
|
|
707
|
+
summary: "Markdown report output includes a diff preview and receipt; report writes are explicit and grant no product or apply authority."
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
if (args.mode === "diagnose") {
|
|
711
|
+
loops.push({
|
|
712
|
+
kind: "diagnostic_loop",
|
|
713
|
+
status: "closed_when_validation_evidence_returns",
|
|
714
|
+
nextEvidenceLane: "evidenceIntake",
|
|
715
|
+
summary: "Feed validation/CI/PR review output back into rhei_code_goal mode=diagnose or rhei_code_context_for_goal evidenceIntake."
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
if (args.mode === "outcome_feedback") {
|
|
719
|
+
loops.push({
|
|
720
|
+
kind: "outcome_feedback_loop",
|
|
721
|
+
status: "captured_report_only",
|
|
722
|
+
nextEvidenceLane: "rhei_code_review mode=generate_memory_candidates or governed memory promotion",
|
|
723
|
+
summary: "Human rewrite/style/outcome feedback is represented as memory candidates without writing memory."
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
if (args.mode === "steer") {
|
|
727
|
+
loops.push({
|
|
728
|
+
kind: "steering_loop",
|
|
729
|
+
status: "goal_boundary_decided",
|
|
730
|
+
summary: "New instructions branch or replace unless append is explicit or similarity is high."
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
if (args.mode === "resume") {
|
|
734
|
+
loops.push({ kind: "resume_loop", status: "continuity_captured_report_only", summary: "Resume metadata links the active goal to evidence without hidden execution." });
|
|
735
|
+
}
|
|
736
|
+
if (args.mode === "intelligence_commit") {
|
|
737
|
+
loops.push({ kind: "intelligence_commit_loop", status: "commit_evidence_captured_report_only", summary: "Commit, validation, PR, and Code Trail refs are linked as evidence only." });
|
|
738
|
+
}
|
|
739
|
+
if (args.mode === "preference_replay") {
|
|
740
|
+
loops.push({ kind: "preference_replay_loop", status: "replay_captured_report_only", summary: "Preference signals can be evaluated without writing memory." });
|
|
741
|
+
}
|
|
742
|
+
if (args.mode === "diagnostic_closure") {
|
|
743
|
+
loops.push({ kind: "diagnostic_closure_loop", status: "closure_captured_report_only", summary: "Diagnostics, fixes, validation, and outcomes are linked without authority escalation." });
|
|
744
|
+
}
|
|
745
|
+
if (args.mode === "service_impact") {
|
|
746
|
+
loops.push({ kind: "service_impact_loop", status: "service_impact_captured_report_only", summary: "Service impact evidence is linked without connector writes or graph mutation." });
|
|
747
|
+
}
|
|
748
|
+
if (args.mode === "start") {
|
|
749
|
+
loops.push({
|
|
750
|
+
kind: "goal_start_loop",
|
|
751
|
+
status: "lifecycle_start_captured_report_only",
|
|
752
|
+
nextEvidenceLane: "rhei_code_goal mode=checkpoint",
|
|
753
|
+
summary: "Goal lifecycle start links bounded context and ContextPacket evidence without creating task authority."
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
if (args.mode === "checkpoint") {
|
|
757
|
+
loops.push({
|
|
758
|
+
kind: "goal_checkpoint_loop",
|
|
759
|
+
status: "lifecycle_checkpoint_captured_report_only",
|
|
760
|
+
nextEvidenceLane: "rhei_code_goal mode=finish or validation evidence",
|
|
761
|
+
summary: "Goal lifecycle checkpoint captures edit, validation, PR, service, and CodeTrail refs as interim report-only evidence."
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
if (args.mode === "finish") {
|
|
765
|
+
loops.push({
|
|
766
|
+
kind: "goal_finish_loop",
|
|
767
|
+
status: "lifecycle_finish_captured_report_only",
|
|
768
|
+
nextEvidenceLane: "explicit CodeTrail import or governed memory promotion path",
|
|
769
|
+
summary: "Goal lifecycle finish emits final report-only evidence and soft observations without writing truth or memory."
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
if (args.mode === "context") {
|
|
773
|
+
loops.push({
|
|
774
|
+
kind: "context_loop",
|
|
775
|
+
status: "bounded_context_ready",
|
|
776
|
+
summary: "Use the compact context handoff, then return diagnostics or outcomes to this central goal surface."
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
return loops;
|
|
780
|
+
}
|
|
781
|
+
function collectGoalEvidenceRefsV1(args, extra) {
|
|
782
|
+
const goalSession = asRecord(args["goalSession"]);
|
|
783
|
+
const records = [
|
|
784
|
+
args,
|
|
785
|
+
goalSession,
|
|
786
|
+
asRecord(args["outcomeFeedback"]),
|
|
787
|
+
asRecord(args["steering"]),
|
|
788
|
+
asRecord(args["resume"]),
|
|
789
|
+
asRecord(args["intelligenceCommit"]),
|
|
790
|
+
asRecord(args["preferenceReplay"]),
|
|
791
|
+
asRecord(args["diagnosticClosure"]),
|
|
792
|
+
asRecord(args["serviceImpact"]),
|
|
793
|
+
extra
|
|
794
|
+
].filter((record) => Boolean(record));
|
|
795
|
+
const fields = [
|
|
796
|
+
"exactRefs",
|
|
797
|
+
"evidenceRefs",
|
|
798
|
+
"acceptedRefs",
|
|
799
|
+
"rejectedRefs",
|
|
800
|
+
"missingRefs",
|
|
801
|
+
"primaryRefs",
|
|
802
|
+
"diagnosticRefs",
|
|
803
|
+
"fixRefs",
|
|
804
|
+
"validationRefs",
|
|
805
|
+
"commitRefs",
|
|
806
|
+
"contextRunIds",
|
|
807
|
+
"codeMarketSnapshotIds",
|
|
808
|
+
"codeTrailRefs",
|
|
809
|
+
"prReviewRefs",
|
|
810
|
+
"outcomeFeedbackRefs",
|
|
811
|
+
"serviceConnectionRefs",
|
|
812
|
+
"impactedRefs",
|
|
813
|
+
"impactRefs"
|
|
814
|
+
];
|
|
815
|
+
return uniqueStrings2(records.flatMap((record) => fields.flatMap((field) => stringList2(record[field]))));
|
|
816
|
+
}
|
|
817
|
+
function collectAcceptedRefsV1(args, input) {
|
|
818
|
+
return uniqueStrings2([
|
|
819
|
+
...stringList2(args["acceptedRefs"]),
|
|
820
|
+
...stringList2(input?.["acceptedRefs"])
|
|
821
|
+
]);
|
|
822
|
+
}
|
|
823
|
+
function collectRejectedRefsV1(args, input) {
|
|
824
|
+
return uniqueStrings2([
|
|
825
|
+
...stringList2(args["rejectedRefs"]),
|
|
826
|
+
...stringList2(input?.["rejectedRefs"])
|
|
827
|
+
]);
|
|
828
|
+
}
|
|
829
|
+
function collectMissingRefsV1(args, input) {
|
|
830
|
+
return uniqueStrings2([
|
|
831
|
+
...stringList2(args["missingRefs"]),
|
|
832
|
+
...stringList2(input?.["missingRefs"])
|
|
833
|
+
]);
|
|
834
|
+
}
|
|
835
|
+
function serviceConnectionIdsFromEvidence(value) {
|
|
836
|
+
return arrayValue(value).flatMap((item) => {
|
|
837
|
+
const record = asRecord(item);
|
|
838
|
+
if (!record)
|
|
839
|
+
return [];
|
|
840
|
+
const source = asRecord(record["source"]);
|
|
841
|
+
const target = asRecord(record["target"]);
|
|
842
|
+
const sourceId = cleanString2(source?.["id"]);
|
|
843
|
+
const targetId = cleanString2(target?.["id"]);
|
|
844
|
+
return uniqueStrings2([
|
|
845
|
+
cleanString2(record["id"]),
|
|
846
|
+
cleanString2(record["serviceConnectionId"]),
|
|
847
|
+
cleanString2(record["dedupeKey"]),
|
|
848
|
+
sourceId && targetId ? `${sourceId}->${targetId}` : undefined
|
|
849
|
+
]);
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
function inferCorrectionKind(feedback) {
|
|
853
|
+
if (cleanString2(feedback["after"]) || cleanString2(feedback["rewrite"]) || cleanString2(feedback["humanRewrite"]) || cleanString2(feedback["corrected"])) {
|
|
854
|
+
return "human_rewrite";
|
|
855
|
+
}
|
|
856
|
+
if (cleanString2(feedback["stylePreference"]) || cleanString2(feedback["preference"]))
|
|
857
|
+
return "style_preference";
|
|
858
|
+
if (cleanString2(feedback["outcome"]) || cleanString2(feedback["status"]))
|
|
859
|
+
return "outcome";
|
|
860
|
+
return "correction";
|
|
861
|
+
}
|
|
862
|
+
function buildPreferenceSignals(args) {
|
|
863
|
+
const signals = [];
|
|
864
|
+
if (args.outcome) {
|
|
865
|
+
signals.push({
|
|
866
|
+
kind: "outcome",
|
|
867
|
+
value: args.outcome,
|
|
868
|
+
summary: "Outcome feedback captured for later proposal ranking."
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
if (args.after) {
|
|
872
|
+
signals.push({
|
|
873
|
+
kind: "human_rewrite",
|
|
874
|
+
correctionKind: args.correctionKind,
|
|
875
|
+
beforePresent: Boolean(args.before),
|
|
876
|
+
afterPresent: true,
|
|
877
|
+
summary: "Human rewrite captured as a style/preference signal, not as automatic memory."
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
if (args.stylePreference) {
|
|
881
|
+
signals.push({
|
|
882
|
+
kind: "style_preference",
|
|
883
|
+
summary: args.stylePreference
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
if (args.rationale) {
|
|
887
|
+
signals.push({
|
|
888
|
+
kind: "rationale",
|
|
889
|
+
summary: args.rationale
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
if (args.evidenceRefs.length > 0) {
|
|
893
|
+
signals.push({
|
|
894
|
+
kind: "evidence_link",
|
|
895
|
+
refs: args.evidenceRefs.slice(0, COMPACT_REF_LIMIT),
|
|
896
|
+
refsOmitted: omittedAfterLimit(args.evidenceRefs.length, COMPACT_REF_LIMIT)
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
return signals;
|
|
900
|
+
}
|
|
901
|
+
function buildOutcomeMemoryCandidates(args) {
|
|
902
|
+
const candidates = [];
|
|
903
|
+
if (args.after || args.stylePreference) {
|
|
904
|
+
const candidateKind = args.stylePreference ? "style_preference" : "code_rewrite_preference";
|
|
905
|
+
const title = args.stylePreference ? "Human style preference" : "Human rewrite preference";
|
|
906
|
+
const summary = args.stylePreference ?? "Human supplied a corrected rewrite; promote only through the governed memory path if this pattern repeats.";
|
|
907
|
+
const identity = buildGoalMemoryCandidateIdentityV1({
|
|
908
|
+
sourceKind: "outcome_feedback",
|
|
909
|
+
candidateKind,
|
|
910
|
+
title,
|
|
911
|
+
summary,
|
|
912
|
+
normalizedRule: summary,
|
|
913
|
+
goal: args.goal,
|
|
914
|
+
goalSessionId: args.goalSessionId,
|
|
915
|
+
activeGoalId: args.activeGoalId,
|
|
916
|
+
parentGoalId: args.parentGoalId,
|
|
917
|
+
supersedesGoalId: args.supersedesGoalId,
|
|
918
|
+
sourceIds: goalMemoryCandidateSourceIdsV1([args.outcomeFeedbackRefs, args.evidenceRefs]),
|
|
919
|
+
targetRefs: args.targetRefs,
|
|
920
|
+
filePaths: args.filePaths,
|
|
921
|
+
evidenceRefs: args.evidenceRefs,
|
|
922
|
+
taskRefs: args.taskRefs,
|
|
923
|
+
serviceConnectionIds: args.serviceConnectionIds
|
|
924
|
+
});
|
|
925
|
+
const status = args.evidenceRefs.length > 0 ? "ready_for_review" : "candidate";
|
|
926
|
+
candidates.push(removeUndefined({
|
|
927
|
+
kind: "memory_candidate",
|
|
928
|
+
candidateKind,
|
|
929
|
+
title,
|
|
930
|
+
summary,
|
|
931
|
+
normalizedRule: summary,
|
|
932
|
+
goal: args.goal,
|
|
933
|
+
correctionKind: args.correctionKind,
|
|
934
|
+
evidenceRefs: args.evidenceRefs.slice(0, COMPACT_REF_LIMIT),
|
|
935
|
+
serviceConnectionIds: args.serviceConnectionIds.slice(0, COMPACT_REF_LIMIT),
|
|
936
|
+
...identity,
|
|
937
|
+
sourceKind: "outcome_feedback",
|
|
938
|
+
sourceIds: goalMemoryCandidateSourceIdsV1([args.outcomeFeedbackRefs, args.evidenceRefs]),
|
|
939
|
+
goalSessionId: args.goalSessionId,
|
|
940
|
+
activeGoalId: args.activeGoalId,
|
|
941
|
+
parentGoalId: args.parentGoalId,
|
|
942
|
+
supersedesGoalId: args.supersedesGoalId,
|
|
943
|
+
targetRefs: args.targetRefs.slice(0, COMPACT_REF_LIMIT),
|
|
944
|
+
filePaths: args.filePaths.slice(0, COMPACT_REF_LIMIT),
|
|
945
|
+
taskRefs: args.taskRefs.slice(0, COMPACT_REF_LIMIT),
|
|
946
|
+
outcomeFeedbackRefs: args.outcomeFeedbackRefs.slice(0, COMPACT_REF_LIMIT),
|
|
947
|
+
confidence: status === "ready_for_review" ? 0.8 : 0.55,
|
|
948
|
+
rank: status === "ready_for_review" ? 80 : 55,
|
|
949
|
+
status,
|
|
950
|
+
promotionStatus: status,
|
|
951
|
+
promotionBlockers: status === "ready_for_review" ? [] : ["promotion:requires_evidence_refs"],
|
|
952
|
+
reasonCodes: uniqueStrings2([
|
|
953
|
+
`goal_memory:${candidateKind}`,
|
|
954
|
+
"goal_memory:human_feedback",
|
|
955
|
+
status === "ready_for_review" ? "goal_memory:evidence_linked" : "goal_memory:candidate_only"
|
|
956
|
+
]),
|
|
957
|
+
candidateOnly: true,
|
|
958
|
+
rankingUseOnly: true,
|
|
959
|
+
requiresUserConfirmation: true,
|
|
960
|
+
requiresRepeatedEvidence: status !== "ready_for_review",
|
|
961
|
+
requiresOmPolicyCheck: true,
|
|
962
|
+
memoryWrite: false,
|
|
963
|
+
truthWrite: false,
|
|
964
|
+
noMemoryWrite: true,
|
|
965
|
+
promotionRequired: true,
|
|
966
|
+
writeAuthority: false,
|
|
967
|
+
promotion: {
|
|
968
|
+
candidateOnly: true,
|
|
969
|
+
rankingUseOnly: true,
|
|
970
|
+
status,
|
|
971
|
+
eligibleForPromotionReview: status === "ready_for_review",
|
|
972
|
+
requiresUserConfirmation: true,
|
|
973
|
+
requiresRepeatedEvidence: status !== "ready_for_review",
|
|
974
|
+
requiresOmPolicyCheck: true,
|
|
975
|
+
promotionRequired: true,
|
|
976
|
+
writeAuthority: false,
|
|
977
|
+
memoryWrite: false,
|
|
978
|
+
truthWrite: false,
|
|
979
|
+
noMemoryWrite: true,
|
|
980
|
+
blockedReasons: status === "ready_for_review" ? [] : ["promotion:requires_evidence_refs"]
|
|
981
|
+
},
|
|
982
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
983
|
+
}));
|
|
984
|
+
}
|
|
985
|
+
if (args.outcome || args.rationale) {
|
|
986
|
+
const title = "Outcome feedback pattern";
|
|
987
|
+
const summary = args.rationale ?? `Outcome recorded: ${args.outcome}.`;
|
|
988
|
+
const status = "needs_more_evidence";
|
|
989
|
+
const identity = buildGoalMemoryCandidateIdentityV1({
|
|
990
|
+
sourceKind: "outcome_feedback",
|
|
991
|
+
candidateKind: "outcome_pattern",
|
|
992
|
+
title,
|
|
993
|
+
summary,
|
|
994
|
+
normalizedRule: summary,
|
|
995
|
+
goal: args.goal,
|
|
996
|
+
goalSessionId: args.goalSessionId,
|
|
997
|
+
activeGoalId: args.activeGoalId,
|
|
998
|
+
parentGoalId: args.parentGoalId,
|
|
999
|
+
supersedesGoalId: args.supersedesGoalId,
|
|
1000
|
+
sourceIds: goalMemoryCandidateSourceIdsV1([args.outcomeFeedbackRefs, args.acceptedRefs, args.evidenceRefs]),
|
|
1001
|
+
targetRefs: args.targetRefs,
|
|
1002
|
+
filePaths: args.filePaths,
|
|
1003
|
+
evidenceRefs: args.evidenceRefs,
|
|
1004
|
+
taskRefs: args.taskRefs,
|
|
1005
|
+
serviceConnectionIds: args.serviceConnectionIds
|
|
1006
|
+
});
|
|
1007
|
+
candidates.push(removeUndefined({
|
|
1008
|
+
kind: "memory_candidate",
|
|
1009
|
+
candidateKind: "outcome_pattern",
|
|
1010
|
+
title,
|
|
1011
|
+
summary,
|
|
1012
|
+
normalizedRule: summary,
|
|
1013
|
+
goal: args.goal,
|
|
1014
|
+
evidenceRefs: args.evidenceRefs.slice(0, COMPACT_REF_LIMIT),
|
|
1015
|
+
serviceConnectionIds: args.serviceConnectionIds.slice(0, COMPACT_REF_LIMIT),
|
|
1016
|
+
...identity,
|
|
1017
|
+
sourceKind: "outcome_feedback",
|
|
1018
|
+
sourceIds: goalMemoryCandidateSourceIdsV1([args.outcomeFeedbackRefs, args.acceptedRefs, args.evidenceRefs]),
|
|
1019
|
+
goalSessionId: args.goalSessionId,
|
|
1020
|
+
activeGoalId: args.activeGoalId,
|
|
1021
|
+
parentGoalId: args.parentGoalId,
|
|
1022
|
+
supersedesGoalId: args.supersedesGoalId,
|
|
1023
|
+
targetRefs: args.targetRefs.slice(0, COMPACT_REF_LIMIT),
|
|
1024
|
+
filePaths: args.filePaths.slice(0, COMPACT_REF_LIMIT),
|
|
1025
|
+
taskRefs: args.taskRefs.slice(0, COMPACT_REF_LIMIT),
|
|
1026
|
+
outcomeFeedbackRefs: args.outcomeFeedbackRefs.slice(0, COMPACT_REF_LIMIT),
|
|
1027
|
+
confidence: CLOSED_OUTCOMES.has(args.outcome ?? "") || args.acceptedRefs.length > 0 ? 0.55 : 0.35,
|
|
1028
|
+
rank: CLOSED_OUTCOMES.has(args.outcome ?? "") || args.acceptedRefs.length > 0 ? 55 : 35,
|
|
1029
|
+
status,
|
|
1030
|
+
promotionStatus: status,
|
|
1031
|
+
promotionBlockers: ["promotion:outcome_feedback_requires_repeated_evidence"],
|
|
1032
|
+
reasonCodes: uniqueStrings2([
|
|
1033
|
+
"goal_memory:outcome_pattern",
|
|
1034
|
+
"goal_memory:needs_more_evidence",
|
|
1035
|
+
args.acceptedRefs.length > 0 ? "goal_memory:accepted_refs_linked" : undefined
|
|
1036
|
+
]),
|
|
1037
|
+
candidateOnly: true,
|
|
1038
|
+
rankingUseOnly: true,
|
|
1039
|
+
requiresUserConfirmation: true,
|
|
1040
|
+
requiresRepeatedEvidence: true,
|
|
1041
|
+
requiresOmPolicyCheck: true,
|
|
1042
|
+
memoryWrite: false,
|
|
1043
|
+
truthWrite: false,
|
|
1044
|
+
noMemoryWrite: true,
|
|
1045
|
+
promotionRequired: true,
|
|
1046
|
+
writeAuthority: false,
|
|
1047
|
+
promotion: {
|
|
1048
|
+
candidateOnly: true,
|
|
1049
|
+
rankingUseOnly: true,
|
|
1050
|
+
status,
|
|
1051
|
+
eligibleForPromotionReview: false,
|
|
1052
|
+
requiresUserConfirmation: true,
|
|
1053
|
+
requiresRepeatedEvidence: true,
|
|
1054
|
+
requiresOmPolicyCheck: true,
|
|
1055
|
+
promotionRequired: true,
|
|
1056
|
+
writeAuthority: false,
|
|
1057
|
+
memoryWrite: false,
|
|
1058
|
+
truthWrite: false,
|
|
1059
|
+
noMemoryWrite: true,
|
|
1060
|
+
blockedReasons: ["promotion:outcome_feedback_requires_repeated_evidence"]
|
|
1061
|
+
},
|
|
1062
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
1063
|
+
}));
|
|
1064
|
+
}
|
|
1065
|
+
return candidates;
|
|
1066
|
+
}
|
|
1067
|
+
function steeringDecision(args) {
|
|
1068
|
+
if (!args.incomingGoal)
|
|
1069
|
+
return "ask_for_goal_boundary";
|
|
1070
|
+
if (!args.activeGoal)
|
|
1071
|
+
return "start_goal";
|
|
1072
|
+
if (args.replaceActiveGoal)
|
|
1073
|
+
return "replace_active_goal";
|
|
1074
|
+
if (args.forceNewGoal)
|
|
1075
|
+
return "branch_goal";
|
|
1076
|
+
if (args.allowAppend)
|
|
1077
|
+
return "continue_active_goal";
|
|
1078
|
+
if ((args.similarity ?? 0) >= 0.62)
|
|
1079
|
+
return "continue_active_goal";
|
|
1080
|
+
if ((args.similarity ?? 0) <= 0.28)
|
|
1081
|
+
return "branch_goal";
|
|
1082
|
+
return "ask_for_goal_boundary";
|
|
1083
|
+
}
|
|
1084
|
+
function steeringReasonCodes(args) {
|
|
1085
|
+
const reasons = ["steering:latest_explicit_goal_wins"];
|
|
1086
|
+
if (!args.incomingGoal)
|
|
1087
|
+
reasons.push("steering:missing_incoming_goal");
|
|
1088
|
+
if (!args.activeGoal)
|
|
1089
|
+
reasons.push("steering:no_active_goal");
|
|
1090
|
+
if (args.allowAppend)
|
|
1091
|
+
reasons.push("steering:append_explicitly_allowed");
|
|
1092
|
+
if (!args.allowAppend)
|
|
1093
|
+
reasons.push("steering:append_requires_explicit_intent");
|
|
1094
|
+
if (args.forceNewGoal)
|
|
1095
|
+
reasons.push("steering:force_new_goal");
|
|
1096
|
+
if (args.replaceActiveGoal)
|
|
1097
|
+
reasons.push("steering:replace_active_goal_requested");
|
|
1098
|
+
if (typeof args.similarity === "number") {
|
|
1099
|
+
if (args.similarity <= 0.28)
|
|
1100
|
+
reasons.push("steering:low_goal_similarity");
|
|
1101
|
+
else if (args.similarity >= 0.62)
|
|
1102
|
+
reasons.push("steering:high_goal_similarity");
|
|
1103
|
+
else
|
|
1104
|
+
reasons.push("steering:ambiguous_goal_similarity");
|
|
1105
|
+
}
|
|
1106
|
+
reasons.push(`steering:decision:${args.decision}`);
|
|
1107
|
+
return uniqueStrings2(reasons);
|
|
1108
|
+
}
|
|
1109
|
+
function steeringNextStep(decision) {
|
|
1110
|
+
if (decision === "continue_active_goal")
|
|
1111
|
+
return "Continue only because the goal is similar or append was explicit.";
|
|
1112
|
+
if (decision === "replace_active_goal")
|
|
1113
|
+
return "Start a new active goal that supersedes the prior goal.";
|
|
1114
|
+
if (decision === "branch_goal")
|
|
1115
|
+
return "Create a visible child/branch goal instead of appending silently to the active goal.";
|
|
1116
|
+
if (decision === "start_goal")
|
|
1117
|
+
return "Start a new goal session.";
|
|
1118
|
+
return "Ask the operator whether this instruction continues, replaces, or branches from the active goal.";
|
|
1119
|
+
}
|
|
1120
|
+
function normalizedGoalSession(goalSession, goal, extra) {
|
|
1121
|
+
const base = goalSession ?? buildGoalSessionV1({ args: {}, goal });
|
|
1122
|
+
const goalSessionId = cleanString2(extra["goalSessionId"]) ?? base.goalSessionId ?? `goal-session:${goalStableHash({ goal, activeGoal: base.activeGoal, incomingGoal: base.incomingGoal, parentGoalId: base.parentGoalId })}`;
|
|
1123
|
+
return removeUndefined({
|
|
1124
|
+
schemaVersion: 1,
|
|
1125
|
+
kind: "goal_session",
|
|
1126
|
+
goalSessionId,
|
|
1127
|
+
activeGoalId: cleanString2(extra["activeGoalId"]) ?? base.activeGoalId,
|
|
1128
|
+
incomingGoalId: cleanString2(extra["incomingGoalId"]) ?? base.incomingGoalId,
|
|
1129
|
+
parentGoalId: cleanString2(extra["parentGoalId"]) ?? base.parentGoalId,
|
|
1130
|
+
supersedesGoalId: cleanString2(extra["supersedesGoalId"]) ?? base.supersedesGoalId,
|
|
1131
|
+
activeGoal: cleanString2(extra["activeGoal"]) ?? base.activeGoal,
|
|
1132
|
+
incomingGoal: cleanString2(extra["incomingGoal"]) ?? base.incomingGoal ?? goal,
|
|
1133
|
+
contextRunIds: uniqueStrings2([...base.contextRunIds, ...stringList2(extra["contextRunIds"])]),
|
|
1134
|
+
codeMarketSnapshotIds: uniqueStrings2([...base.codeMarketSnapshotIds, ...stringList2(extra["codeMarketSnapshotIds"])]),
|
|
1135
|
+
codeWorkroomSessionId: cleanString2(extra["codeWorkroomSessionId"]) ?? base.codeWorkroomSessionId,
|
|
1136
|
+
codeTrailRefs: uniqueStrings2([...base.codeTrailRefs, ...stringList2(extra["codeTrailRefs"])]),
|
|
1137
|
+
prReviewRefs: uniqueStrings2([...base.prReviewRefs, ...stringList2(extra["prReviewRefs"])]),
|
|
1138
|
+
commitRefs: uniqueStrings2([...base.commitRefs, ...stringList2(extra["commitRefs"])]),
|
|
1139
|
+
validationRefs: uniqueStrings2([...base.validationRefs, ...stringList2(extra["validationRefs"])]),
|
|
1140
|
+
outcomeFeedbackRefs: uniqueStrings2([...base.outcomeFeedbackRefs, ...stringList2(extra["outcomeFeedbackRefs"])]),
|
|
1141
|
+
serviceConnectionIds: uniqueStrings2([...base.serviceConnectionIds, ...stringList2(extra["serviceConnectionIds"])]),
|
|
1142
|
+
staleRefs: uniqueStrings2([...base.staleRefs, ...stringList2(extra["staleRefs"])]),
|
|
1143
|
+
openQuestions: uniqueStrings2([...base.openQuestions, ...stringList2(extra["openQuestions"])]),
|
|
1144
|
+
completedSteps: uniqueStrings2([...base.completedSteps, ...stringList2(extra["completedSteps"])]),
|
|
1145
|
+
remainingSteps: uniqueStrings2([...base.remainingSteps, ...stringList2(extra["remainingSteps"])]),
|
|
1146
|
+
boundaryPolicy: "new_goal_requires_explicit_steer_decision",
|
|
1147
|
+
refsOnly: true,
|
|
1148
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
function goalStableHash(value) {
|
|
1152
|
+
let text;
|
|
1153
|
+
try {
|
|
1154
|
+
text = JSON.stringify(value, Object.keys(asRecord(value) ?? {}).sort());
|
|
1155
|
+
} catch {
|
|
1156
|
+
text = String(value);
|
|
1157
|
+
}
|
|
1158
|
+
let hash = 2166136261;
|
|
1159
|
+
for (let index = 0;index < text.length; index += 1) {
|
|
1160
|
+
hash ^= text.charCodeAt(index);
|
|
1161
|
+
hash = Math.imul(hash, 16777619);
|
|
1162
|
+
}
|
|
1163
|
+
return (hash >>> 0).toString(16).padStart(8, "0").slice(0, 8);
|
|
1164
|
+
}
|
|
1165
|
+
function goalSimilarity(left, right) {
|
|
1166
|
+
const leftTokens = goalTokens(left);
|
|
1167
|
+
const rightTokens = goalTokens(right);
|
|
1168
|
+
if (leftTokens.size === 0 || rightTokens.size === 0)
|
|
1169
|
+
return 0;
|
|
1170
|
+
let intersection = 0;
|
|
1171
|
+
for (const token of leftTokens) {
|
|
1172
|
+
if (rightTokens.has(token))
|
|
1173
|
+
intersection += 1;
|
|
1174
|
+
}
|
|
1175
|
+
const union = new Set([...leftTokens, ...rightTokens]).size;
|
|
1176
|
+
return Math.round(intersection / union * 100) / 100;
|
|
1177
|
+
}
|
|
1178
|
+
function goalTokens(value) {
|
|
1179
|
+
const stopWords = new Set(["a", "an", "and", "are", "as", "be", "by", "for", "in", "is", "it", "of", "on", "or", "the", "this", "to", "with"]);
|
|
1180
|
+
return new Set(value.toLowerCase().split(/[^a-z0-9_]+/g).map((token) => token.trim()).filter((token) => token.length > 2 && !stopWords.has(token)));
|
|
1181
|
+
}
|
|
1182
|
+
function booleanValue(value) {
|
|
1183
|
+
return typeof value === "boolean" ? value : undefined;
|
|
1184
|
+
}
|
|
1185
|
+
function stringList2(value) {
|
|
1186
|
+
return stringArray(value) ?? [];
|
|
1187
|
+
}
|
|
1188
|
+
function stringArray(value) {
|
|
1189
|
+
if (!Array.isArray(value))
|
|
1190
|
+
return;
|
|
1191
|
+
const output = value.map((item) => cleanString2(item)).filter((item) => Boolean(item));
|
|
1192
|
+
return output.length > 0 ? output : undefined;
|
|
1193
|
+
}
|
|
1194
|
+
function uniqueStrings2(values) {
|
|
1195
|
+
return Array.from(new Set(values.map((value) => value?.trim()).filter((value) => Boolean(value))));
|
|
1196
|
+
}
|
|
1197
|
+
function cleanString2(value) {
|
|
1198
|
+
if (typeof value !== "string")
|
|
1199
|
+
return;
|
|
1200
|
+
const text = value.trim();
|
|
1201
|
+
return text.length > 0 ? text : undefined;
|
|
1202
|
+
}
|
|
1203
|
+
function asRecord(value) {
|
|
1204
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
1205
|
+
}
|
|
1206
|
+
function arrayValue(value) {
|
|
1207
|
+
return Array.isArray(value) ? value : [];
|
|
1208
|
+
}
|
|
1209
|
+
function omittedAfterLimit(total, limit) {
|
|
1210
|
+
const omitted = Math.max(0, total - limit);
|
|
1211
|
+
return omitted > 0 ? omitted : undefined;
|
|
1212
|
+
}
|
|
1213
|
+
function removeUndefined(value) {
|
|
1214
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
1215
|
+
}
|
|
1216
|
+
// ../core/src/goalLifecycle/types.ts
|
|
1217
|
+
var GOAL_LIFECYCLE_SCHEMA_VERSION = 1;
|
|
1218
|
+
// ../core/src/goalLifecycle/progressSignals.ts
|
|
1219
|
+
function detectSearchLoopV1(args) {
|
|
1220
|
+
const byQuery = new Map;
|
|
1221
|
+
for (const item of args.searchQueries) {
|
|
1222
|
+
const query = normalizeQuery(item.query);
|
|
1223
|
+
if (!query)
|
|
1224
|
+
continue;
|
|
1225
|
+
byQuery.set(query, [...byQuery.get(query) ?? [], { query, at: item.at }]);
|
|
1226
|
+
}
|
|
1227
|
+
for (const [query, occurrences] of byQuery) {
|
|
1228
|
+
if (occurrences.length < 3)
|
|
1229
|
+
continue;
|
|
1230
|
+
const sorted = occurrences.sort((left, right) => left.at - right.at);
|
|
1231
|
+
const first = sorted[0]?.at ?? 0;
|
|
1232
|
+
const last = sorted[sorted.length - 1]?.at ?? first;
|
|
1233
|
+
const changedBetween = args.changeTimestamps.some((at) => at > first && at < last);
|
|
1234
|
+
if (changedBetween)
|
|
1235
|
+
continue;
|
|
1236
|
+
return signal("search_loop", "warning", {
|
|
1237
|
+
repeatedQuery: query,
|
|
1238
|
+
repeatCount: occurrences.length
|
|
1239
|
+
}, "consider_escalation");
|
|
1240
|
+
}
|
|
1241
|
+
return null;
|
|
1242
|
+
}
|
|
1243
|
+
function detectNoProgressCheckpointsV1(args) {
|
|
1244
|
+
const span = consecutiveNoGrowthSpan(args.checkpoints, (checkpoint) => [
|
|
1245
|
+
...setKey(checkpoint.changedFiles),
|
|
1246
|
+
...setKey(checkpoint.validationRefs).map((ref) => `validation:${ref}`)
|
|
1247
|
+
]);
|
|
1248
|
+
if (span < 2)
|
|
1249
|
+
return null;
|
|
1250
|
+
return signal("no_progress_checkpoints", span >= 3 ? "warning" : "info", { checkpointSpan: span }, span >= 3 ? "consider_escalation" : "continue");
|
|
1251
|
+
}
|
|
1252
|
+
function detectValidationStuckV1(args) {
|
|
1253
|
+
let span = 1;
|
|
1254
|
+
let repeated = [];
|
|
1255
|
+
for (let index = 1;index < args.checkpoints.length; index += 1) {
|
|
1256
|
+
const previous = new Set(args.checkpoints[index - 1]?.failingValidationRefs ?? []);
|
|
1257
|
+
const current = setKey(args.checkpoints[index]?.failingValidationRefs ?? []);
|
|
1258
|
+
const overlap = current.filter((ref) => previous.has(ref));
|
|
1259
|
+
if (overlap.length > 0) {
|
|
1260
|
+
span += 1;
|
|
1261
|
+
repeated = overlap;
|
|
1262
|
+
} else {
|
|
1263
|
+
span = 1;
|
|
1264
|
+
repeated = [];
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
if (span < 2 || repeated.length === 0)
|
|
1268
|
+
return null;
|
|
1269
|
+
return signal("validation_stuck", "warning", {
|
|
1270
|
+
checkpointSpan: span,
|
|
1271
|
+
failingValidationRefs: repeated
|
|
1272
|
+
}, "consider_escalation");
|
|
1273
|
+
}
|
|
1274
|
+
function buildGoalProgressObservationsV1(inputs) {
|
|
1275
|
+
const checkpoints = (inputs.checkpoints ?? []).map((checkpoint) => ({
|
|
1276
|
+
changedFiles: checkpoint.changedFiles ?? [],
|
|
1277
|
+
validationRefs: checkpoint.validationRefs ?? [],
|
|
1278
|
+
failingValidationRefs: checkpoint.failingValidationRefs ?? []
|
|
1279
|
+
}));
|
|
1280
|
+
const signals = [
|
|
1281
|
+
inputs.searchQueries ? detectSearchLoopV1({ searchQueries: inputs.searchQueries, changeTimestamps: inputs.changeTimestamps ?? [] }) : null,
|
|
1282
|
+
checkpoints.length > 0 ? detectNoProgressCheckpointsV1({ checkpoints }) : null,
|
|
1283
|
+
checkpoints.length > 0 ? detectValidationStuckV1({ checkpoints }) : null
|
|
1284
|
+
].filter((item) => Boolean(item));
|
|
1285
|
+
return signals.map((progressSignal, index) => ({
|
|
1286
|
+
kind: "goal_lifecycle_observation",
|
|
1287
|
+
observationKind: "progress_observation",
|
|
1288
|
+
observationId: `goal-progress:${progressSignal.signal}:${index}`,
|
|
1289
|
+
title: progressSignal.signal.replace(/_/g, " "),
|
|
1290
|
+
summary: progressSignal.recommendation === "consider_escalation" ? "Progress signal suggests considering escalation." : "Progress signal suggests continuing with the current approach.",
|
|
1291
|
+
targetRefs: [],
|
|
1292
|
+
filePaths: [],
|
|
1293
|
+
evidenceRefs: progressSignal.evidence.failingValidationRefs ?? [],
|
|
1294
|
+
serviceConnectionIds: [],
|
|
1295
|
+
confidence: progressSignal.severity === "warning" ? 0.8 : 0.55,
|
|
1296
|
+
rank: progressSignal.severity === "warning" ? 70 : 45,
|
|
1297
|
+
reasonCodes: [`goal_progress:${progressSignal.signal}`, "goal_progress:advisory_only"],
|
|
1298
|
+
progressSignal,
|
|
1299
|
+
promotion: {
|
|
1300
|
+
candidateOnly: true,
|
|
1301
|
+
rankingUseOnly: true,
|
|
1302
|
+
eligibleForPromotionReview: false,
|
|
1303
|
+
requiresUserConfirmation: true,
|
|
1304
|
+
requiresRepeatedEvidence: true,
|
|
1305
|
+
requiresOmPolicyCheck: true,
|
|
1306
|
+
writeAuthority: false,
|
|
1307
|
+
memoryWrite: false,
|
|
1308
|
+
truthWrite: false,
|
|
1309
|
+
blockedReasons: ["progress_signal:no_authority"]
|
|
1310
|
+
},
|
|
1311
|
+
noAuthority: true
|
|
1312
|
+
}));
|
|
1313
|
+
}
|
|
1314
|
+
function signal(signalName, severity, evidence, recommendation) {
|
|
1315
|
+
return {
|
|
1316
|
+
kind: "goal_progress_signal",
|
|
1317
|
+
schemaVersion: GOAL_LIFECYCLE_SCHEMA_VERSION,
|
|
1318
|
+
signal: signalName,
|
|
1319
|
+
severity,
|
|
1320
|
+
evidence,
|
|
1321
|
+
recommendation,
|
|
1322
|
+
noAuthority: true
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
function normalizeQuery(query) {
|
|
1326
|
+
return query.trim().toLowerCase().replace(/\s+/g, " ");
|
|
1327
|
+
}
|
|
1328
|
+
function setKey(values) {
|
|
1329
|
+
return [...new Set(values.map((value) => value.trim()).filter(Boolean))].sort();
|
|
1330
|
+
}
|
|
1331
|
+
function consecutiveNoGrowthSpan(items, keyFor) {
|
|
1332
|
+
let span = 1;
|
|
1333
|
+
for (let index = 1;index < items.length; index += 1) {
|
|
1334
|
+
const previous = new Set(keyFor(items[index - 1]));
|
|
1335
|
+
const current = keyFor(items[index]);
|
|
1336
|
+
const grew = current.some((value) => !previous.has(value));
|
|
1337
|
+
span = grew ? 1 : span + 1;
|
|
1338
|
+
}
|
|
1339
|
+
return span;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// ../core/src/goalLifecycle/builders.ts
|
|
1343
|
+
var COMPACT_REF_LIMIT2 = 12;
|
|
1344
|
+
var MAX_OBSERVATIONS = 12;
|
|
1345
|
+
var MAX_MEMORY_CANDIDATES = 12;
|
|
1346
|
+
var MAX_FILE_OBSERVATION_CANDIDATES = 50;
|
|
1347
|
+
var UNSAFE_KEY_PATTERN = /(^|_|\b)(rawtranscript|transcript|messages|rawoutput|commandoutput|stdout|stderr|secret|apikey|api_key|token|memorycontent|providercall)(\b|_|$)/i;
|
|
1348
|
+
function buildGoalLifecycleV1({
|
|
1349
|
+
args,
|
|
1350
|
+
stage = lifecycleStageFromArgs(args),
|
|
1351
|
+
goal,
|
|
1352
|
+
goalSession,
|
|
1353
|
+
contextPacket,
|
|
1354
|
+
serviceConnectionIds = collectGoalServiceConnectionIdsV1(args),
|
|
1355
|
+
generatedAt,
|
|
1356
|
+
maxObservations = MAX_OBSERVATIONS,
|
|
1357
|
+
progressInputs
|
|
1358
|
+
}) {
|
|
1359
|
+
const normalizedSession = goalSession ?? buildGoalSessionV1({ args, goal });
|
|
1360
|
+
const stageArgs = lifecycleStageArgs(args, stage);
|
|
1361
|
+
const contextSummary = contextPacket ? summarizeContextPacket(contextPacket) : undefined;
|
|
1362
|
+
const evidence = collectLifecycleEvidence({
|
|
1363
|
+
args,
|
|
1364
|
+
stage,
|
|
1365
|
+
stageArgs,
|
|
1366
|
+
goalSession: normalizedSession,
|
|
1367
|
+
contextPacketSummary: contextSummary,
|
|
1368
|
+
serviceConnectionIds
|
|
1369
|
+
});
|
|
1370
|
+
const codeTrailUse = buildGoalLifecycleCodeTrailUseV1(evidence);
|
|
1371
|
+
const status = evaluateEvidenceStatus({ stage, contextSummary, evidence, codeTrailUse });
|
|
1372
|
+
const finalClaimPolicy = buildFinalClaimPolicy(status, evidence);
|
|
1373
|
+
const evidenceStatusDetail = buildEvidenceStatusDetail({ status, evidence, contextSummary, finalClaimPolicy });
|
|
1374
|
+
const taskLinks = buildTaskLinks(evidence, normalizedSession);
|
|
1375
|
+
const observations = buildGoalLifecycleObservationsV1({
|
|
1376
|
+
goal,
|
|
1377
|
+
status,
|
|
1378
|
+
evidence,
|
|
1379
|
+
contextSummary,
|
|
1380
|
+
codeTrailUse,
|
|
1381
|
+
maxObservations,
|
|
1382
|
+
progressInputs
|
|
1383
|
+
});
|
|
1384
|
+
const rankingHints = buildObservationRankingHintsV1(observations.visible);
|
|
1385
|
+
const feedbackLoops = buildLifecycleFeedbackLoops(stage);
|
|
1386
|
+
const lifecycleId = `goal-lifecycle:${stableHash2({
|
|
1387
|
+
stage,
|
|
1388
|
+
goal,
|
|
1389
|
+
goalSessionId: normalizedSession.goalSessionId,
|
|
1390
|
+
contextPacketId: contextSummary?.packetId,
|
|
1391
|
+
changedFiles: evidence.changedFiles,
|
|
1392
|
+
validationRefs: evidence.validationRefs,
|
|
1393
|
+
diffRefs: evidence.diffRefs,
|
|
1394
|
+
codeTrailRefs: evidence.codeTrailRefs,
|
|
1395
|
+
status
|
|
1396
|
+
})}`;
|
|
1397
|
+
const memoryCandidates = buildGoalLifecycleMemoryCandidatesV1({
|
|
1398
|
+
lifecycleId,
|
|
1399
|
+
stage,
|
|
1400
|
+
goal,
|
|
1401
|
+
goalSession: normalizedSession,
|
|
1402
|
+
status,
|
|
1403
|
+
observations: observations.visible,
|
|
1404
|
+
taskLinks,
|
|
1405
|
+
evidence
|
|
1406
|
+
});
|
|
1407
|
+
return removeUndefined2({
|
|
1408
|
+
kind: "rhei_code_goal_lifecycle",
|
|
1409
|
+
schemaVersion: 1,
|
|
1410
|
+
lifecycleId,
|
|
1411
|
+
stage,
|
|
1412
|
+
phase: stage,
|
|
1413
|
+
status: lifecycleStatusForStage(stage, status),
|
|
1414
|
+
goal,
|
|
1415
|
+
goalSession: normalizedSession,
|
|
1416
|
+
goalSessionId: normalizedSession.goalSessionId,
|
|
1417
|
+
activeGoalId: normalizedSession.activeGoalId,
|
|
1418
|
+
parentGoalId: normalizedSession.parentGoalId,
|
|
1419
|
+
supersedesGoalId: normalizedSession.supersedesGoalId,
|
|
1420
|
+
repoPath: cleanString3(args["repoPath"]),
|
|
1421
|
+
projectId: cleanString3(args["projectId"]),
|
|
1422
|
+
repoId: cleanString3(args["repoId"]),
|
|
1423
|
+
evidenceStatus: status,
|
|
1424
|
+
evidenceStatusDetail,
|
|
1425
|
+
evidenceStatusReasonCodes: evidenceStatusReasonCodes(status, evidence, contextSummary, codeTrailUse),
|
|
1426
|
+
taskLinks,
|
|
1427
|
+
contextPacket: contextSummary,
|
|
1428
|
+
codeTrailUse,
|
|
1429
|
+
finalClaimPolicy,
|
|
1430
|
+
observations: observations.visible,
|
|
1431
|
+
observationsOmitted: omittedAfterLimit2(observations.total, maxObservations),
|
|
1432
|
+
memoryCandidates: memoryCandidates.slice(0, MAX_MEMORY_CANDIDATES),
|
|
1433
|
+
memoryCandidatesOmitted: omittedAfterLimit2(memoryCandidates.length, MAX_MEMORY_CANDIDATES),
|
|
1434
|
+
rankingHints: rankingHints.slice(0, COMPACT_REF_LIMIT2),
|
|
1435
|
+
rankingHintsOmitted: omittedAfterLimit2(rankingHints.length, COMPACT_REF_LIMIT2),
|
|
1436
|
+
nextAction: nextActionForStatus(stage, status),
|
|
1437
|
+
feedbackLoops,
|
|
1438
|
+
generatedAt,
|
|
1439
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
function buildGoalStartLifecycleV1(args) {
|
|
1443
|
+
return buildGoalLifecycleV1({ ...args, stage: "start" });
|
|
1444
|
+
}
|
|
1445
|
+
function buildGoalCheckpointLifecycleV1(args) {
|
|
1446
|
+
return buildGoalLifecycleV1({ ...args, stage: "checkpoint" });
|
|
1447
|
+
}
|
|
1448
|
+
function buildGoalFinishLifecycleV1(args) {
|
|
1449
|
+
return buildGoalLifecycleV1({ ...args, stage: "finish" });
|
|
1450
|
+
}
|
|
1451
|
+
function buildGoalLifecycleCodeTrailUseV1(evidence) {
|
|
1452
|
+
if (evidence.hasUnsafePayload) {
|
|
1453
|
+
return {
|
|
1454
|
+
status: "blocked_unsafe_payload",
|
|
1455
|
+
codeTrailRefs: [],
|
|
1456
|
+
codeChangeStoryRefs: [],
|
|
1457
|
+
blockers: ["goal_lifecycle:blocked_unsafe_payload"],
|
|
1458
|
+
noAuthority: true
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
if (evidence.codeTrailImportRefs.length > 0 || evidence.codeTrailRefs.length > 0) {
|
|
1462
|
+
return removeUndefined2({
|
|
1463
|
+
status: evidence.stageArgs["durableImportExplicit"] === true ? "imported_by_explicit_durable_path" : "linked_existing_import",
|
|
1464
|
+
importId: evidence.codeTrailImportRefs[0],
|
|
1465
|
+
codeTrailImportId: evidence.codeTrailImportRefs[0],
|
|
1466
|
+
trailHash: cleanString3(evidence.stageArgs["trailHash"]),
|
|
1467
|
+
sourceMcpRequestId: cleanString3(evidence.stageArgs["sourceMcpRequestId"]),
|
|
1468
|
+
sourceMcpRunId: cleanString3(evidence.stageArgs["sourceMcpRunId"]),
|
|
1469
|
+
codeTrailRefs: evidence.codeTrailRefs,
|
|
1470
|
+
codeChangeStoryRefs: evidence.codeChangeStoryRefs,
|
|
1471
|
+
blockers: [],
|
|
1472
|
+
noAuthority: true
|
|
1473
|
+
});
|
|
1474
|
+
}
|
|
1475
|
+
if (evidence.stage === "finish" && (evidence.diffRefs.length > 0 || evidence.changedFiles.length > 0) && (evidence.validationRefs.length > 0 || evidence.hasValidationResult || evidence.hasExecutionReceipt)) {
|
|
1476
|
+
const candidateRef = `code-trail-import-candidate:${stableHash2({
|
|
1477
|
+
changedFiles: evidence.changedFiles,
|
|
1478
|
+
validationRefs: evidence.validationRefs,
|
|
1479
|
+
diffRefs: evidence.diffRefs,
|
|
1480
|
+
receiptRefs: evidence.receiptRefs
|
|
1481
|
+
})}`;
|
|
1482
|
+
return {
|
|
1483
|
+
status: "import_candidate_emitted",
|
|
1484
|
+
codeTrailRefs: [],
|
|
1485
|
+
codeChangeStoryRefs: [],
|
|
1486
|
+
importCandidateRef: candidateRef,
|
|
1487
|
+
importCandidateSummary: {
|
|
1488
|
+
entryCount: Math.max(1, evidence.changedFiles.length + evidence.validationRefs.length),
|
|
1489
|
+
linkCount: evidence.evidenceRefs.length,
|
|
1490
|
+
gapCount: evidence.missingProofRefs.length,
|
|
1491
|
+
truncationCount: evidence.truncatedRefs.length,
|
|
1492
|
+
safeForImport: true
|
|
1493
|
+
},
|
|
1494
|
+
blockers: [],
|
|
1495
|
+
noAuthority: true
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
return {
|
|
1499
|
+
status: "unavailable",
|
|
1500
|
+
codeTrailRefs: [],
|
|
1501
|
+
codeChangeStoryRefs: [],
|
|
1502
|
+
blockers: evidence.stage === "finish" ? ["goal_lifecycle:missing_code_trail_use"] : [],
|
|
1503
|
+
noAuthority: true
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
function collectLifecycleEvidence(args) {
|
|
1507
|
+
const agentEditSession = asRecord2(args.stageArgs["agentEditSession"]) ?? asRecord2(args.args["agentEditSession"]) ?? asRecord2(args.args["agentEditSessionOutput"]);
|
|
1508
|
+
const validationResult = asRecord2(args.stageArgs["validationResult"]) ?? asRecord2(args.args["validationResult"]);
|
|
1509
|
+
const executionReceipt = asRecord2(args.stageArgs["executionReceipt"]) ?? asRecord2(args.args["executionReceipt"]);
|
|
1510
|
+
const changedFiles = uniqueStrings3([
|
|
1511
|
+
...stringList3(args.args["changedFiles"]),
|
|
1512
|
+
...stringList3(args.stageArgs["changedFiles"]),
|
|
1513
|
+
...stringList3(agentEditSession?.["changedFiles"]),
|
|
1514
|
+
...stringList3(agentEditSession?.["primaryEditFiles"])
|
|
1515
|
+
]);
|
|
1516
|
+
const finalDiffRef = cleanString3(args.stageArgs["finalDiffRef"]) ?? cleanString3(args.args["finalDiffRef"]) ?? cleanString3(agentEditSession?.["finalDiffRef"]);
|
|
1517
|
+
const reverseDiffRef = cleanString3(args.stageArgs["reverseDiffRef"]) ?? cleanString3(args.args["reverseDiffRef"]) ?? cleanString3(agentEditSession?.["reverseDiffRef"]);
|
|
1518
|
+
const diffRefs = uniqueStrings3([
|
|
1519
|
+
...stringList3(args.args["diffRefs"]),
|
|
1520
|
+
...stringList3(args.stageArgs["diffRefs"]),
|
|
1521
|
+
...stringList3(agentEditSession?.["diffRefs"]),
|
|
1522
|
+
finalDiffRef,
|
|
1523
|
+
reverseDiffRef
|
|
1524
|
+
]);
|
|
1525
|
+
const validationRefs = uniqueStrings3([
|
|
1526
|
+
...args.goalSession.validationRefs,
|
|
1527
|
+
...stringList3(args.args["validationRefs"]),
|
|
1528
|
+
...stringList3(args.stageArgs["validationRefs"]),
|
|
1529
|
+
...stringList3(agentEditSession?.["validationRefs"]),
|
|
1530
|
+
cleanString3(validationResult?.["ref"]),
|
|
1531
|
+
cleanString3(validationResult?.["receiptRef"])
|
|
1532
|
+
]);
|
|
1533
|
+
const codeTrailImportRefs = uniqueStrings3([
|
|
1534
|
+
cleanString3(args.args["codeTrailImportRef"]),
|
|
1535
|
+
cleanString3(args.stageArgs["codeTrailImportRef"]),
|
|
1536
|
+
cleanString3(agentEditSession?.["codeTrailImportRef"])
|
|
1537
|
+
]);
|
|
1538
|
+
const codeTrailRefs = uniqueStrings3([
|
|
1539
|
+
...args.goalSession.codeTrailRefs,
|
|
1540
|
+
...stringList3(args.args["codeTrailRefs"]),
|
|
1541
|
+
...stringList3(args.stageArgs["codeTrailRefs"]),
|
|
1542
|
+
...stringList3(agentEditSession?.["codeTrailRefs"]),
|
|
1543
|
+
...codeTrailImportRefs
|
|
1544
|
+
]);
|
|
1545
|
+
const prReviewRefs = uniqueStrings3([
|
|
1546
|
+
...args.goalSession.prReviewRefs,
|
|
1547
|
+
...stringList3(args.args["prReviewRefs"]),
|
|
1548
|
+
...stringList3(args.stageArgs["prReviewRefs"]),
|
|
1549
|
+
cleanString3(args.stageArgs["prSnapshotId"]),
|
|
1550
|
+
cleanString3(args.stageArgs["reviewRoomId"])
|
|
1551
|
+
]);
|
|
1552
|
+
const receiptRefs = uniqueStrings3([
|
|
1553
|
+
...stringList3(args.args["receiptRefs"]),
|
|
1554
|
+
...stringList3(args.stageArgs["receiptRefs"]),
|
|
1555
|
+
cleanString3(executionReceipt?.["receiptId"]),
|
|
1556
|
+
cleanString3(executionReceipt?.["executionReceiptId"])
|
|
1557
|
+
]);
|
|
1558
|
+
const staleRefs = uniqueStrings3([
|
|
1559
|
+
...args.goalSession.staleRefs,
|
|
1560
|
+
...stringList3(args.args["staleRefs"]),
|
|
1561
|
+
...stringList3(args.stageArgs["staleRefs"])
|
|
1562
|
+
]);
|
|
1563
|
+
const truncatedRefs = uniqueStrings3([
|
|
1564
|
+
...stringList3(args.args["truncatedRefs"]),
|
|
1565
|
+
...stringList3(args.stageArgs["truncatedRefs"]),
|
|
1566
|
+
...stringList3(args.stageArgs["truncation"]),
|
|
1567
|
+
args.contextPacketSummary?.truncated ? args.contextPacketSummary.packetId : undefined
|
|
1568
|
+
]);
|
|
1569
|
+
const fallbackStatus = fallbackStatusValue(cleanString3(args.stageArgs["fallbackStatus"]) ?? cleanString3(args.args["fallbackStatus"]));
|
|
1570
|
+
const evidenceRefs = uniqueStrings3([
|
|
1571
|
+
...collectGoalEvidenceRefsV1(args.args, args.stageArgs),
|
|
1572
|
+
...validationRefs,
|
|
1573
|
+
...diffRefs,
|
|
1574
|
+
...receiptRefs,
|
|
1575
|
+
...codeTrailRefs,
|
|
1576
|
+
...prReviewRefs,
|
|
1577
|
+
...changedFiles
|
|
1578
|
+
]);
|
|
1579
|
+
return {
|
|
1580
|
+
stage: args.stage,
|
|
1581
|
+
stageArgs: args.stageArgs,
|
|
1582
|
+
goalSession: args.goalSession,
|
|
1583
|
+
changedFiles,
|
|
1584
|
+
validationRefs,
|
|
1585
|
+
diffRefs,
|
|
1586
|
+
codeTrailRefs,
|
|
1587
|
+
codeTrailImportRefs,
|
|
1588
|
+
codeChangeStoryRefs: uniqueStrings3([
|
|
1589
|
+
...stringList3(args.args["codeChangeStoryRefs"]),
|
|
1590
|
+
...stringList3(args.stageArgs["codeChangeStoryRefs"])
|
|
1591
|
+
]),
|
|
1592
|
+
prReviewRefs,
|
|
1593
|
+
receiptRefs,
|
|
1594
|
+
serviceConnectionIds: uniqueStrings3([
|
|
1595
|
+
...args.serviceConnectionIds,
|
|
1596
|
+
...args.goalSession.serviceConnectionIds,
|
|
1597
|
+
...stringList3(args.stageArgs["serviceConnectionIds"])
|
|
1598
|
+
]),
|
|
1599
|
+
staleRefs,
|
|
1600
|
+
truncatedRefs,
|
|
1601
|
+
missingProofRefs: uniqueStrings3([
|
|
1602
|
+
...stringList3(args.args["missingProofRefs"]),
|
|
1603
|
+
...stringList3(args.stageArgs["missingProofRefs"])
|
|
1604
|
+
]),
|
|
1605
|
+
fallbackRefs: uniqueStrings3([
|
|
1606
|
+
...stringList3(args.args["fallbackRefs"]),
|
|
1607
|
+
...stringList3(args.stageArgs["fallbackRefs"])
|
|
1608
|
+
]),
|
|
1609
|
+
fallbackStatus,
|
|
1610
|
+
hasValidationResult: Boolean(validationResult),
|
|
1611
|
+
hasExecutionReceipt: Boolean(executionReceipt),
|
|
1612
|
+
hasNoChangeProof: args.stageArgs["noChangeProof"] === true || args.args["noChangeProof"] === true,
|
|
1613
|
+
hasActiveEditSession: Boolean(agentEditSession && !["done", "completed", "failed", "blocked"].includes(cleanString3(agentEditSession["status"]) ?? "")),
|
|
1614
|
+
hasUnsafePayload: hasUnsafeLifecyclePayload(args.stageArgs) || hasUnsafeLifecyclePayload(args.args),
|
|
1615
|
+
evidenceRefs
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
function evaluateEvidenceStatus(args) {
|
|
1619
|
+
if (args.evidence.hasUnsafePayload)
|
|
1620
|
+
return "blocked_unsafe_payload";
|
|
1621
|
+
if (args.stage === "start") {
|
|
1622
|
+
if ((args.contextSummary?.contentSliceCount ?? 0) > 0)
|
|
1623
|
+
return "context_ready";
|
|
1624
|
+
return "planning_only";
|
|
1625
|
+
}
|
|
1626
|
+
if (args.stage === "finish") {
|
|
1627
|
+
const hasValidation = args.evidence.validationRefs.length > 0 || args.evidence.hasValidationResult || args.evidence.hasExecutionReceipt;
|
|
1628
|
+
const hasChangeProof = args.evidence.changedFiles.length === 0 ? args.evidence.hasNoChangeProof || args.evidence.diffRefs.length > 0 : args.evidence.diffRefs.length > 0;
|
|
1629
|
+
const hasTrailUse = args.codeTrailUse.status === "linked_existing_import" || args.codeTrailUse.status === "import_candidate_emitted" || args.codeTrailUse.status === "imported_by_explicit_durable_path";
|
|
1630
|
+
if (!hasValidation || !hasChangeProof || !hasTrailUse || args.evidence.missingProofRefs.length > 0)
|
|
1631
|
+
return "blocked_missing_proof";
|
|
1632
|
+
if (args.evidence.staleRefs.length > 0 || args.evidence.truncatedRefs.length > 0)
|
|
1633
|
+
return "blocked_stale_or_truncated";
|
|
1634
|
+
return "finish_ready_report_only";
|
|
1635
|
+
}
|
|
1636
|
+
if (args.evidence.staleRefs.length > 0 || args.evidence.truncatedRefs.length > 0)
|
|
1637
|
+
return "blocked_stale_or_truncated";
|
|
1638
|
+
if (args.stage === "checkpoint") {
|
|
1639
|
+
if (args.evidence.validationRefs.length > 0 || args.evidence.hasValidationResult)
|
|
1640
|
+
return "validation_linked";
|
|
1641
|
+
if (args.evidence.hasActiveEditSession)
|
|
1642
|
+
return "work_in_progress";
|
|
1643
|
+
if (args.evidence.changedFiles.length > 0 || args.evidence.diffRefs.length > 0 || args.evidence.prReviewRefs.length > 0)
|
|
1644
|
+
return "partial_evidence";
|
|
1645
|
+
return "blocked_missing_proof";
|
|
1646
|
+
}
|
|
1647
|
+
return args.evidence.validationRefs.length > 0 ? "validation_linked" : "partial_evidence";
|
|
1648
|
+
}
|
|
1649
|
+
function buildFinalClaimPolicy(status, evidence) {
|
|
1650
|
+
const blockers = uniqueStrings3([
|
|
1651
|
+
status.startsWith("blocked_") ? status : undefined,
|
|
1652
|
+
...evidence.missingProofRefs.map((ref) => `missing:${ref}`),
|
|
1653
|
+
...evidence.staleRefs.map((ref) => `stale:${ref}`),
|
|
1654
|
+
...evidence.truncatedRefs.map((ref) => `truncated:${ref}`)
|
|
1655
|
+
]);
|
|
1656
|
+
const absenceProof = asRecord2(evidence.stageArgs["absenceProof"]);
|
|
1657
|
+
const canClaimAbsence = status === "finish_ready_report_only" && absenceProof?.["complete"] === true && evidence.staleRefs.length === 0 && evidence.truncatedRefs.length === 0;
|
|
1658
|
+
return {
|
|
1659
|
+
canClaimDone: status === "finish_ready_report_only",
|
|
1660
|
+
canClaimAbsence,
|
|
1661
|
+
blockers,
|
|
1662
|
+
staleRefs: evidence.staleRefs,
|
|
1663
|
+
truncatedRefs: evidence.truncatedRefs,
|
|
1664
|
+
missingProofRefs: evidence.missingProofRefs
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
function buildEvidenceStatusDetail(args) {
|
|
1668
|
+
const blocked = args.status.startsWith("blocked_");
|
|
1669
|
+
const finalClaimsAllowed = args.finalClaimPolicy.canClaimDone;
|
|
1670
|
+
const validationRefs = args.evidence.validationRefs.slice(0, COMPACT_REF_LIMIT2);
|
|
1671
|
+
return {
|
|
1672
|
+
kind: "goal_lifecycle_evidence_status",
|
|
1673
|
+
schemaVersion: 1,
|
|
1674
|
+
status: blocked ? "blocked" : args.status === "planning_only" || args.status === "partial_evidence" ? "degraded" : "ready",
|
|
1675
|
+
runtimeFreshness: {
|
|
1676
|
+
status: args.evidence.staleRefs.length > 0 ? "stale" : "unknown",
|
|
1677
|
+
reasonCodes: args.evidence.staleRefs.length > 0 ? ["goal_lifecycle:stale_ref"] : ["goal_lifecycle:runtime_freshness_not_claimed"]
|
|
1678
|
+
},
|
|
1679
|
+
coverage: {
|
|
1680
|
+
status: args.contextSummary?.truncated || args.evidence.truncatedRefs.length > 0 ? "truncated" : args.status === "planning_only" || args.status === "partial_evidence" ? "partial" : "complete",
|
|
1681
|
+
selectedFileCount: args.contextSummary?.primaryEditFiles.length ?? args.evidence.changedFiles.length,
|
|
1682
|
+
omittedRangeCount: args.contextSummary?.truncated ? 1 : 0,
|
|
1683
|
+
truncated: Boolean(args.contextSummary?.truncated || args.evidence.truncatedRefs.length > 0),
|
|
1684
|
+
reasonCodes: evidenceCoverageReasonCodes(args.status, args.contextSummary, args.evidence)
|
|
1685
|
+
},
|
|
1686
|
+
proof: {
|
|
1687
|
+
status: blocked ? "blocked" : finalClaimsAllowed ? "proved" : args.evidence.validationRefs.length > 0 ? "evidence_only" : "not_proved",
|
|
1688
|
+
validationRefs,
|
|
1689
|
+
absenceClaimsAllowed: args.finalClaimPolicy.canClaimAbsence,
|
|
1690
|
+
finalClaimsAllowed,
|
|
1691
|
+
reasonCodes: evidenceProofReasonCodes(args.status, finalClaimsAllowed)
|
|
1692
|
+
},
|
|
1693
|
+
fallback: {
|
|
1694
|
+
status: args.evidence.fallbackStatus,
|
|
1695
|
+
fallbackRefs: args.evidence.fallbackRefs.slice(0, COMPACT_REF_LIMIT2),
|
|
1696
|
+
reasonCodes: args.evidence.fallbackRefs.length > 0 ? ["goal_lifecycle:fallback_refs_linked"] : ["goal_lifecycle:fallback_not_needed"]
|
|
1697
|
+
},
|
|
1698
|
+
agentTrust: {
|
|
1699
|
+
level: finalClaimsAllowed ? "bounded" : "advisory",
|
|
1700
|
+
basisRefs: uniqueStrings3([...args.evidence.validationRefs, ...args.evidence.codeTrailRefs, ...args.evidence.receiptRefs]).slice(0, COMPACT_REF_LIMIT2),
|
|
1701
|
+
reasonCodes: ["goal_lifecycle:report_only_no_authority"]
|
|
1702
|
+
},
|
|
1703
|
+
noAuthority: true
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
function buildTaskLinks(evidence, goalSession) {
|
|
1707
|
+
const links = [];
|
|
1708
|
+
if (goalSession.goalSessionId) {
|
|
1709
|
+
links.push(taskLink("goal_session", goalSession.goalSessionId, "source", undefined, [], evidence.evidenceRefs));
|
|
1710
|
+
}
|
|
1711
|
+
for (const ref of evidence.validationRefs)
|
|
1712
|
+
links.push(taskLink("validation_receipt", ref, "validation", undefined, [], [ref]));
|
|
1713
|
+
for (const ref of evidence.prReviewRefs)
|
|
1714
|
+
links.push(taskLink(ref.includes("review-room") ? "review_room" : "pr_snapshot", ref, "review", undefined, [], [ref]));
|
|
1715
|
+
for (const ref of evidence.serviceConnectionIds)
|
|
1716
|
+
links.push(taskLink("service_connection", ref, "service", undefined, [], [ref]));
|
|
1717
|
+
const editSessionId = cleanString3(evidence.stageArgs["editSessionId"]) ?? cleanString3(evidence.stageArgs["agentEditSessionId"]) ?? cleanString3(asRecord2(evidence.stageArgs["agentEditSession"])?.["editSessionId"]) ?? cleanString3(asRecord2(evidence.stageArgs["agentEditSession"])?.["id"]);
|
|
1718
|
+
if (editSessionId) {
|
|
1719
|
+
links.push(taskLink("agent_edit_session", editSessionId, "work", cleanString3(asRecord2(evidence.stageArgs["agentEditSession"])?.["status"]), evidence.changedFiles, evidence.evidenceRefs));
|
|
1720
|
+
}
|
|
1721
|
+
const workroomRunId = cleanString3(evidence.stageArgs["workroomRunId"]);
|
|
1722
|
+
if (workroomRunId)
|
|
1723
|
+
links.push(taskLink("code_workroom_run", workroomRunId, "work", undefined, evidence.changedFiles, evidence.evidenceRefs));
|
|
1724
|
+
const patchRunId = cleanString3(evidence.stageArgs["patchRunId"]);
|
|
1725
|
+
if (patchRunId)
|
|
1726
|
+
links.push(taskLink("code_patch_run", patchRunId, "work", undefined, evidence.changedFiles, evidence.evidenceRefs));
|
|
1727
|
+
return uniqueTaskLinks(links);
|
|
1728
|
+
}
|
|
1729
|
+
function buildGoalLifecycleObservationsV1(args) {
|
|
1730
|
+
const candidates = [];
|
|
1731
|
+
const evidenceRefs = uniqueStrings3([
|
|
1732
|
+
...args.evidence.evidenceRefs,
|
|
1733
|
+
...args.codeTrailUse.codeTrailRefs,
|
|
1734
|
+
args.codeTrailUse.importCandidateRef
|
|
1735
|
+
]);
|
|
1736
|
+
if ((args.evidence.changedFiles.length > 0 || evidenceRefs.length > 0) && args.evidence.stage !== "start") {
|
|
1737
|
+
candidates.push(observation({
|
|
1738
|
+
observationKind: "worktask_observation",
|
|
1739
|
+
title: `Goal ${args.evidence.stage} evidence`,
|
|
1740
|
+
summary: cleanString3(args.evidence.stageArgs["summary"]) ?? "Goal lifecycle evidence was captured as report-only task context.",
|
|
1741
|
+
targetRefs: evidenceRefs,
|
|
1742
|
+
filePaths: args.evidence.changedFiles,
|
|
1743
|
+
evidenceRefs,
|
|
1744
|
+
serviceConnectionIds: args.evidence.serviceConnectionIds,
|
|
1745
|
+
rank: observationRank(args.evidence, args.contextSummary, args.codeTrailUse),
|
|
1746
|
+
status: args.status,
|
|
1747
|
+
reasonCodes: [`goal_lifecycle:${args.evidence.stage}`, "goal_lifecycle:ranking_hint_only"]
|
|
1748
|
+
}));
|
|
1749
|
+
}
|
|
1750
|
+
const filePaths = uniqueStrings3([
|
|
1751
|
+
...args.evidence.changedFiles,
|
|
1752
|
+
...args.contextSummary?.primaryEditFiles ?? []
|
|
1753
|
+
]).slice(0, MAX_FILE_OBSERVATION_CANDIDATES);
|
|
1754
|
+
for (const filePath of filePaths) {
|
|
1755
|
+
candidates.push(observation({
|
|
1756
|
+
observationKind: "file_observation",
|
|
1757
|
+
title: `File evidence: ${filePath}`,
|
|
1758
|
+
summary: "File participated in the goal lifecycle evidence set; use as a ranking hint only.",
|
|
1759
|
+
targetRefs: [filePath],
|
|
1760
|
+
filePaths: [filePath],
|
|
1761
|
+
evidenceRefs,
|
|
1762
|
+
serviceConnectionIds: args.evidence.serviceConnectionIds,
|
|
1763
|
+
rank: observationRank(args.evidence, args.contextSummary, args.codeTrailUse) + (args.contextSummary?.primaryEditFiles.includes(filePath) ? 10 : 0),
|
|
1764
|
+
status: args.status,
|
|
1765
|
+
reasonCodes: ["goal_lifecycle:file_observation", "goal_lifecycle:ranking_hint_only"]
|
|
1766
|
+
}));
|
|
1767
|
+
}
|
|
1768
|
+
if (args.evidence.validationRefs.length > 0 || args.evidence.hasValidationResult) {
|
|
1769
|
+
candidates.push(observation({
|
|
1770
|
+
observationKind: "validation_observation",
|
|
1771
|
+
title: "Validation evidence linked",
|
|
1772
|
+
summary: "Validation was linked to the lifecycle as evidence only.",
|
|
1773
|
+
targetRefs: args.evidence.validationRefs,
|
|
1774
|
+
filePaths: args.evidence.changedFiles,
|
|
1775
|
+
evidenceRefs,
|
|
1776
|
+
serviceConnectionIds: args.evidence.serviceConnectionIds,
|
|
1777
|
+
rank: observationRank(args.evidence, args.contextSummary, args.codeTrailUse) + 30,
|
|
1778
|
+
status: args.status,
|
|
1779
|
+
reasonCodes: ["goal_lifecycle:validation_observation", "goal_lifecycle:ranking_hint_only"]
|
|
1780
|
+
}));
|
|
1781
|
+
}
|
|
1782
|
+
if (args.status.startsWith("blocked_")) {
|
|
1783
|
+
candidates.push(observation({
|
|
1784
|
+
observationKind: "risk_observation",
|
|
1785
|
+
title: "Lifecycle proof blocked",
|
|
1786
|
+
summary: `Lifecycle evidence cannot support final claims: ${args.status}.`,
|
|
1787
|
+
targetRefs: uniqueStrings3([...args.evidence.staleRefs, ...args.evidence.truncatedRefs, ...args.evidence.missingProofRefs]),
|
|
1788
|
+
filePaths: args.evidence.changedFiles,
|
|
1789
|
+
evidenceRefs,
|
|
1790
|
+
serviceConnectionIds: args.evidence.serviceConnectionIds,
|
|
1791
|
+
rank: 20,
|
|
1792
|
+
status: args.status,
|
|
1793
|
+
reasonCodes: [`goal_lifecycle:${args.status}`, "goal_lifecycle:risk_observation"]
|
|
1794
|
+
}));
|
|
1795
|
+
}
|
|
1796
|
+
if (args.progressInputs) {
|
|
1797
|
+
candidates.push(...buildGoalProgressObservationsV1(args.progressInputs));
|
|
1798
|
+
}
|
|
1799
|
+
const sorted = candidates.sort((left, right) => right.rank - left.rank || left.observationId.localeCompare(right.observationId));
|
|
1800
|
+
return { visible: sorted.slice(0, args.maxObservations), total: sorted.length };
|
|
1801
|
+
}
|
|
1802
|
+
function buildGoalLifecycleMemoryCandidatesV1(args) {
|
|
1803
|
+
if (args.stage === "start")
|
|
1804
|
+
return [];
|
|
1805
|
+
const taskRefs = uniqueStrings3(args.taskLinks.map((link) => link.ref)).slice(0, COMPACT_REF_LIMIT2);
|
|
1806
|
+
return args.observations.filter((item) => item.observationKind === "file_observation" || item.observationKind === "worktask_observation" || item.observationKind === "validation_observation" || item.observationKind === "risk_observation").map((observation) => {
|
|
1807
|
+
const candidateKind = lifecycleMemoryCandidateKind(observation);
|
|
1808
|
+
const status = lifecycleMemoryCandidateStatus(args.stage, args.status, observation);
|
|
1809
|
+
const blockedReasons = observation.promotion.blockedReasons;
|
|
1810
|
+
const identity = buildGoalMemoryCandidateIdentityV1({
|
|
1811
|
+
sourceKind: "goal_lifecycle",
|
|
1812
|
+
candidateKind,
|
|
1813
|
+
title: observation.title,
|
|
1814
|
+
summary: observation.summary,
|
|
1815
|
+
normalizedRule: observation.summary,
|
|
1816
|
+
goal: args.goal,
|
|
1817
|
+
goalSessionId: args.goalSession.goalSessionId,
|
|
1818
|
+
activeGoalId: args.goalSession.activeGoalId,
|
|
1819
|
+
parentGoalId: args.goalSession.parentGoalId,
|
|
1820
|
+
supersedesGoalId: args.goalSession.supersedesGoalId,
|
|
1821
|
+
sourceEventId: observation.observationId,
|
|
1822
|
+
sourceIds: goalMemoryCandidateSourceIdsV1([[args.lifecycleId, observation.observationId], observation.evidenceRefs]),
|
|
1823
|
+
targetRefs: observation.targetRefs,
|
|
1824
|
+
filePaths: observation.filePaths,
|
|
1825
|
+
evidenceRefs: observation.evidenceRefs,
|
|
1826
|
+
observationRefs: [observation.observationId],
|
|
1827
|
+
taskRefs,
|
|
1828
|
+
serviceConnectionIds: observation.serviceConnectionIds
|
|
1829
|
+
});
|
|
1830
|
+
return removeUndefined2({
|
|
1831
|
+
kind: "memory_candidate",
|
|
1832
|
+
candidateKind,
|
|
1833
|
+
title: observation.title,
|
|
1834
|
+
summary: observation.summary,
|
|
1835
|
+
normalizedRule: observation.summary,
|
|
1836
|
+
goal: args.goal,
|
|
1837
|
+
evidenceRefs: observation.evidenceRefs.slice(0, COMPACT_REF_LIMIT2),
|
|
1838
|
+
serviceConnectionIds: observation.serviceConnectionIds.slice(0, COMPACT_REF_LIMIT2),
|
|
1839
|
+
...identity,
|
|
1840
|
+
sourceKind: "goal_lifecycle",
|
|
1841
|
+
sourceIds: goalMemoryCandidateSourceIdsV1([[args.lifecycleId, observation.observationId], observation.evidenceRefs]),
|
|
1842
|
+
goalSessionId: args.goalSession.goalSessionId,
|
|
1843
|
+
activeGoalId: args.goalSession.activeGoalId,
|
|
1844
|
+
parentGoalId: args.goalSession.parentGoalId,
|
|
1845
|
+
supersedesGoalId: args.goalSession.supersedesGoalId,
|
|
1846
|
+
targetRefs: observation.targetRefs.slice(0, COMPACT_REF_LIMIT2),
|
|
1847
|
+
filePaths: observation.filePaths.slice(0, COMPACT_REF_LIMIT2),
|
|
1848
|
+
observationRefs: [observation.observationId],
|
|
1849
|
+
taskRefs,
|
|
1850
|
+
codeTrailRefs: args.evidence.codeTrailRefs.slice(0, COMPACT_REF_LIMIT2),
|
|
1851
|
+
prReviewRefs: args.evidence.prReviewRefs.slice(0, COMPACT_REF_LIMIT2),
|
|
1852
|
+
confidence: observation.confidence,
|
|
1853
|
+
rank: observation.rank,
|
|
1854
|
+
status,
|
|
1855
|
+
promotionStatus: status,
|
|
1856
|
+
promotionBlockers: blockedReasons,
|
|
1857
|
+
reasonCodes: uniqueStrings3([
|
|
1858
|
+
...observation.reasonCodes,
|
|
1859
|
+
`goal_memory:${candidateKind}`,
|
|
1860
|
+
`goal_memory:status:${status}`
|
|
1861
|
+
]),
|
|
1862
|
+
candidateOnly: true,
|
|
1863
|
+
rankingUseOnly: observation.promotion.rankingUseOnly,
|
|
1864
|
+
requiresUserConfirmation: true,
|
|
1865
|
+
requiresRepeatedEvidence: observation.promotion.requiresRepeatedEvidence || status !== "ready_for_review",
|
|
1866
|
+
requiresOmPolicyCheck: true,
|
|
1867
|
+
memoryWrite: false,
|
|
1868
|
+
truthWrite: false,
|
|
1869
|
+
noMemoryWrite: true,
|
|
1870
|
+
promotionRequired: true,
|
|
1871
|
+
writeAuthority: false,
|
|
1872
|
+
promotion: {
|
|
1873
|
+
candidateOnly: true,
|
|
1874
|
+
rankingUseOnly: observation.promotion.rankingUseOnly,
|
|
1875
|
+
status,
|
|
1876
|
+
eligibleForPromotionReview: observation.promotion.eligibleForPromotionReview,
|
|
1877
|
+
requiresUserConfirmation: true,
|
|
1878
|
+
requiresRepeatedEvidence: observation.promotion.requiresRepeatedEvidence || status !== "ready_for_review",
|
|
1879
|
+
requiresOmPolicyCheck: true,
|
|
1880
|
+
promotionRequired: true,
|
|
1881
|
+
writeAuthority: false,
|
|
1882
|
+
memoryWrite: false,
|
|
1883
|
+
truthWrite: false,
|
|
1884
|
+
noMemoryWrite: true,
|
|
1885
|
+
blockedReasons
|
|
1886
|
+
},
|
|
1887
|
+
...buildGoalIntelligenceGuardrailsV1()
|
|
1888
|
+
});
|
|
1889
|
+
}).sort((left, right) => (right.rank ?? 0) - (left.rank ?? 0) || (left.candidateId ?? "").localeCompare(right.candidateId ?? ""));
|
|
1890
|
+
}
|
|
1891
|
+
function lifecycleMemoryCandidateKind(observation) {
|
|
1892
|
+
if (observation.observationKind === "file_observation")
|
|
1893
|
+
return "lifecycle_file_pattern";
|
|
1894
|
+
if (observation.observationKind === "worktask_observation")
|
|
1895
|
+
return "lifecycle_worktask_pattern";
|
|
1896
|
+
if (observation.observationKind === "validation_observation")
|
|
1897
|
+
return "validation_practice";
|
|
1898
|
+
if (observation.observationKind === "risk_observation")
|
|
1899
|
+
return "risk_pattern";
|
|
1900
|
+
return "lifecycle_worktask_pattern";
|
|
1901
|
+
}
|
|
1902
|
+
function lifecycleMemoryCandidateStatus(stage, status, observation) {
|
|
1903
|
+
if (status.startsWith("blocked_") || !observation.promotion.eligibleForPromotionReview)
|
|
1904
|
+
return "needs_more_evidence";
|
|
1905
|
+
if (stage === "finish" && (status === "finish_ready_report_only" || status === "validation_linked"))
|
|
1906
|
+
return "ready_for_review";
|
|
1907
|
+
return "candidate";
|
|
1908
|
+
}
|
|
1909
|
+
function buildObservationRankingHintsV1(observations) {
|
|
1910
|
+
return observations.flatMap((item) => item.targetRefs.map((targetRef) => ({
|
|
1911
|
+
kind: "goal_lifecycle_ranking_hint",
|
|
1912
|
+
targetRef,
|
|
1913
|
+
weight: item.rank,
|
|
1914
|
+
reasonCodes: item.reasonCodes,
|
|
1915
|
+
sourceObservationId: item.observationId,
|
|
1916
|
+
noAuthority: true
|
|
1917
|
+
})));
|
|
1918
|
+
}
|
|
1919
|
+
function observation(args) {
|
|
1920
|
+
const blockedReasons = promotionBlockedReasons(args.status, args.evidenceRefs, args.summary);
|
|
1921
|
+
const eligibleForPromotionReview = blockedReasons.length === 0;
|
|
1922
|
+
const boundedRank = Math.max(0, Math.min(100, Math.round(args.rank)));
|
|
1923
|
+
return {
|
|
1924
|
+
kind: "goal_lifecycle_observation",
|
|
1925
|
+
observationKind: args.observationKind,
|
|
1926
|
+
observationId: `goal-observation:${stableHash2({
|
|
1927
|
+
kind: args.observationKind,
|
|
1928
|
+
targetRefs: args.targetRefs,
|
|
1929
|
+
evidenceRefs: args.evidenceRefs,
|
|
1930
|
+
summary: args.summary
|
|
1931
|
+
})}`,
|
|
1932
|
+
title: args.title.slice(0, 120),
|
|
1933
|
+
summary: args.summary.slice(0, 360),
|
|
1934
|
+
targetRefs: uniqueStrings3(args.targetRefs).slice(0, COMPACT_REF_LIMIT2),
|
|
1935
|
+
filePaths: uniqueStrings3(args.filePaths).slice(0, COMPACT_REF_LIMIT2),
|
|
1936
|
+
evidenceRefs: uniqueStrings3(args.evidenceRefs).slice(0, COMPACT_REF_LIMIT2),
|
|
1937
|
+
serviceConnectionIds: uniqueStrings3(args.serviceConnectionIds).slice(0, COMPACT_REF_LIMIT2),
|
|
1938
|
+
confidence: Math.max(0, Math.min(1, Number((boundedRank / 100).toFixed(2)))),
|
|
1939
|
+
rank: boundedRank,
|
|
1940
|
+
reasonCodes: uniqueStrings3(args.reasonCodes),
|
|
1941
|
+
promotion: {
|
|
1942
|
+
candidateOnly: true,
|
|
1943
|
+
rankingUseOnly: true,
|
|
1944
|
+
eligibleForPromotionReview,
|
|
1945
|
+
requiresUserConfirmation: true,
|
|
1946
|
+
requiresRepeatedEvidence: true,
|
|
1947
|
+
requiresOmPolicyCheck: true,
|
|
1948
|
+
writeAuthority: false,
|
|
1949
|
+
memoryWrite: false,
|
|
1950
|
+
truthWrite: false,
|
|
1951
|
+
blockedReasons
|
|
1952
|
+
},
|
|
1953
|
+
noAuthority: true
|
|
1954
|
+
};
|
|
1955
|
+
}
|
|
1956
|
+
function observationRank(evidence, contextSummary, codeTrailUse) {
|
|
1957
|
+
let score = 0;
|
|
1958
|
+
if (evidence.validationRefs.length > 0 || evidence.hasValidationResult)
|
|
1959
|
+
score += 30;
|
|
1960
|
+
if (codeTrailUse.status !== "unavailable")
|
|
1961
|
+
score += 25;
|
|
1962
|
+
if (evidence.diffRefs.length > 0)
|
|
1963
|
+
score += 20;
|
|
1964
|
+
if (evidence.prReviewRefs.length > 0)
|
|
1965
|
+
score += 15;
|
|
1966
|
+
if ((contextSummary?.primaryEditFiles.length ?? 0) > 0)
|
|
1967
|
+
score += 10;
|
|
1968
|
+
if (evidence.stageArgs["repoIntelligence"] || evidence.stageArgs["repoIntelligenceStatus"])
|
|
1969
|
+
score += 5;
|
|
1970
|
+
if (evidence.staleRefs.length > 0)
|
|
1971
|
+
score -= 30;
|
|
1972
|
+
if (evidence.truncatedRefs.length > 0)
|
|
1973
|
+
score -= 30;
|
|
1974
|
+
if (evidence.missingProofRefs.length > 0)
|
|
1975
|
+
score -= 40;
|
|
1976
|
+
if (evidence.hasUnsafePayload)
|
|
1977
|
+
score -= 20;
|
|
1978
|
+
return Math.max(0, Math.min(100, score));
|
|
1979
|
+
}
|
|
1980
|
+
function summarizeContextPacket(packet) {
|
|
1981
|
+
const record = packet;
|
|
1982
|
+
const slices = objectArray(record["contextSlices"]);
|
|
1983
|
+
const primaryEditFiles = objectArray(record["primaryEditFiles"]).map((item) => cleanString3(item["path"])).filter((path) => Boolean(path));
|
|
1984
|
+
const contentSliceCount = slices.filter((slice) => Boolean(asRecord2(slice["content"])?.["text"])).length;
|
|
1985
|
+
const contentBudget = asRecord2(record["contentBudget"]);
|
|
1986
|
+
return {
|
|
1987
|
+
packetId: cleanString3(record["packetId"]),
|
|
1988
|
+
primaryEditFiles: uniqueStrings3(primaryEditFiles),
|
|
1989
|
+
contextSliceCount: slices.length,
|
|
1990
|
+
contentSliceCount,
|
|
1991
|
+
truncated: Boolean(cleanString3(contentBudget?.["overflowReason"]) || slices.some((slice) => asRecord2(slice["content"])?.["truncated"] === true)),
|
|
1992
|
+
sourceRefs: stringList3(record["sourceRefs"]).slice(0, COMPACT_REF_LIMIT2),
|
|
1993
|
+
evidenceRefs: stringList3(record["evidenceRefs"]).slice(0, COMPACT_REF_LIMIT2),
|
|
1994
|
+
receiptRefs: stringList3(record["receiptRefs"]).slice(0, COMPACT_REF_LIMIT2),
|
|
1995
|
+
noAuthority: true
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
function lifecycleStageFromArgs(args) {
|
|
1999
|
+
const lifecycle = asRecord2(args["goalLifecycle"]) ?? asRecord2(args["lifecycle"]);
|
|
2000
|
+
const explicit = cleanString3(lifecycle?.["stage"]) ?? cleanString3(lifecycle?.["phase"]);
|
|
2001
|
+
if (explicit === "start" || explicit === "steer" || explicit === "checkpoint" || explicit === "finish")
|
|
2002
|
+
return explicit;
|
|
2003
|
+
if (asRecord2(args["start"]))
|
|
2004
|
+
return "start";
|
|
2005
|
+
if (asRecord2(args["checkpoint"]))
|
|
2006
|
+
return "checkpoint";
|
|
2007
|
+
if (asRecord2(args["finish"]))
|
|
2008
|
+
return "finish";
|
|
2009
|
+
return "start";
|
|
2010
|
+
}
|
|
2011
|
+
function lifecycleStageArgs(args, stage) {
|
|
2012
|
+
const lifecycle = asRecord2(args["goalLifecycle"]) ?? asRecord2(args["lifecycle"]) ?? {};
|
|
2013
|
+
return {
|
|
2014
|
+
...asRecord2(lifecycle[stage]),
|
|
2015
|
+
...asRecord2(args[stage]),
|
|
2016
|
+
...lifecycle
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
2019
|
+
function lifecycleStatusForStage(stage, status) {
|
|
2020
|
+
if (status.startsWith("blocked_"))
|
|
2021
|
+
return "blocked";
|
|
2022
|
+
if (stage === "start")
|
|
2023
|
+
return "started";
|
|
2024
|
+
if (stage === "checkpoint")
|
|
2025
|
+
return "checkpointed";
|
|
2026
|
+
if (stage === "finish")
|
|
2027
|
+
return "finished";
|
|
2028
|
+
return "continued";
|
|
2029
|
+
}
|
|
2030
|
+
function evidenceStatusReasonCodes(status, evidence, contextSummary, codeTrailUse) {
|
|
2031
|
+
return uniqueStrings3([
|
|
2032
|
+
`goal_lifecycle:${evidence.stage}`,
|
|
2033
|
+
`goal_lifecycle:${status}`,
|
|
2034
|
+
contextSummary?.contentSliceCount ? "goal_lifecycle:context_content_linked" : undefined,
|
|
2035
|
+
codeTrailUse.status !== "unavailable" ? `goal_lifecycle:code_trail:${codeTrailUse.status}` : undefined,
|
|
2036
|
+
evidence.validationRefs.length > 0 ? "goal_lifecycle:validation_refs_linked" : undefined,
|
|
2037
|
+
evidence.diffRefs.length > 0 ? "goal_lifecycle:diff_refs_linked" : undefined,
|
|
2038
|
+
evidence.staleRefs.length > 0 ? "goal_lifecycle:stale_ref" : undefined,
|
|
2039
|
+
evidence.truncatedRefs.length > 0 ? "goal_lifecycle:truncated_coverage" : undefined,
|
|
2040
|
+
evidence.hasUnsafePayload ? "goal_lifecycle:unsafe_payload_withheld" : undefined
|
|
2041
|
+
]);
|
|
2042
|
+
}
|
|
2043
|
+
function evidenceCoverageReasonCodes(status, contextSummary, evidence) {
|
|
2044
|
+
return uniqueStrings3([
|
|
2045
|
+
contextSummary ? "goal_lifecycle:context_packet_summary" : undefined,
|
|
2046
|
+
contextSummary?.truncated || evidence.truncatedRefs.length > 0 ? "goal_lifecycle:coverage_truncated" : undefined,
|
|
2047
|
+
status === "planning_only" ? "goal_lifecycle:planner_only" : undefined,
|
|
2048
|
+
status === "context_ready" ? "goal_lifecycle:context_ready" : undefined
|
|
2049
|
+
]);
|
|
2050
|
+
}
|
|
2051
|
+
function evidenceProofReasonCodes(status, finalClaimsAllowed) {
|
|
2052
|
+
return uniqueStrings3([
|
|
2053
|
+
finalClaimsAllowed ? "goal_lifecycle:finish_ready_report_only" : "goal_lifecycle:no_final_claim",
|
|
2054
|
+
status === "blocked_missing_proof" ? "goal_lifecycle:missing_proof" : undefined,
|
|
2055
|
+
status === "blocked_stale_or_truncated" ? "goal_lifecycle:stale_or_truncated_blocks_claims" : undefined,
|
|
2056
|
+
status === "blocked_unsafe_payload" ? "goal_lifecycle:unsafe_payload_blocks_claims" : undefined
|
|
2057
|
+
]);
|
|
2058
|
+
}
|
|
2059
|
+
function promotionBlockedReasons(status, evidenceRefs, summary) {
|
|
2060
|
+
return uniqueStrings3([
|
|
2061
|
+
status !== "finish_ready_report_only" && status !== "validation_linked" ? "promotion:requires_finish_or_validation_linked_status" : undefined,
|
|
2062
|
+
evidenceRefs.length === 0 ? "promotion:requires_validation_or_code_trail_evidence" : undefined,
|
|
2063
|
+
status.startsWith("blocked_") ? "promotion:blocked_lifecycle_status" : undefined,
|
|
2064
|
+
summary.length > 360 ? "promotion:summary_too_long" : undefined
|
|
2065
|
+
]);
|
|
2066
|
+
}
|
|
2067
|
+
function nextActionForStatus(stage, status) {
|
|
2068
|
+
if (status === "finish_ready_report_only") {
|
|
2069
|
+
return {
|
|
2070
|
+
tool: "rhei_code_trail_export",
|
|
2071
|
+
mode: "trail",
|
|
2072
|
+
reason: "Finish evidence is report-ready; import or export CodeTrail only through the explicit durable path.",
|
|
2073
|
+
noAuthority: true
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
if (status.startsWith("blocked_")) {
|
|
2077
|
+
return {
|
|
2078
|
+
tool: "rhei_code_goal",
|
|
2079
|
+
mode: stage === "finish" ? "checkpoint" : "verify",
|
|
2080
|
+
reason: "Lifecycle evidence is blocked; add validation, freshness, diff, or proof refs before claiming completion.",
|
|
2081
|
+
noAuthority: true
|
|
2082
|
+
};
|
|
2083
|
+
}
|
|
2084
|
+
return {
|
|
2085
|
+
tool: "rhei_code_goal",
|
|
2086
|
+
mode: stage === "start" ? "checkpoint" : "finish",
|
|
2087
|
+
reason: "Continue the report-only lifecycle with bounded evidence refs.",
|
|
2088
|
+
noAuthority: true
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
2091
|
+
function buildLifecycleFeedbackLoops(stage) {
|
|
2092
|
+
if (stage === "steer")
|
|
2093
|
+
return buildGoalFeedbackLoopsV1({ mode: "steer" });
|
|
2094
|
+
return buildGoalFeedbackLoopsV1({ mode: stage });
|
|
2095
|
+
}
|
|
2096
|
+
function taskLink(kind, ref, role, status, filePaths, evidenceRefs) {
|
|
2097
|
+
return removeUndefined2({
|
|
2098
|
+
kind,
|
|
2099
|
+
ref,
|
|
2100
|
+
role,
|
|
2101
|
+
status,
|
|
2102
|
+
filePaths: uniqueStrings3(filePaths).slice(0, COMPACT_REF_LIMIT2),
|
|
2103
|
+
evidenceRefs: uniqueStrings3(evidenceRefs).slice(0, COMPACT_REF_LIMIT2),
|
|
2104
|
+
noAuthority: true
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
function uniqueTaskLinks(links) {
|
|
2108
|
+
const seen = new Set;
|
|
2109
|
+
return links.filter((link) => {
|
|
2110
|
+
const key = `${link.kind}:${link.ref}:${link.role}`;
|
|
2111
|
+
if (seen.has(key))
|
|
2112
|
+
return false;
|
|
2113
|
+
seen.add(key);
|
|
2114
|
+
return true;
|
|
2115
|
+
});
|
|
2116
|
+
}
|
|
2117
|
+
function fallbackStatusValue(value) {
|
|
2118
|
+
if (value === "used" || value === "available" || value === "missing" || value === "blocked")
|
|
2119
|
+
return value;
|
|
2120
|
+
return "not_needed";
|
|
2121
|
+
}
|
|
2122
|
+
function hasUnsafeLifecyclePayload(value, depth = 0) {
|
|
2123
|
+
if (depth > 5)
|
|
2124
|
+
return false;
|
|
2125
|
+
const record = asRecord2(value);
|
|
2126
|
+
if (!record)
|
|
2127
|
+
return false;
|
|
2128
|
+
for (const [key, child] of Object.entries(record)) {
|
|
2129
|
+
if (UNSAFE_KEY_PATTERN.test(key) && child !== undefined && child !== null)
|
|
2130
|
+
return true;
|
|
2131
|
+
if (typeof child === "object" && hasUnsafeLifecyclePayload(child, depth + 1))
|
|
2132
|
+
return true;
|
|
2133
|
+
}
|
|
2134
|
+
return false;
|
|
2135
|
+
}
|
|
2136
|
+
function asRecord2(value) {
|
|
2137
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
2138
|
+
return;
|
|
2139
|
+
return value;
|
|
2140
|
+
}
|
|
2141
|
+
function objectArray(value) {
|
|
2142
|
+
if (!Array.isArray(value))
|
|
2143
|
+
return [];
|
|
2144
|
+
return value.map((item) => asRecord2(item)).filter((item) => Boolean(item));
|
|
2145
|
+
}
|
|
2146
|
+
function stringList3(value) {
|
|
2147
|
+
if (!Array.isArray(value))
|
|
2148
|
+
return [];
|
|
2149
|
+
return value.map((item) => cleanString3(item)).filter((item) => Boolean(item));
|
|
2150
|
+
}
|
|
2151
|
+
function uniqueStrings3(values) {
|
|
2152
|
+
return Array.from(new Set(values.map((value) => value?.trim()).filter((value) => Boolean(value))));
|
|
2153
|
+
}
|
|
2154
|
+
function cleanString3(value) {
|
|
2155
|
+
if (typeof value !== "string")
|
|
2156
|
+
return;
|
|
2157
|
+
const text = value.trim();
|
|
2158
|
+
return text.length > 0 ? text : undefined;
|
|
2159
|
+
}
|
|
2160
|
+
function removeUndefined2(value) {
|
|
2161
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
2162
|
+
}
|
|
2163
|
+
function omittedAfterLimit2(total, limit) {
|
|
2164
|
+
return total > limit ? total - limit : undefined;
|
|
2165
|
+
}
|
|
2166
|
+
function stableHash2(value) {
|
|
2167
|
+
const text = stableJson2(value);
|
|
2168
|
+
let hash = 2166136261;
|
|
2169
|
+
for (let index = 0;index < text.length; index += 1) {
|
|
2170
|
+
hash ^= text.charCodeAt(index);
|
|
2171
|
+
hash = Math.imul(hash, 16777619);
|
|
2172
|
+
}
|
|
2173
|
+
return (hash >>> 0).toString(16).padStart(8, "0").slice(0, 12);
|
|
2174
|
+
}
|
|
2175
|
+
function stableJson2(value) {
|
|
2176
|
+
if (Array.isArray(value))
|
|
2177
|
+
return `[${value.map(stableJson2).join(",")}]`;
|
|
2178
|
+
if (value && typeof value === "object") {
|
|
2179
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson2(value[key])}`).join(",")}}`;
|
|
2180
|
+
}
|
|
2181
|
+
return JSON.stringify(value);
|
|
2182
|
+
}
|
|
2183
|
+
export {
|
|
2184
|
+
normalizeGoalMemoryTextV1,
|
|
2185
|
+
goalSessionHasContinuityV1,
|
|
2186
|
+
goalMemoryCandidateSourceIdsV1,
|
|
2187
|
+
detectValidationStuckV1,
|
|
2188
|
+
detectSearchLoopV1,
|
|
2189
|
+
detectNoProgressCheckpointsV1,
|
|
2190
|
+
collectGoalServiceConnectionIdsV1,
|
|
2191
|
+
collectGoalMemoryFilePathsV1,
|
|
2192
|
+
collectGoalEvidenceRefsV1,
|
|
2193
|
+
buildServiceImpactV1,
|
|
2194
|
+
buildPreferenceReplayV1,
|
|
2195
|
+
buildGoalStewardDecisionV1,
|
|
2196
|
+
buildGoalStartLifecycleV1,
|
|
2197
|
+
buildGoalSessionV1,
|
|
2198
|
+
buildGoalResumeV1,
|
|
2199
|
+
buildGoalProgressObservationsV1,
|
|
2200
|
+
buildGoalOutcomeFeedbackV1,
|
|
2201
|
+
buildGoalMemoryCandidateIdentityV1,
|
|
2202
|
+
buildGoalLifecycleV1,
|
|
2203
|
+
buildGoalLifecycleCodeTrailUseV1,
|
|
2204
|
+
buildGoalIntelligenceGuardrailsV1,
|
|
2205
|
+
buildGoalIntelligenceCommitV1,
|
|
2206
|
+
buildGoalFinishLifecycleV1,
|
|
2207
|
+
buildGoalFeedbackLoopsV1,
|
|
2208
|
+
buildGoalContinuityPacketV1,
|
|
2209
|
+
buildGoalCheckpointLifecycleV1,
|
|
2210
|
+
buildDiagnosticClosureV1,
|
|
2211
|
+
GOAL_STEWARD_DECISION_VALUES,
|
|
2212
|
+
GOAL_MEMORY_CANDIDATE_STATUS_VALUES,
|
|
2213
|
+
GOAL_MEMORY_CANDIDATE_SOURCE_KIND_VALUES,
|
|
2214
|
+
GOAL_MEMORY_CANDIDATE_KIND_VALUES,
|
|
2215
|
+
GOAL_LIFECYCLE_SCHEMA_VERSION,
|
|
2216
|
+
GOAL_INTELLIGENCE_SCHEMA_VERSION,
|
|
2217
|
+
GOAL_INTELLIGENCE_COMPACT_REF_LIMIT
|
|
2218
|
+
};
|