@alan512/experienceengine 0.3.4 → 0.3.5

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.
Files changed (36) hide show
  1. package/.mcp.json +11 -11
  2. package/README.md +8 -0
  3. package/README.zh-CN.md +8 -0
  4. package/dist/adapters/codex/action-registry.d.ts +3 -0
  5. package/dist/adapters/codex/action-registry.js +22 -0
  6. package/dist/adapters/codex/action-registry.js.map +1 -1
  7. package/dist/adapters/codex/broker-tools.d.ts +6 -0
  8. package/dist/adapters/codex/broker-tools.js +7 -1
  9. package/dist/adapters/codex/broker-tools.js.map +1 -1
  10. package/dist/adapters/codex/mcp-server.js +30 -0
  11. package/dist/adapters/codex/mcp-server.js.map +1 -1
  12. package/dist/cli/commands/inspect.js +41 -6
  13. package/dist/cli/commands/inspect.js.map +1 -1
  14. package/dist/cli/dispatch.js +11 -13
  15. package/dist/cli/dispatch.js.map +1 -1
  16. package/dist/install/openclaw-cli.d.ts +2 -0
  17. package/dist/install/openclaw-cli.js +5 -0
  18. package/dist/install/openclaw-cli.js.map +1 -1
  19. package/dist/install/openclaw-installer.js +65 -6
  20. package/dist/install/openclaw-installer.js.map +1 -1
  21. package/dist/interaction/quality-band.d.ts +30 -0
  22. package/dist/interaction/quality-band.js +149 -0
  23. package/dist/interaction/quality-band.js.map +1 -0
  24. package/dist/interaction/repo-summary.d.ts +3 -0
  25. package/dist/interaction/repo-summary.js +1 -0
  26. package/dist/interaction/repo-summary.js.map +1 -1
  27. package/dist/interaction/service.d.ts +3 -0
  28. package/dist/interaction/service.js +63 -81
  29. package/dist/interaction/service.js.map +1 -1
  30. package/dist/interaction/surface-tiers.d.ts +8 -0
  31. package/dist/interaction/surface-tiers.js +19 -0
  32. package/dist/interaction/surface-tiers.js.map +1 -0
  33. package/docs/releases/v0.3.5.md +42 -0
  34. package/docs/user-guide.md +30 -3
  35. package/openclaw.plugin.json +1 -1
  36. package/package.json +1 -1
@@ -0,0 +1,149 @@
1
+ export const deriveNodeRisk = (node) => {
2
+ if (node.state === "candidate") {
3
+ return "high";
4
+ }
5
+ if (node.state === "priority_candidate") {
6
+ return "medium";
7
+ }
8
+ if (node.state === "cooling" || node.harmed_count > 0 || node.node_type === "warning") {
9
+ return node.harmed_count > node.helped_count ? "high" : "medium";
10
+ }
11
+ return "low";
12
+ };
13
+ export const deriveNodeConfidence = (node) => {
14
+ if (node.validation_state === "validated_by_reuse" && node.state === "active" && node.harmed_count === 0) {
15
+ return "high";
16
+ }
17
+ if (node.state === "candidate" || node.harmed_count > node.helped_count) {
18
+ return "low";
19
+ }
20
+ return "medium";
21
+ };
22
+ const firstUnique = (items) => [...new Set(items)];
23
+ const buildEvidenceRefs = (node) => [
24
+ { kind: "node", id: node.id },
25
+ ...node.origin_record_ids.map((id) => ({ kind: "origin_record", id })),
26
+ ...node.helped_record_ids.map((id) => ({ kind: "helped_record", id })),
27
+ ...node.harmed_record_ids.map((id) => ({ kind: "harmed_record", id }))
28
+ ];
29
+ const actionForBand = (node, band) => {
30
+ if (band === "risky") {
31
+ return {
32
+ label: "Review this node before trusting it in live guidance.",
33
+ command: `ee inspect node ${node.id}`
34
+ };
35
+ }
36
+ if (band === "building") {
37
+ return {
38
+ label: "Use as tentative guidance and keep collecting outcome evidence.",
39
+ command: `ee inspect node ${node.id}`
40
+ };
41
+ }
42
+ return undefined;
43
+ };
44
+ export const deriveQualityBandExplanation = (node) => {
45
+ const reasonCodes = [];
46
+ const reasons = [];
47
+ const isHighHygieneRisk = node.delivery_state === "quarantined" || Boolean(node.quarantined_at);
48
+ const harmOutweighsHelp = node.harmed_count > node.helped_count;
49
+ let band = "building";
50
+ if (node.state === "retired" ||
51
+ node.state === "cooling" ||
52
+ node.validation_state === "invalidated" ||
53
+ harmOutweighsHelp ||
54
+ isHighHygieneRisk) {
55
+ band = "risky";
56
+ }
57
+ else if (node.state === "active" &&
58
+ node.validation_state === "validated_by_reuse" &&
59
+ node.harmed_count === 0 &&
60
+ (!node.delivery_state || node.delivery_state === "eligible")) {
61
+ band = "strong";
62
+ }
63
+ if (node.state === "active" && (!node.delivery_state || node.delivery_state === "eligible")) {
64
+ reasonCodes.push("active_eligible");
65
+ reasons.push("This node is active and eligible for normal delivery.");
66
+ }
67
+ if (node.validation_state === "validated_by_reuse") {
68
+ reasonCodes.push("validated_by_reuse");
69
+ reasons.push("This node has already been validated by successful reuse.");
70
+ }
71
+ if (node.helped_count > 0 && node.harmed_count === 0) {
72
+ reasonCodes.push("helped_without_harm");
73
+ reasons.push("Helpful outcomes exist and no harmful outcome has been recorded for this node.");
74
+ }
75
+ if (node.helped_count === 0 && node.harmed_count === 0) {
76
+ reasonCodes.push("limited_reuse_evidence");
77
+ reasons.push("This node still has limited reuse evidence.");
78
+ }
79
+ if (node.state === "candidate" || node.state === "priority_candidate") {
80
+ reasonCodes.push("early_lifecycle");
81
+ reasons.push("This node is still early in its lifecycle and needs more runtime evidence.");
82
+ }
83
+ if (node.delivery_state === "conservative_only") {
84
+ reasonCodes.push("conservative_only");
85
+ reasons.push("Delivery governance limits this node to conservative use.");
86
+ }
87
+ if (node.delivery_state === "shadow_only") {
88
+ reasonCodes.push("shadow_only");
89
+ reasons.push("Delivery governance keeps this node in shadow-only observation.");
90
+ }
91
+ if (node.state === "retired") {
92
+ reasonCodes.push("retired");
93
+ reasons.push("This node is retired and should not be reused without review.");
94
+ }
95
+ if (node.state === "cooling") {
96
+ reasonCodes.push("cooling");
97
+ reasons.push("This node is in cooling state because recent runtime evidence weakened confidence.");
98
+ }
99
+ if (harmOutweighsHelp) {
100
+ reasonCodes.push("harm_outweighs_help");
101
+ reasons.push("Harmful outcomes currently outweigh helpful ones for this node.");
102
+ }
103
+ else if (node.helped_count > node.harmed_count) {
104
+ reasons.push("Helpful outcomes still outweigh harmful ones for this node.");
105
+ }
106
+ if (node.delivery_state === "quarantined") {
107
+ reasonCodes.push("quarantined");
108
+ reasons.push(node.quarantine_reason ?? "Delivery governance has quarantined this node.");
109
+ }
110
+ if (isHighHygieneRisk) {
111
+ reasonCodes.push("high_hygiene_risk");
112
+ }
113
+ if (node.node_type === "warning") {
114
+ reasonCodes.push("warning_guidance");
115
+ reasons.push("This is warning guidance, so reuse should stay narrow and evidence-led.");
116
+ }
117
+ if (node.validation_state === "invalidated") {
118
+ reasonCodes.push("invalidated");
119
+ reasons.push("Reuse validation has invalidated this node.");
120
+ }
121
+ const summary = band === "strong"
122
+ ? "Strong guidance: active, reuse-validated guidance with no harmful feedback."
123
+ : band === "risky"
124
+ ? "Risky guidance: review before reuse because governance or outcome evidence weakened confidence."
125
+ : "Building guidance: usable with caution while ExperienceEngine gathers stronger reuse evidence.";
126
+ return {
127
+ band,
128
+ summary,
129
+ reasonCodes: firstUnique(reasonCodes),
130
+ reasons: firstUnique(reasons).slice(0, 4),
131
+ evidenceRefs: buildEvidenceRefs(node),
132
+ recommendedAction: actionForBand(node, band)
133
+ };
134
+ };
135
+ export const summarizeQualityBandDistribution = (explanations) => {
136
+ const distribution = explanations.reduce((counts, explanation) => {
137
+ counts[explanation.band] += 1;
138
+ return counts;
139
+ }, { strong: 0, building: 0, risky: 0 });
140
+ const total = explanations.length;
141
+ const summary = total === 0
142
+ ? "No experience nodes are available for this scope yet."
143
+ : `${distribution.strong} strong, ${distribution.building} building, ${distribution.risky} risky node(s) in this scope.`;
144
+ return {
145
+ ...distribution,
146
+ summary
147
+ };
148
+ };
149
+ //# sourceMappingURL=quality-band.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality-band.js","sourceRoot":"","sources":["../../src/interaction/quality-band.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import type { BenchmarkSummary } from "../evaluation/benchmark-summary.js";
2
2
  import type { RepoPolicyInspection } from "../experience-management/repo-policy.js";
3
3
  import type { RepoPolicy } from "../types/domain.js";
4
4
  import type { ExperienceLastInspection, ExperienceLearningSummary } from "./service.js";
5
+ import type { QualityBandDistribution } from "./quality-band.js";
5
6
  export type ExperienceRepoSummary = {
6
7
  scope: {
7
8
  scopeId: string;
@@ -19,6 +20,7 @@ export type ExperienceRepoSummary = {
19
20
  latestTrustSummary?: ExperienceLastInspection["trustSummary"];
20
21
  };
21
22
  benchmark: BenchmarkSummary;
23
+ quality: QualityBandDistribution;
22
24
  policy?: {
23
25
  configuredMode: RepoPolicy["configured_mode"];
24
26
  effectiveMode: RepoPolicy["effective_mode"];
@@ -42,6 +44,7 @@ export declare const buildRepoSummary: (input: {
42
44
  };
43
45
  latest?: ExperienceLastInspection;
44
46
  learning: ExperienceLearningSummary;
47
+ quality: QualityBandDistribution;
45
48
  policy?: RepoPolicy;
46
49
  policyInspection?: RepoPolicyInspection;
47
50
  }) => ExperienceRepoSummary;
@@ -25,6 +25,7 @@ export const buildRepoSummary = (input) => {
25
25
  latestTrustSummary: input.latest?.trustSummary
26
26
  },
27
27
  benchmark: input.learning.benchmark,
28
+ quality: input.quality,
28
29
  policy: policy
29
30
  ? {
30
31
  configuredMode: policy.configured_mode,
@@ -1 +1 @@
1
- {"version":3,"file":"repo-summary.js","sourceRoot":"","sources":["../../src/interaction/repo-summary.ts"],"names":[],"mappings":"AAsCA,MAAM,uBAAuB,GAAG,CAAC,SAA2B,EAAU,EAAE;IACtE,QAAQ,SAAS,CAAC,OAAO,EAAE,CAAC;QAC1B,KAAK,SAAS;YACZ,OAAO,gFAAgF,CAAC;QAC1F,KAAK,YAAY;YACf,OAAO,yGAAyG,CAAC;QACnH,KAAK,SAAS;YACZ,OAAO,sGAAsG,CAAC;QAChH;YACE,OAAO,uHAAuH,CAAC;IACnI,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAUhC,EAAyB,EAAE;IAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,EAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;IAE9D,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE;YACN,eAAe,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS;YACxC,iBAAiB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;YACxC,gBAAgB,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS;YACzC,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY;YAC9C,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY;YAC9C,wBAAwB,EAAE,KAAK,CAAC,MAAM,EAAE,kBAAkB;YAC1D,yBAAyB,EAAE,KAAK,CAAC,MAAM,EAAE,mBAAmB;YAC5D,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY;SAC/C;QACD,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,SAAS;QACnC,MAAM,EAAE,MAAM;YACZ,CAAC,CAAC;gBACE,cAAc,EAAE,MAAM,CAAC,eAAe;gBACtC,aAAa,EAAE,MAAM,CAAC,cAAc;gBACpC,YAAY,EAAE,MAAM,CAAC,aAAa;gBAClC,aAAa,EAAE,MAAM,CAAC,cAAc;gBACpC,uBAAuB,EAAE,MAAM,CAAC,yBAAyB;gBACzD,SAAS,EAAE,MAAM,CAAC,UAAU;gBAC5B,aAAa,EAAE,MAAM,CAAC,eAAe;gBACrC,UAAU,EAAE,MAAM,CAAC,WAAW;gBAC9B,eAAe,EAAE,KAAK,CAAC,gBAAgB,EAAE,eAAe;gBACxD,QAAQ,EAAE,KAAK,CAAC,gBAAgB,EAAE,QAAQ;gBAC1C,eAAe,EAAE,KAAK,CAAC,gBAAgB,EAAE,eAAe;aACzD;YACH,CAAC,CAAC,SAAS;QACb,qBAAqB,EAAE,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;KACzE,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"repo-summary.js","sourceRoot":"","sources":["../../src/interaction/repo-summary.ts"],"names":[],"mappings":"AAwCA,MAAM,uBAAuB,GAAG,CAAC,SAA2B,EAAU,EAAE;IACtE,QAAQ,SAAS,CAAC,OAAO,EAAE,CAAC;QAC1B,KAAK,SAAS;YACZ,OAAO,gFAAgF,CAAC;QAC1F,KAAK,YAAY;YACf,OAAO,yGAAyG,CAAC;QACnH,KAAK,SAAS;YACZ,OAAO,sGAAsG,CAAC;QAChH;YACE,OAAO,uHAAuH,CAAC;IACnI,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAWhC,EAAyB,EAAE;IAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,EAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;IAE9D,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE;YACN,eAAe,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS;YACxC,iBAAiB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;YACxC,gBAAgB,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS;YACzC,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY;YAC9C,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY;YAC9C,wBAAwB,EAAE,KAAK,CAAC,MAAM,EAAE,kBAAkB;YAC1D,yBAAyB,EAAE,KAAK,CAAC,MAAM,EAAE,mBAAmB;YAC5D,kBAAkB,EAAE,KAAK,CAAC,MAAM,EAAE,YAAY;SAC/C;QACD,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,SAAS;QACnC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,MAAM;YACZ,CAAC,CAAC;gBACE,cAAc,EAAE,MAAM,CAAC,eAAe;gBACtC,aAAa,EAAE,MAAM,CAAC,cAAc;gBACpC,YAAY,EAAE,MAAM,CAAC,aAAa;gBAClC,aAAa,EAAE,MAAM,CAAC,cAAc;gBACpC,uBAAuB,EAAE,MAAM,CAAC,yBAAyB;gBACzD,SAAS,EAAE,MAAM,CAAC,UAAU;gBAC5B,aAAa,EAAE,MAAM,CAAC,eAAe;gBACrC,UAAU,EAAE,MAAM,CAAC,WAAW;gBAC9B,eAAe,EAAE,KAAK,CAAC,gBAAgB,EAAE,eAAe;gBACxD,QAAQ,EAAE,KAAK,CAAC,gBAAgB,EAAE,QAAQ;gBAC1C,eAAe,EAAE,KAAK,CAAC,gBAAgB,EAAE,eAAe;aACzD;YACH,CAAC,CAAC,SAAS;QACb,qBAAqB,EAAE,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;KACzE,CAAC;AACJ,CAAC,CAAC"}
@@ -7,6 +7,7 @@ import { type HybridRouteDecision } from "../hybrid/router.js";
7
7
  import type { CandidateLifecycleState, DistillationSource, DistillationJobState, EvaluationMode, ExperienceInputRecord, FeedbackAttributionReason, AttributionRecord, EpisodeProjection, InjectionEvent, InjectionScorecard, ExperienceNode, ExperienceNodeType, ExperienceState, TaskRun } from "../types/domain.js";
8
8
  import { type ExperienceRepoSummary } from "./repo-summary.js";
9
9
  import { type RetrievalPolicyInspectionSummary } from "./retrieval-policy-inspection.js";
10
+ import { type ExperienceQualityBandExplanation } from "./quality-band.js";
10
11
  export type ExperienceNodeSummary = {
11
12
  id: string;
12
13
  type: ExperienceNode["node_type"];
@@ -30,6 +31,7 @@ export type ExperienceNodeSummary = {
30
31
  hint: string;
31
32
  qualityBand: "strong" | "building" | "risky";
32
33
  qualityDrivers: string[];
34
+ quality: ExperienceQualityBandExplanation;
33
35
  applicabilityProfile: {
34
36
  bestFit: string;
35
37
  scopeValidity: string;
@@ -74,6 +76,7 @@ export type ExperienceLastInspection = {
74
76
  scorecard?: InjectionScorecard;
75
77
  decisionExplanation?: string;
76
78
  trustSummary?: string;
79
+ qualityContext?: ExperienceQualityBandExplanation;
77
80
  retrievalNotes: string[];
78
81
  retrievalPolicySummary?: RetrievalPolicyInspectionSummary;
79
82
  timeline: ExperienceTimelineEntry[];
@@ -30,6 +30,7 @@ import { nowIso } from "../utils/clock.js";
30
30
  import { createId, stableId } from "../utils/ids.js";
31
31
  import { buildRepoSummary } from "./repo-summary.js";
32
32
  import { buildRetrievalPolicyInspectionSummary } from "./retrieval-policy-inspection.js";
33
+ import { deriveNodeConfidence, deriveNodeRisk, deriveQualityBandExplanation, summarizeQualityBandDistribution } from "./quality-band.js";
33
34
  const normalizeHybridExplainPrompt = (value) => value
34
35
  .toLowerCase()
35
36
  .replace(/\s+/g, " ")
@@ -163,90 +164,43 @@ const toManualOverrideAttributionRecord = (input) => {
163
164
  resolved_at: timestamp
164
165
  };
165
166
  };
166
- const deriveNodeRisk = (node) => {
167
- if (node.state === "candidate") {
168
- return "high";
169
- }
170
- if (node.state === "priority_candidate") {
171
- return "medium";
172
- }
173
- if (node.state === "cooling" || node.harmed_count > 0 || node.node_type === "warning") {
174
- return node.harmed_count > node.helped_count ? "high" : "medium";
175
- }
176
- return "low";
177
- };
178
- const deriveQualityBand = (node) => {
179
- if (node.state === "retired" || node.harmed_count > node.helped_count || deriveNodeRisk(node) === "high") {
180
- return "risky";
181
- }
182
- if (node.state === "active" &&
183
- node.validation_state === "validated_by_reuse" &&
184
- node.harmed_count === 0) {
185
- return "strong";
186
- }
187
- return "building";
188
- };
189
- const buildQualityDrivers = (node) => {
190
- const drivers = [];
191
- if (node.validation_state === "validated_by_reuse") {
192
- drivers.push("This node has already been validated by successful reuse.");
193
- }
194
- if (node.helped_count > node.harmed_count) {
195
- drivers.push("Helpful outcomes still outweigh harmful ones for this node.");
196
- }
197
- else if (node.harmed_count > node.helped_count) {
198
- drivers.push("Harmful outcomes currently outweigh helpful ones for this node.");
199
- }
200
- if (node.state === "candidate" || node.state === "priority_candidate") {
201
- drivers.push("This node is still early in its lifecycle and needs more runtime evidence.");
202
- }
203
- else if (node.state === "cooling") {
204
- drivers.push("This node is in cooling state because recent runtime evidence weakened confidence.");
205
- }
206
- return drivers.slice(0, 3);
207
- };
208
- const deriveConfidence = (node) => {
209
- if (node.validation_state === "validated_by_reuse" && node.state === "active" && node.harmed_count === 0) {
210
- return "high";
211
- }
212
- if (node.state === "candidate" || node.harmed_count > node.helped_count) {
213
- return "low";
214
- }
215
- return "medium";
216
- };
217
167
  const formatTaskFamily = (taskType) => taskType === "general" ? "general tasks" : `${taskType} tasks`;
218
168
  const buildApplicabilityProfile = (node) => ({
219
169
  bestFit: `${formatTaskFamily(node.task_type)} in this repo scope`,
220
170
  scopeValidity: node.applicability_notes ?? "Use within the same repo scope unless fresh evidence says otherwise.",
221
- confidence: deriveConfidence(node),
171
+ confidence: deriveNodeConfidence(node),
222
172
  risk: deriveNodeRisk(node),
223
173
  avoidWhen: node.stop_condition ?? node.escalation_condition ?? node.avoid_steps?.[0]
224
174
  });
225
- const toNodeSummary = (node) => ({
226
- id: node.id,
227
- type: node.node_type,
228
- taskType: node.task_type,
229
- state: node.state,
230
- sourceKind: node.source_kind,
231
- distillationMode: node.distillation_mode_used,
232
- distillationSource: node.distillation_source,
233
- redistilledFrom: node.redistilled_from,
234
- promotionSignal: node.promotion_signal,
235
- promotionReason: node.promotion_reason,
236
- mergeDecision: node.merge_decision,
237
- mergeReason: node.merge_reason,
238
- priorityPromotionApplied: node.priority_promotion_applied,
239
- triggerPattern: node.trigger_pattern,
240
- evidenceSummary: node.evidence_summary,
241
- originRecordIds: node.origin_record_ids,
242
- helped: node.helped_count,
243
- harmed: node.harmed_count,
244
- lastUsedAt: node.last_used_at,
245
- hint: node.compact_hint,
246
- qualityBand: deriveQualityBand(node),
247
- qualityDrivers: buildQualityDrivers(node),
248
- applicabilityProfile: buildApplicabilityProfile(node)
249
- });
175
+ const toNodeSummary = (node) => {
176
+ const quality = deriveQualityBandExplanation(node);
177
+ return {
178
+ id: node.id,
179
+ type: node.node_type,
180
+ taskType: node.task_type,
181
+ state: node.state,
182
+ sourceKind: node.source_kind,
183
+ distillationMode: node.distillation_mode_used,
184
+ distillationSource: node.distillation_source,
185
+ redistilledFrom: node.redistilled_from,
186
+ promotionSignal: node.promotion_signal,
187
+ promotionReason: node.promotion_reason,
188
+ mergeDecision: node.merge_decision,
189
+ mergeReason: node.merge_reason,
190
+ priorityPromotionApplied: node.priority_promotion_applied,
191
+ triggerPattern: node.trigger_pattern,
192
+ evidenceSummary: node.evidence_summary,
193
+ originRecordIds: node.origin_record_ids,
194
+ helped: node.helped_count,
195
+ harmed: node.harmed_count,
196
+ lastUsedAt: node.last_used_at,
197
+ hint: node.compact_hint,
198
+ qualityBand: quality.band,
199
+ qualityDrivers: quality.reasons,
200
+ quality,
201
+ applicabilityProfile: buildApplicabilityProfile(node)
202
+ };
203
+ };
250
204
  const toNodeDetail = (node) => ({
251
205
  ...toNodeSummary(node),
252
206
  scopeId: node.scope_id,
@@ -390,6 +344,18 @@ const buildTrustSummary = (input) => {
390
344
  const confidence = scorecard.confidence ? ` ${scorecard.confidence}-confidence` : "";
391
345
  return `${scorecard.riskLevel}-risk${confidence} ${primaryNode.state} guidance with ${primaryNode.helped} helped and ${primaryNode.harmed} harmed signal(s).`;
392
346
  };
347
+ const buildQualityContext = (input) => {
348
+ const primaryInjected = input.injectedNodes[0]?.quality;
349
+ if (primaryInjected) {
350
+ return primaryInjected;
351
+ }
352
+ const topCandidateId = input.scorecard?.topCandidates?.[0]?.id;
353
+ if (!topCandidateId) {
354
+ return undefined;
355
+ }
356
+ const candidateNode = input.lookupNode(topCandidateId);
357
+ return candidateNode ? deriveQualityBandExplanation(candidateNode) : undefined;
358
+ };
393
359
  const buildRetrievalNotes = (scorecard) => {
394
360
  if (!scorecard) {
395
361
  return [];
@@ -579,6 +545,12 @@ export class ExperienceInteractionService {
579
545
  outcome: record.outcome_signal
580
546
  });
581
547
  const decisionExplanation = buildDecisionExplanation({ intervention, scorecard });
548
+ const injectedNodeSummaries = injectedNodes.map(toNodeSummary);
549
+ const qualityContext = buildQualityContext({
550
+ scorecard,
551
+ injectedNodes: injectedNodeSummaries,
552
+ lookupNode: (nodeId) => this.nodeRepo.getById(nodeId)
553
+ });
582
554
  return {
583
555
  sessionId: record.session_id,
584
556
  episodeId: record.episode_id,
@@ -592,12 +564,13 @@ export class ExperienceInteractionService {
592
564
  attributionRecords,
593
565
  episodeProjection,
594
566
  outcome: record.outcome_signal,
595
- injectedNodes: injectedNodes.map(toNodeSummary),
567
+ injectedNodes: injectedNodeSummaries,
596
568
  hints: injectedNodes.map((node) => node.compact_hint),
597
569
  evidence: record.evidence,
598
570
  scorecard,
599
571
  decisionExplanation,
600
- trustSummary: buildTrustSummary({ scorecard, injectedNodes: injectedNodes.map(toNodeSummary) }),
572
+ trustSummary: buildTrustSummary({ scorecard, injectedNodes: injectedNodeSummaries }),
573
+ qualityContext,
601
574
  retrievalNotes: buildRetrievalNotes(scorecard),
602
575
  retrievalPolicySummary: buildRetrievalPolicyInspectionSummary(scorecard),
603
576
  timeline: buildLatestTimeline({
@@ -645,6 +618,12 @@ export class ExperienceInteractionService {
645
618
  (taskRun?.final_status === "success" ? "success" : taskRun?.final_status === "failure" ? "failure" : "unknown");
646
619
  const summary = event.task_summary ?? taskRun?.task_summary ?? "Latest injection event";
647
620
  const decisionExplanation = buildDecisionExplanation({ intervention, scorecard: event.scorecard });
621
+ const injectedNodeSummaries = injectedNodes.map(toNodeSummary);
622
+ const qualityContext = buildQualityContext({
623
+ scorecard: event.scorecard,
624
+ injectedNodes: injectedNodeSummaries,
625
+ lookupNode: (nodeId) => this.nodeRepo.getById(nodeId)
626
+ });
648
627
  return {
649
628
  sessionId: event.session_id,
650
629
  episodeId: event.episode_id,
@@ -663,12 +642,13 @@ export class ExperienceInteractionService {
663
642
  attributionRecords,
664
643
  episodeProjection,
665
644
  outcome,
666
- injectedNodes: injectedNodes.map(toNodeSummary),
645
+ injectedNodes: injectedNodeSummaries,
667
646
  hints: injectedNodes.map((node) => node.compact_hint),
668
647
  evidence: [],
669
648
  scorecard: event.scorecard,
670
649
  decisionExplanation,
671
- trustSummary: buildTrustSummary({ scorecard: event.scorecard, injectedNodes: injectedNodes.map(toNodeSummary) }),
650
+ trustSummary: buildTrustSummary({ scorecard: event.scorecard, injectedNodes: injectedNodeSummaries }),
651
+ qualityContext,
672
652
  retrievalNotes: buildRetrievalNotes(event.scorecard),
673
653
  retrievalPolicySummary: buildRetrievalPolicyInspectionSummary(event.scorecard),
674
654
  timeline: buildLatestTimeline({
@@ -889,6 +869,7 @@ export class ExperienceInteractionService {
889
869
  const latest = latestRecord ? this.inspectRecord(latestRecord) : undefined;
890
870
  const learning = this.buildLearningSummary(scope.scope_id);
891
871
  const policyInspection = this.inspectRepoPolicy(cwd);
872
+ const quality = summarizeQualityBandDistribution(this.nodeRepo.listByScope(scope.scope_id).map((node) => deriveQualityBandExplanation(node)));
892
873
  return buildRepoSummary({
893
874
  scope: {
894
875
  scopeId: scope.scope_id,
@@ -897,6 +878,7 @@ export class ExperienceInteractionService {
897
878
  },
898
879
  latest: latest && latest.scopeId === scope.scope_id ? latest : undefined,
899
880
  learning,
881
+ quality,
900
882
  policyInspection
901
883
  });
902
884
  }