principles-disciple 1.7.5 → 1.7.8

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 (129) hide show
  1. package/dist/commands/context.js +5 -15
  2. package/dist/commands/evolution-status.js +29 -48
  3. package/dist/commands/export.js +61 -8
  4. package/dist/commands/nocturnal-review.d.ts +24 -0
  5. package/dist/commands/nocturnal-review.js +265 -0
  6. package/dist/commands/nocturnal-rollout.d.ts +27 -0
  7. package/dist/commands/nocturnal-rollout.js +671 -0
  8. package/dist/commands/nocturnal-train.d.ts +25 -0
  9. package/dist/commands/nocturnal-train.js +919 -0
  10. package/dist/commands/pain.js +8 -21
  11. package/dist/config/defaults/runtime.d.ts +40 -0
  12. package/dist/config/defaults/runtime.js +44 -0
  13. package/dist/config/errors.d.ts +84 -0
  14. package/dist/config/errors.js +94 -0
  15. package/dist/config/index.d.ts +7 -0
  16. package/dist/config/index.js +7 -0
  17. package/dist/constants/diagnostician.d.ts +0 -4
  18. package/dist/constants/diagnostician.js +0 -4
  19. package/dist/constants/tools.d.ts +2 -2
  20. package/dist/constants/tools.js +1 -1
  21. package/dist/core/adaptive-thresholds.d.ts +186 -0
  22. package/dist/core/adaptive-thresholds.js +300 -0
  23. package/dist/core/config.d.ts +2 -38
  24. package/dist/core/config.js +6 -61
  25. package/dist/core/control-ui-db.d.ts +27 -0
  26. package/dist/core/control-ui-db.js +18 -0
  27. package/dist/core/event-log.d.ts +1 -2
  28. package/dist/core/event-log.js +0 -3
  29. package/dist/core/evolution-engine.js +1 -21
  30. package/dist/core/evolution-reducer.d.ts +7 -1
  31. package/dist/core/evolution-reducer.js +56 -4
  32. package/dist/core/evolution-types.d.ts +61 -9
  33. package/dist/core/evolution-types.js +31 -9
  34. package/dist/core/external-training-contract.d.ts +276 -0
  35. package/dist/core/external-training-contract.js +269 -0
  36. package/dist/core/local-worker-routing.d.ts +175 -0
  37. package/dist/core/local-worker-routing.js +525 -0
  38. package/dist/core/model-deployment-registry.d.ts +218 -0
  39. package/dist/core/model-deployment-registry.js +503 -0
  40. package/dist/core/model-training-registry.d.ts +295 -0
  41. package/dist/core/model-training-registry.js +475 -0
  42. package/dist/core/nocturnal-arbiter.d.ts +159 -0
  43. package/dist/core/nocturnal-arbiter.js +534 -0
  44. package/dist/core/nocturnal-candidate-scoring.d.ts +137 -0
  45. package/dist/core/nocturnal-candidate-scoring.js +266 -0
  46. package/dist/core/nocturnal-compliance.d.ts +175 -0
  47. package/dist/core/nocturnal-compliance.js +824 -0
  48. package/dist/core/nocturnal-dataset.d.ts +224 -0
  49. package/dist/core/nocturnal-dataset.js +443 -0
  50. package/dist/core/nocturnal-executability.d.ts +85 -0
  51. package/dist/core/nocturnal-executability.js +331 -0
  52. package/dist/core/nocturnal-export.d.ts +124 -0
  53. package/dist/core/nocturnal-export.js +275 -0
  54. package/dist/core/nocturnal-paths.d.ts +124 -0
  55. package/dist/core/nocturnal-paths.js +214 -0
  56. package/dist/core/nocturnal-trajectory-extractor.d.ts +242 -0
  57. package/dist/core/nocturnal-trajectory-extractor.js +307 -0
  58. package/dist/core/nocturnal-trinity.d.ts +311 -0
  59. package/dist/core/nocturnal-trinity.js +880 -0
  60. package/dist/core/path-resolver.js +2 -1
  61. package/dist/core/paths.d.ts +6 -0
  62. package/dist/core/paths.js +6 -0
  63. package/dist/core/principle-training-state.d.ts +121 -0
  64. package/dist/core/principle-training-state.js +321 -0
  65. package/dist/core/promotion-gate.d.ts +238 -0
  66. package/dist/core/promotion-gate.js +529 -0
  67. package/dist/core/session-tracker.d.ts +10 -0
  68. package/dist/core/session-tracker.js +14 -0
  69. package/dist/core/shadow-observation-registry.d.ts +217 -0
  70. package/dist/core/shadow-observation-registry.js +308 -0
  71. package/dist/core/training-program.d.ts +233 -0
  72. package/dist/core/training-program.js +433 -0
  73. package/dist/core/trajectory.d.ts +155 -1
  74. package/dist/core/trajectory.js +292 -8
  75. package/dist/core/workspace-context.d.ts +0 -6
  76. package/dist/core/workspace-context.js +0 -12
  77. package/dist/hooks/bash-risk.d.ts +57 -0
  78. package/dist/hooks/bash-risk.js +137 -0
  79. package/dist/hooks/edit-verification.d.ts +62 -0
  80. package/dist/hooks/edit-verification.js +256 -0
  81. package/dist/hooks/gate-block-helper.d.ts +44 -0
  82. package/dist/hooks/gate-block-helper.js +119 -0
  83. package/dist/hooks/gate.d.ts +18 -0
  84. package/dist/hooks/gate.js +62 -751
  85. package/dist/hooks/gfi-gate.d.ts +40 -0
  86. package/dist/hooks/gfi-gate.js +113 -0
  87. package/dist/hooks/pain.js +6 -9
  88. package/dist/hooks/progressive-trust-gate.d.ts +51 -0
  89. package/dist/hooks/progressive-trust-gate.js +89 -0
  90. package/dist/hooks/prompt.d.ts +11 -11
  91. package/dist/hooks/prompt.js +167 -77
  92. package/dist/hooks/subagent.js +43 -6
  93. package/dist/hooks/thinking-checkpoint.d.ts +37 -0
  94. package/dist/hooks/thinking-checkpoint.js +51 -0
  95. package/dist/http/principles-console-route.js +13 -3
  96. package/dist/i18n/commands.js +8 -8
  97. package/dist/index.js +129 -28
  98. package/dist/service/central-database.js +2 -1
  99. package/dist/service/control-ui-query-service.d.ts +1 -1
  100. package/dist/service/control-ui-query-service.js +3 -3
  101. package/dist/service/evolution-query-service.d.ts +1 -1
  102. package/dist/service/evolution-query-service.js +5 -5
  103. package/dist/service/evolution-worker.d.ts +52 -4
  104. package/dist/service/evolution-worker.js +328 -16
  105. package/dist/service/nocturnal-runtime.d.ts +183 -0
  106. package/dist/service/nocturnal-runtime.js +352 -0
  107. package/dist/service/nocturnal-service.d.ts +163 -0
  108. package/dist/service/nocturnal-service.js +787 -0
  109. package/dist/service/nocturnal-target-selector.d.ts +145 -0
  110. package/dist/service/nocturnal-target-selector.js +315 -0
  111. package/dist/service/phase3-input-filter.d.ts +48 -12
  112. package/dist/service/phase3-input-filter.js +84 -18
  113. package/dist/service/runtime-summary-service.d.ts +34 -10
  114. package/dist/service/runtime-summary-service.js +87 -48
  115. package/dist/tools/deep-reflect.js +2 -1
  116. package/dist/types/event-types.d.ts +4 -10
  117. package/dist/types/runtime-summary.d.ts +47 -0
  118. package/dist/types/runtime-summary.js +1 -0
  119. package/dist/types.d.ts +0 -3
  120. package/dist/types.js +0 -2
  121. package/openclaw.plugin.json +1 -1
  122. package/package.json +1 -1
  123. package/templates/langs/en/skills/pd-mentor/SKILL.md +5 -5
  124. package/templates/langs/zh/skills/pd-mentor/SKILL.md +5 -5
  125. package/templates/pain_settings.json +0 -6
  126. package/dist/commands/trust.d.ts +0 -4
  127. package/dist/commands/trust.js +0 -78
  128. package/dist/core/trust-engine.d.ts +0 -96
  129. package/dist/core/trust-engine.js +0 -286
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Adaptive Thresholds — Bounded Threshold State Management
3
+ * ========================================================
4
+ *
5
+ * PURPOSE: Manage adaptive thresholds for Trinity candidate scoring with
6
+ * bounded, observable, and reproducible threshold changes.
7
+ *
8
+ * DESIGN CONSTRAINTS:
9
+ * - Thresholds only move within bounded ranges (min/max)
10
+ * - Changes depend on explicit observable signals only
11
+ * - No hidden learning loops
12
+ * - Threshold state is persisted and can be rolled back
13
+ * - Corruption or missing state falls back to safe defaults
14
+ *
15
+ * OBSERVABLE SIGNALS:
16
+ * - recent malformed rate (arbiter/executability failures)
17
+ * - recent arbiter reject rate
18
+ * - recent executability reject rate
19
+ * - reviewed subset quality delta
20
+ *
21
+ * PHASE 6 ONLY — No real training, no automatic deployment
22
+ */
23
+ import * as fs from 'fs';
24
+ import * as path from 'path';
25
+ import { withLock } from '../utils/file-lock.js';
26
+ // ---------------------------------------------------------------------------
27
+ // Constants
28
+ // ---------------------------------------------------------------------------
29
+ /** File name for threshold state */
30
+ export const THRESHOLD_STATE_FILE = 'nocturnal-threshold-state.json';
31
+ /** Default threshold values */
32
+ export const DEFAULT_THRESHOLDS = {
33
+ /** Minimum score to pass arbiter validation */
34
+ schemaCompletenessMin: 0.6,
35
+ /** Minimum principle alignment score */
36
+ principleAlignmentMin: 0.7,
37
+ /** Minimum executability score */
38
+ executabilityMin: 0.65,
39
+ /** Minimum boundedness score */
40
+ boundednessMin: 0.5,
41
+ /** Minimum confidence/consistency score */
42
+ confidenceMin: 0.6,
43
+ /** Minimum aggregate score to be tournament-eligible */
44
+ aggregateMin: 0.65,
45
+ };
46
+ /** Minimum threshold value (safety bound) */
47
+ export const THRESHOLD_MIN = 0.0;
48
+ /** Maximum threshold value (safety bound) */
49
+ export const THRESHOLD_MAX = 1.0;
50
+ /** Maximum adjustment per update (bounded step size) */
51
+ export const MAX_ADJUSTMENT_PER_STEP = 0.05;
52
+ /** Minimum adjustment to trigger a change */
53
+ export const MIN_ADJUSTMENT_TO_RECORD = 0.01;
54
+ // ---------------------------------------------------------------------------
55
+ // State Persistence
56
+ // ---------------------------------------------------------------------------
57
+ /**
58
+ * Get the threshold state file path.
59
+ */
60
+ function getStatePath(stateDir) {
61
+ return path.join(stateDir, THRESHOLD_STATE_FILE);
62
+ }
63
+ /**
64
+ * Create default threshold persistence state.
65
+ */
66
+ function createDefaultState() {
67
+ const now = new Date().toISOString();
68
+ const thresholds = {};
69
+ for (const [name, defaultValue] of Object.entries(DEFAULT_THRESHOLDS)) {
70
+ thresholds[name] = {
71
+ currentValue: defaultValue,
72
+ minValue: THRESHOLD_MIN,
73
+ maxValue: THRESHOLD_MAX,
74
+ lastUpdatedAt: now,
75
+ adjustmentCount: 0,
76
+ };
77
+ }
78
+ return {
79
+ thresholds,
80
+ lastUpdatedAt: now,
81
+ version: 1,
82
+ };
83
+ }
84
+ /**
85
+ * Read threshold state from disk (with locking).
86
+ */
87
+ function readState(stateDir) {
88
+ const statePath = getStatePath(stateDir);
89
+ if (!fs.existsSync(statePath)) {
90
+ return null;
91
+ }
92
+ try {
93
+ const content = fs.readFileSync(statePath, 'utf-8');
94
+ const parsed = JSON.parse(content);
95
+ return parsed;
96
+ }
97
+ catch {
98
+ // Corrupted — return null to trigger default fallback
99
+ return null;
100
+ }
101
+ }
102
+ /**
103
+ * Write threshold state to disk (with locking).
104
+ */
105
+ function writeState(stateDir, state) {
106
+ const statePath = getStatePath(stateDir);
107
+ const stateDirPath = path.dirname(statePath);
108
+ if (!fs.existsSync(stateDirPath)) {
109
+ fs.mkdirSync(stateDirPath, { recursive: true });
110
+ }
111
+ withLock(statePath, () => {
112
+ const tmpPath = `${statePath}.tmp`;
113
+ fs.writeFileSync(tmpPath, JSON.stringify(state, null, 2), 'utf-8');
114
+ fs.renameSync(tmpPath, statePath);
115
+ });
116
+ }
117
+ // ---------------------------------------------------------------------------
118
+ // Core Threshold Operations
119
+ // ---------------------------------------------------------------------------
120
+ /**
121
+ * Load threshold values with fallback to defaults on corruption.
122
+ *
123
+ * @param stateDir - State directory
124
+ * @returns LoadThresholdResult with current values and status
125
+ */
126
+ export function loadThresholdState(stateDir) {
127
+ const rawState = readState(stateDir);
128
+ if (!rawState) {
129
+ return {
130
+ success: true,
131
+ thresholds: { ...DEFAULT_THRESHOLDS },
132
+ usedDefaults: true,
133
+ };
134
+ }
135
+ // Validate and reconstruct threshold values
136
+ const thresholds = { ...DEFAULT_THRESHOLDS };
137
+ let usedDefaults = false;
138
+ for (const [name, defaultValue] of Object.entries(DEFAULT_THRESHOLDS)) {
139
+ const key = name;
140
+ const state = rawState.thresholds[key];
141
+ if (state && typeof state.currentValue === 'number') {
142
+ // Clamp to bounds (defensive)
143
+ thresholds[key] = Math.max(state.minValue, Math.min(state.maxValue, state.currentValue));
144
+ }
145
+ else {
146
+ thresholds[key] = defaultValue;
147
+ usedDefaults = true;
148
+ }
149
+ }
150
+ return {
151
+ success: true,
152
+ thresholds: thresholds,
153
+ usedDefaults,
154
+ };
155
+ }
156
+ /**
157
+ * Get effective threshold values (alias for loadThresholdState).
158
+ *
159
+ * @param stateDir - State directory
160
+ * @returns Current threshold values
161
+ */
162
+ export function getEffectiveThresholds(stateDir) {
163
+ const result = loadThresholdState(stateDir);
164
+ return result.thresholds;
165
+ }
166
+ /**
167
+ * Update a single threshold with bounded step size.
168
+ *
169
+ * @param stateDir - State directory
170
+ * @param thresholdName - Name of threshold to update
171
+ * @param newValue - New value (will be clamped to bounds)
172
+ * @param reason - Reason for the adjustment (required for tracking)
173
+ * @returns UpdateThresholdResult
174
+ */
175
+ export function updateThresholdState(stateDir, thresholdName, newValue, reason) {
176
+ // Read current state
177
+ let rawState = readState(stateDir);
178
+ if (!rawState) {
179
+ rawState = createDefaultState();
180
+ }
181
+ const currentState = rawState.thresholds[thresholdName];
182
+ if (!currentState) {
183
+ return {
184
+ success: false,
185
+ thresholds: { ...DEFAULT_THRESHOLDS },
186
+ changed: false,
187
+ error: `Unknown threshold: ${thresholdName}`,
188
+ };
189
+ }
190
+ // Calculate bounded new value
191
+ const clampedValue = Math.max(currentState.minValue, Math.min(currentState.maxValue, newValue));
192
+ // Check if change is meaningful
193
+ const delta = Math.abs(clampedValue - currentState.currentValue);
194
+ if (delta < MIN_ADJUSTMENT_TO_RECORD) {
195
+ return {
196
+ success: true,
197
+ thresholds: getEffectiveThresholds(stateDir),
198
+ changed: false,
199
+ };
200
+ }
201
+ // Enforce maximum step size for bounded, safe threshold adjustments
202
+ let finalValue = clampedValue;
203
+ if (delta > MAX_ADJUSTMENT_PER_STEP) {
204
+ const direction = clampedValue > currentState.currentValue ? 1 : -1;
205
+ finalValue = currentState.currentValue + direction * MAX_ADJUSTMENT_PER_STEP;
206
+ }
207
+ // Update state
208
+ const now = new Date().toISOString();
209
+ rawState.thresholds[thresholdName] = {
210
+ ...currentState,
211
+ currentValue: finalValue,
212
+ lastUpdatedAt: now,
213
+ adjustmentReason: reason,
214
+ adjustmentCount: currentState.adjustmentCount + 1,
215
+ };
216
+ rawState.lastUpdatedAt = now;
217
+ writeState(stateDir, rawState);
218
+ return {
219
+ success: true,
220
+ thresholds: getEffectiveThresholds(stateDir),
221
+ changed: true,
222
+ changedThreshold: thresholdName,
223
+ oldValue: currentState.currentValue,
224
+ newValue: finalValue,
225
+ reason,
226
+ };
227
+ }
228
+ /**
229
+ * Reset all thresholds to defaults.
230
+ *
231
+ * @param stateDir - State directory
232
+ */
233
+ export function resetThresholdState(stateDir) {
234
+ const defaultState = createDefaultState();
235
+ writeState(stateDir, defaultState);
236
+ }
237
+ /**
238
+ * Get detailed threshold state for debugging/inspection.
239
+ *
240
+ * @param stateDir - State directory
241
+ * @returns Detailed threshold state or null if corrupted
242
+ */
243
+ export function getDetailedThresholdState(stateDir) {
244
+ return readState(stateDir);
245
+ }
246
+ // ---------------------------------------------------------------------------
247
+ // Signal-Based Threshold Adjustment
248
+ // ---------------------------------------------------------------------------
249
+ /**
250
+ * Adjust thresholds based on observable signals.
251
+ *
252
+ * This is a simple proportional controller that adjusts thresholds
253
+ * based on observed rejection rates. The adjustment is bounded
254
+ * and requires a minimum signal magnitude to trigger.
255
+ *
256
+ * @param stateDir - State directory
257
+ * @param signals - Observable signals
258
+ * @returns UpdateThresholdResult describing the most significant change
259
+ */
260
+ export function adjustThresholdsFromSignals(stateDir, signals) {
261
+ const currentThresholds = getEffectiveThresholds(stateDir);
262
+ let bestResult = {
263
+ success: true,
264
+ thresholds: currentThresholds,
265
+ changed: false,
266
+ };
267
+ // High malformed rate → tighten schema completeness threshold
268
+ if (signals.malformedRate > 0.3) {
269
+ const adjustment = signals.malformedRate * 0.1;
270
+ const newValue = currentThresholds.schemaCompletenessMin + adjustment;
271
+ const result = updateThresholdState(stateDir, 'schemaCompletenessMin', newValue, `High malformed rate (${signals.malformedRate.toFixed(2)}) → tightening schema threshold`);
272
+ if (result.changed)
273
+ bestResult = result;
274
+ }
275
+ // High arbiter reject rate → tighten principle alignment threshold
276
+ if (signals.arbiterRejectRate > 0.25) {
277
+ const adjustment = signals.arbiterRejectRate * 0.08;
278
+ const result = updateThresholdState(stateDir, 'principleAlignmentMin', currentThresholds.principleAlignmentMin + adjustment, `High arbiter reject rate (${signals.arbiterRejectRate.toFixed(2)}) → tightening alignment threshold`);
279
+ if (result.changed && (!bestResult.changed || (result.newValue - result.oldValue) > 0)) {
280
+ bestResult = result;
281
+ }
282
+ }
283
+ // High executability reject rate → tighten executability threshold
284
+ if (signals.executabilityRejectRate > 0.3) {
285
+ const adjustment = signals.executabilityRejectRate * 0.1;
286
+ const result = updateThresholdState(stateDir, 'executabilityMin', currentThresholds.executabilityMin + adjustment, `High executability reject rate (${signals.executabilityRejectRate.toFixed(2)}) → tightening executability threshold`);
287
+ if (result.changed && (!bestResult.changed || (result.newValue - result.oldValue) > 0)) {
288
+ bestResult = result;
289
+ }
290
+ }
291
+ // Good quality delta → slightly loosen thresholds (reward good performance)
292
+ if (signals.qualityDelta > 0.1) {
293
+ const reward = Math.min(signals.qualityDelta * 0.05, MAX_ADJUSTMENT_PER_STEP);
294
+ const result = updateThresholdState(stateDir, 'aggregateMin', Math.max(currentThresholds.aggregateMin - reward, THRESHOLD_MIN), `Positive quality delta (${signals.qualityDelta.toFixed(2)}) → rewarding with slightly lower aggregate threshold`);
295
+ if (result.changed && (!bestResult.changed || (result.oldValue - result.newValue) > 0)) {
296
+ bestResult = result;
297
+ }
298
+ }
299
+ return bestResult;
300
+ }
@@ -21,51 +21,16 @@ export interface GfiGateSettings {
21
21
  large_change_block: number;
22
22
  };
23
23
  large_change_lines: number;
24
- trust_stage_multipliers: {
24
+ ep_tier_multipliers: {
25
25
  '1': number;
26
26
  '2': number;
27
27
  '3': number;
28
28
  '4': number;
29
+ '5': number;
29
30
  };
30
31
  bash_safe_patterns: string[];
31
32
  bash_dangerous_patterns: string[];
32
33
  }
33
- export interface TrustSettings {
34
- stages: {
35
- stage_1_observer: number;
36
- stage_2_editor: number;
37
- stage_3_developer: number;
38
- };
39
- cold_start: {
40
- initial_trust: number;
41
- grace_failures: number;
42
- cold_start_period_ms: number;
43
- };
44
- penalties: {
45
- tool_failure_base: number;
46
- risky_failure_base: number;
47
- gate_bypass_attempt: number;
48
- failure_streak_multiplier: number;
49
- max_penalty: number;
50
- };
51
- rewards: {
52
- success_base: number;
53
- subagent_success: number;
54
- tool_success_reward: number;
55
- streak_bonus_threshold: number;
56
- streak_bonus: number;
57
- recovery_boost: number;
58
- max_reward: number;
59
- };
60
- limits: {
61
- stage_2_max_lines: number;
62
- stage_3_max_lines: number;
63
- stage_2_max_percentage: number;
64
- stage_3_max_percentage: number;
65
- min_lines_fallback: number;
66
- };
67
- history_limit?: number;
68
- }
69
34
  export interface DiagnosticianSettings {
70
35
  context: {
71
36
  time_window_minutes: number;
@@ -110,7 +75,6 @@ export interface PainSettings {
110
75
  initial_delay_ms: number;
111
76
  task_timeout_ms: number;
112
77
  };
113
- trust: TrustSettings;
114
78
  deep_reflection?: DeepReflectionSettings;
115
79
  empathy_engine?: {
116
80
  enabled?: boolean;
@@ -46,46 +46,6 @@ export const DEFAULT_SETTINGS = {
46
46
  initial_delay_ms: 5000,
47
47
  task_timeout_ms: 60 * 60 * 1000 // 1 hour, matching evolution-worker.ts default
48
48
  },
49
- trust: {
50
- stages: {
51
- stage_1_observer: 30,
52
- stage_2_editor: 60,
53
- stage_3_developer: 80,
54
- },
55
- cold_start: {
56
- // 🚀 The most important change: Start at 85 (Developer level)
57
- // This allows the AI to perform medium-sized edits right out of the box
58
- // without needing to beg for a PLAN.md on every single change.
59
- initial_trust: 85,
60
- grace_failures: 5, // Give the AI 5 free mistakes before deducting any trust points
61
- cold_start_period_ms: 24 * 60 * 60 * 1000,
62
- },
63
- penalties: {
64
- // 🛡️ Forgiving penalties for exploration
65
- tool_failure_base: -2, // Was -8. A simple 'ls' typo shouldn't cost 8 points.
66
- risky_failure_base: -10, // Was -15.
67
- gate_bypass_attempt: -5,
68
- failure_streak_multiplier: -2,
69
- max_penalty: -20,
70
- },
71
- rewards: {
72
- success_base: 2, // Was 1. Faster recovery
73
- subagent_success: 5, // Was 3.
74
- tool_success_reward: 0.2, // 👈 Minor reward for tool success, but resets streak!
75
- streak_bonus_threshold: 3, // Was 5. Easier to get bonuses
76
- streak_bonus: 5,
77
- recovery_boost: 5, // Was 3. If trust drops low, it's easier to climb back up
78
- max_reward: 15,
79
- },
80
- limits: {
81
- stage_2_max_lines: 50, // Was 10. 10 lines is barely enough to fix a function signature.
82
- stage_3_max_lines: 300, // Was 100. Allow substantial feature implementation.
83
- stage_2_max_percentage: 10, // Percentage-based threshold for Stage 2
84
- stage_3_max_percentage: 15, // Percentage-based threshold for Stage 3
85
- min_lines_fallback: 20, // Minimum threshold even for small files
86
- },
87
- history_limit: 50
88
- },
89
49
  deep_reflection: {
90
50
  enabled: true,
91
51
  mode: 'auto',
@@ -122,11 +82,12 @@ export const DEFAULT_SETTINGS = {
122
82
  large_change_block: 50, // 大规模修改警告阈值
123
83
  },
124
84
  large_change_lines: 50,
125
- trust_stage_multipliers: {
126
- '1': 0.5, // Observer: 更严格,阈值减半
127
- '2': 0.75, // Editor: 阈值降低 25%
128
- '3': 1.0, // Developer: 标准阈值
129
- '4': 1.5, // Architect: 更宽松,阈值提高 50%
85
+ ep_tier_multipliers: {
86
+ '1': 0.5, // Seed: 更严格,阈值减半
87
+ '2': 0.75, // Sprout: 阈值降低 25%
88
+ '3': 1.0, // Sapling: 标准阈值
89
+ '4': 1.5, // Tree: 更宽松
90
+ '5': 2.0, // Forest: 最宽松
130
91
  },
131
92
  bash_safe_patterns: [
132
93
  '^(ls|dir|pwd|which|where|echo|env|cat|type|head|tail|less|more)\\b',
@@ -216,25 +177,9 @@ export class PainConfig {
216
177
  * Basic validation for critical settings
217
178
  */
218
179
  validate(settings) {
219
- // Ensure trust scores stay within 0-100 logical range
220
- const s = settings.trust.stages;
221
- if (s.stage_1_observer < 0 || s.stage_1_observer > 100)
222
- s.stage_1_observer = 30;
223
- if (s.stage_2_editor < 0 || s.stage_2_editor > 100)
224
- s.stage_2_editor = 60;
225
- if (s.stage_3_developer < 0 || s.stage_3_developer > 100)
226
- s.stage_3_developer = 80;
227
180
  // Ensure intervals are positive
228
181
  if (settings.intervals.worker_poll_ms < 1000)
229
182
  settings.intervals.worker_poll_ms = 15 * 60 * 1000;
230
- // Ensure percentage limits are in valid range [0, 100]
231
- const l = settings.trust.limits;
232
- if (l.stage_2_max_percentage < 0 || l.stage_2_max_percentage > 100)
233
- l.stage_2_max_percentage = 10;
234
- if (l.stage_3_max_percentage < 0 || l.stage_3_max_percentage > 100)
235
- l.stage_3_max_percentage = 15;
236
- if (l.min_lines_fallback < 1)
237
- l.min_lines_fallback = 20;
238
183
  }
239
184
  /**
240
185
  * Gets a value using dot notation (e.g. 'thresholds.pain_trigger')
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Control UI database stores ANALYTICS READ MODELS.
3
+ *
4
+ * PURPOSE: Aggregated data for dashboard visualization and historical insights.
5
+ * USAGE: Control UI queries and dashboard displays.
6
+ * NOT FOR: Control decisions, Phase 3 eligibility, or real-time operations.
7
+ *
8
+ * Runtime truth comes from: queue state, workspace trust scorecard, active sessions
9
+ */
1
10
  export interface ThinkingModelEventInput {
2
11
  sessionId: string;
3
12
  runId: string;
@@ -59,8 +68,26 @@ export declare class ControlUiDatabase {
59
68
  constructor(opts: ControlUiDatabaseOptions);
60
69
  dispose(): void;
61
70
  recordThinkingModelEvent(input: ThinkingModelEventInput): number;
71
+ /**
72
+ * Get recent thinking context for a session.
73
+ *
74
+ * Returns: Analytics data (read model) aggregated from trajectory database.
75
+ * Not: Runtime truth or real-time queue state.
76
+ */
62
77
  getRecentThinkingContext(sessionId: string, beforeCreatedAt: string, limit?: number): RecentThinkingContext;
78
+ /**
79
+ * Execute SQL query and return all rows.
80
+ *
81
+ * Returns: Analytics data (read model) aggregated from trajectory database.
82
+ * Not: Runtime truth or real-time queue state.
83
+ */
63
84
  all<T>(sql: string, ...params: unknown[]): T[];
85
+ /**
86
+ * Execute SQL query and return first row.
87
+ *
88
+ * Returns: Analytics data (read model) aggregated from trajectory database.
89
+ * Not: Runtime truth or real-time queue state.
90
+ */
64
91
  get<T>(sql: string, ...params: unknown[]): T | undefined;
65
92
  restoreRawText(inlineText?: string | null, blobRef?: string | null): string;
66
93
  private initSchema;
@@ -39,6 +39,12 @@ export class ControlUiDatabase {
39
39
  return Number(result.lastInsertRowid);
40
40
  });
41
41
  }
42
+ /**
43
+ * Get recent thinking context for a session.
44
+ *
45
+ * Returns: Analytics data (read model) aggregated from trajectory database.
46
+ * Not: Runtime truth or real-time queue state.
47
+ */
42
48
  getRecentThinkingContext(sessionId, beforeCreatedAt, limit = 5) {
43
49
  return {
44
50
  toolCalls: this.all(`
@@ -107,9 +113,21 @@ export class ControlUiDatabase {
107
113
  })),
108
114
  };
109
115
  }
116
+ /**
117
+ * Execute SQL query and return all rows.
118
+ *
119
+ * Returns: Analytics data (read model) aggregated from trajectory database.
120
+ * Not: Runtime truth or real-time queue state.
121
+ */
110
122
  all(sql, ...params) {
111
123
  return this.db.prepare(sql).all(...params);
112
124
  }
125
+ /**
126
+ * Execute SQL query and return first row.
127
+ *
128
+ * Returns: Analytics data (read model) aggregated from trajectory database.
129
+ * Not: Runtime truth or real-time queue state.
130
+ */
113
131
  get(sql, ...params) {
114
132
  return this.db.prepare(sql).get(...params);
115
133
  }
@@ -1,4 +1,4 @@
1
- import type { EventLogEntry, DailyStats, EmpathyEventStats, ToolCallEventData, PainSignalEventData, RuleMatchEventData, RulePromotionEventData, HookExecutionEventData, GateBlockEventData, GateBypassEventData, PlanApprovalEventData, EvolutionTaskEventData, DeepReflectionEventData, TrustChangeEventData, EmpathyRollbackEventData } from '../types/event-types.js';
1
+ import type { EventLogEntry, DailyStats, EmpathyEventStats, ToolCallEventData, PainSignalEventData, RuleMatchEventData, RulePromotionEventData, HookExecutionEventData, GateBlockEventData, GateBypassEventData, PlanApprovalEventData, EvolutionTaskEventData, DeepReflectionEventData, EmpathyRollbackEventData } from '../types/event-types.js';
2
2
  import type { PluginLogger } from '../openclaw-sdk.js';
3
3
  /**
4
4
  * EventLog - Structured event logging with daily statistics aggregation.
@@ -23,7 +23,6 @@ export declare class EventLog {
23
23
  recordPlanApproval(sessionId: string | undefined, data: PlanApprovalEventData): void;
24
24
  recordEvolutionTask(data: EvolutionTaskEventData): void;
25
25
  recordDeepReflection(sessionId: string | undefined, data: DeepReflectionEventData): void;
26
- recordTrustChange(sessionId: string | undefined, data: TrustChangeEventData): void;
27
26
  recordEmpathyRollback(sessionId: string | undefined, data: EmpathyRollbackEventData): void;
28
27
  recordError(sessionId: string | undefined, message: string, context?: Record<string, unknown>): void;
29
28
  recordWarn(sessionId: string | undefined, message: string, context?: Record<string, unknown>): void;
@@ -57,9 +57,6 @@ export class EventLog {
57
57
  const category = data.passed ? 'passed' : data.timeout ? 'failure' : 'completed';
58
58
  this.record('deep_reflection', category, sessionId, data);
59
59
  }
60
- recordTrustChange(sessionId, data) {
61
- this.record('trust_change', 'changed', sessionId, data);
62
- }
63
60
  recordEmpathyRollback(sessionId, data) {
64
61
  this.record('empathy_rollback', 'rolled_back', sessionId, data);
65
62
  }
@@ -14,7 +14,7 @@ import * as fs from 'fs';
14
14
  import * as path from 'path';
15
15
  import { resolvePdPath } from './paths.js';
16
16
  import { withLock } from '../utils/file-lock.js';
17
- import { CONSTRUCTIVE_TOOLS, CONTENT_LIMITED_TOOLS, EXPLORATORY_TOOLS, HIGH_RISK_TOOLS, } from '../constants/tools.js';
17
+ import { CONSTRUCTIVE_TOOLS, EXPLORATORY_TOOLS, HIGH_RISK_TOOLS, } from '../constants/tools.js';
18
18
  import { EvolutionTier, DEFAULT_EVOLUTION_CONFIG, TIER_DEFINITIONS, TASK_DIFFICULTY_CONFIG, getTierDefinition, getTierByPoints, } from './evolution-types.js';
19
19
  // ===== 主引擎 =====
20
20
  export class EvolutionEngine {
@@ -137,26 +137,6 @@ export class EvolutionEngine {
137
137
  beforeToolCall(context) {
138
138
  const tierDef = this.getTierDefinition();
139
139
  const perms = tierDef.permissions;
140
- // 行数检查(仅针对写操作工具)
141
- if (CONTENT_LIMITED_TOOLS.has(context.toolName)) {
142
- if (context.content) {
143
- const lineCount = context.content.split('\n').length;
144
- if (lineCount > perms.maxLinesPerWrite) {
145
- return {
146
- allowed: false,
147
- reason: `Tier ${this.scorecard.currentTier} (${tierDef.name}) 限制: 最多 ${perms.maxLinesPerWrite} 行,当前 ${lineCount} 行`,
148
- currentTier: this.scorecard.currentTier,
149
- };
150
- }
151
- }
152
- if (context.lineCount && context.lineCount > perms.maxLinesPerWrite) {
153
- return {
154
- allowed: false,
155
- reason: `Tier ${this.scorecard.currentTier} (${tierDef.name}) 限制: 最多 ${perms.maxLinesPerWrite} 行`,
156
- currentTier: this.scorecard.currentTier,
157
- };
158
- }
159
- }
160
140
  // 风险路径检查
161
141
  if (context.isRiskPath && !perms.allowRiskPath) {
162
142
  return {
@@ -1,4 +1,4 @@
1
- import type { EvolutionLoopEvent, Principle } from './evolution-types.js';
1
+ import type { EvolutionLoopEvent, Principle, PrincipleDetectorSpec, PrincipleEvaluatorLevel } from './evolution-types.js';
2
2
  export interface EvolutionReducer {
3
3
  emit(event: EvolutionLoopEvent): void;
4
4
  emitSync(event: EvolutionLoopEvent): void;
@@ -21,6 +21,10 @@ export interface EvolutionReducer {
21
21
  triggerPattern: string;
22
22
  action: string;
23
23
  source: string;
24
+ /** Evaluability level — defaults to 'manual_only' if omitted */
25
+ evaluability?: PrincipleEvaluatorLevel;
26
+ /** Detector metadata — absent or malformed = 'manual_only' evaluability */
27
+ detectorMetadata?: PrincipleDetectorSpec;
24
28
  }): string | null;
25
29
  getStats(): {
26
30
  candidateCount: number;
@@ -65,6 +69,8 @@ export declare class EvolutionReducerImpl implements EvolutionReducer {
65
69
  triggerPattern: string;
66
70
  action: string;
67
71
  source: string;
72
+ evaluability?: PrincipleEvaluatorLevel;
73
+ detectorMetadata?: PrincipleDetectorSpec;
68
74
  }): string | null;
69
75
  getStats(): {
70
76
  candidateCount: number;