principles-disciple 1.17.0 → 1.18.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.
@@ -173,7 +173,7 @@ let timeoutId: NodeJS.Timeout | null = null;
173
173
  * Old queue items (without taskKind) are migrated to pain_diagnosis for compatibility.
174
174
  */
175
175
  export type QueueStatus = 'pending' | 'in_progress' | 'completed' | 'failed' | 'canceled';
176
- export type TaskResolution = 'marker_detected' | 'auto_completed_timeout' | 'failed_max_retries' | 'runtime_unavailable' | 'canceled' | 'late_marker_principle_created' | 'late_marker_no_principle' | 'stub_fallback';
176
+ export type TaskResolution = 'marker_detected' | 'auto_completed_timeout' | 'failed_max_retries' | 'runtime_unavailable' | 'canceled' | 'late_marker_principle_created' | 'late_marker_no_principle' | 'stub_fallback' | 'skipped_thin_violation';
177
177
 
178
178
  /**
179
179
  * Recent pain context attached to sleep_reflection tasks.
@@ -1595,13 +1595,14 @@ async function processEvolutionQueue(wctx: WorkspaceContext, logger: PluginLogge
1595
1595
  const errorReason = lastEvent?.reason ?? 'unknown';
1596
1596
  // #219: Include payload details for better diagnostics
1597
1597
  let detailedError = `Workflow terminal_error: ${errorReason}`;
1598
+ let payload: unknown = {};
1598
1599
  try {
1599
- const payload = lastEvent?.payload ?? {};
1600
- if (payload.skipReason) {
1601
- detailedError += ` (skipReason: ${payload.skipReason})`;
1600
+ payload = lastEvent?.payload ?? {};
1601
+ if ((payload as any).skipReason) {
1602
+ detailedError += ` (skipReason: ${(payload as any).skipReason})`;
1602
1603
  }
1603
- if (payload.failures && Array.isArray(payload.failures) && payload.failures.length > 0) {
1604
- detailedError += ` | failures: ${(payload.failures as string[]).slice(0, 3).join(', ')}`;
1604
+ if ((payload as any).failures && Array.isArray((payload as any).failures) && (payload as any).failures.length > 0) {
1605
+ detailedError += ` | failures: ${((payload as any).failures as string[]).slice(0, 3).join(', ')}`;
1605
1606
  }
1606
1607
  } catch { /* ignore parse errors */ }
1607
1608
  sleepTask.lastError = detailedError;
@@ -1613,6 +1614,12 @@ async function processEvolutionQueue(wctx: WorkspaceContext, logger: PluginLogge
1613
1614
  sleepTask.completed_at = new Date().toISOString();
1614
1615
  sleepTask.resolution = 'stub_fallback';
1615
1616
  logger?.warn?.(`[PD:EvolutionWorker] sleep_reflection task ${sleepTask.id} background runtime unavailable, using stub fallback: ${errorReason}`);
1617
+ } else if ((payload as any).skipReason === 'no_violating_sessions') {
1618
+ // #244: No meaningful violations found (thin filter) → skip without failure
1619
+ sleepTask.status = 'completed';
1620
+ sleepTask.completed_at = new Date().toISOString();
1621
+ sleepTask.resolution = 'skipped_thin_violation';
1622
+ logger?.info?.(`[PD:EvolutionWorker] sleep_reflection task ${sleepTask.id} completed: no sessions with meaningful violations found`);
1616
1623
  } else {
1617
1624
  sleepTask.status = 'failed';
1618
1625
  sleepTask.completed_at = new Date().toISOString();
@@ -302,7 +302,7 @@ export class NocturnalTargetSelector {
302
302
  this.recentPainContext = recentPainContext;
303
303
  this.opts = {
304
304
  minViolationDensity: restOptions.minViolationDensity ?? 0.1,
305
- maxSessionCandidates: restOptions.maxSessionCandidates ?? 50,
305
+ maxSessionCandidates: restOptions.maxSessionCandidates ?? 300,
306
306
  idleThresholdMs: restOptions.idleThresholdMs ?? DEFAULT_IDLE_THRESHOLD_MS,
307
307
  };
308
308
  }
@@ -440,7 +440,14 @@ export class NocturnalTargetSelector {
440
440
  }
441
441
 
442
442
  // Compute violation signals for each session
443
- const violatingSessions: ViolationSignal[] = recentSessions.map((session) => {
443
+ // #244: Filter out sessions that are too thin for meaningful reflection
444
+ // A session needs enough violation context (failures + pain + gates >= 2)
445
+ const MIN_VIOLATION_DEPTH = 2;
446
+ const richSessions = recentSessions.filter(
447
+ s => (s.failureCount ?? 0) + (s.painEventCount ?? 0) + (s.gateBlockCount ?? 0) >= MIN_VIOLATION_DEPTH
448
+ );
449
+
450
+ const violatingSessions: ViolationSignal[] = richSessions.map((session) => {
444
451
  const violationDensity = computeViolationDensity(session);
445
452
  const snapshot = this.extractor.getNocturnalSessionSnapshot(session.sessionId);
446
453
 
@@ -0,0 +1,111 @@
1
+ {
2
+ "id": "nocturnal-trinity-quality-enhancement",
3
+ "title": "Enhance nocturnal Trinity prompt quality",
4
+ "description": "Enhance nocturnal Trinity prompt quality — add Dreamer perspective diversity constraints and Scribe rejected-decision analysis",
5
+ "workspace": "/home/csuzngjh/code/principles",
6
+ "branch": "fix/bugs-231-228",
7
+ "requiresTaskContract": true,
8
+ "maxRoundsPerStage": 2,
9
+ "maxRuntimeMinutes": 60,
10
+ "stages": [
11
+ "investigate",
12
+ "implement-pass-1",
13
+ "verify"
14
+ ],
15
+ "taskContract": {
16
+ "goal": "Improve nocturnal Trinity output quality by adding perspective diversity to Dreamer and rejected-decision analysis to Scribe",
17
+ "inScope": [
18
+ "nocturnal-trinity.ts prompt modifications",
19
+ "nocturnal-trinity.test.ts assertion updates",
20
+ "nocturnal-arbiter.ts compatibility verification"
21
+ ],
22
+ "outOfScope": [
23
+ "Runtime or infrastructure changes",
24
+ "New file creation",
25
+ "Non-Trinity prompt changes"
26
+ ],
27
+ "validationCommands": [
28
+ "npx vitest run packages/openclaw-plugin/tests/core/nocturnal --reporter=verbose"
29
+ ],
30
+ "expectedArtifacts": [
31
+ "packages/openclaw-plugin/src/core/nocturnal-trinity.ts"
32
+ ]
33
+ },
34
+ "producer": {
35
+ "agent": "iflow",
36
+ "model": "glm-5",
37
+ "timeoutSeconds": 1800
38
+ },
39
+ "reviewerA": {
40
+ "agent": "iflow",
41
+ "model": "glm-4.7",
42
+ "timeoutSeconds": 1200,
43
+ "role": "code-quality",
44
+ "focus": "Verify prompt changes are minimal, backward-compatible, and don't break existing arbiter validation"
45
+ },
46
+ "reviewerB": {
47
+ "agent": "iflow",
48
+ "model": "glm-4.7",
49
+ "timeoutSeconds": 1200,
50
+ "role": "functional-correctness",
51
+ "focus": "Verify tests pass and the new prompt constraints produce structurally valid Trinity output"
52
+ },
53
+ "escalationReviewer": {
54
+ "agent": "iflow",
55
+ "model": "glm-5",
56
+ "timeoutSeconds": 1800
57
+ },
58
+ "stageGoals": {
59
+ "investigate": [
60
+ "Read nocturnal-trinity.ts lines 64-298 (all three prompts) and nocturnal-trinity.test.ts",
61
+ "Identify exact insertion points for Dreamer diversity section and Scribe analysis section",
62
+ "List all test assertions that reference prompt content",
63
+ "Report findings in producer.md"
64
+ ],
65
+ "implement-pass-1": [
66
+ "Apply Dreamer perspective diversity constraints to NOCTURNAL_DREAMER_PROMPT",
67
+ "Apply Scribe rejected-decision analysis to NOCTURNAL_SCRIBE_PROMPT",
68
+ "Update test assertions in nocturnal-trinity.test.ts if needed",
69
+ "Run nocturnal-trinity and nocturnal-arbiter tests to verify no breakage"
70
+ ],
71
+ "verify": [
72
+ "Run full nocturnal test suite: npx vitest run packages/openclaw-plugin/tests/core/nocturnal --reporter=verbose",
73
+ "Verify all tests pass with 0 failures",
74
+ "Confirm arbiter validation is unchanged",
75
+ "Confirm no new files were created"
76
+ ]
77
+ },
78
+ "stageCriteria": {
79
+ "investigate": {
80
+ "scoringDimensions": [
81
+ "completeness",
82
+ "accuracy"
83
+ ],
84
+ "dimensionThreshold": 3,
85
+ "requiredDeliverables": [
86
+ "producer.md"
87
+ ]
88
+ },
89
+ "implement-pass-1": {
90
+ "scoringDimensions": [
91
+ "correctness",
92
+ "completeness"
93
+ ],
94
+ "dimensionThreshold": 3,
95
+ "requiredDeliverables": [
96
+ "producer.md",
97
+ "reviewer-a.md",
98
+ "reviewer-b.md"
99
+ ]
100
+ },
101
+ "verify": {
102
+ "scoringDimensions": [
103
+ "correctness"
104
+ ],
105
+ "dimensionThreshold": 3,
106
+ "requiredDeliverables": [
107
+ "producer.md"
108
+ ]
109
+ }
110
+ }
111
+ }
@@ -325,7 +325,7 @@ export function buildStageBrief(spec, stage, round, previousDecision, handoff =
325
325
  carryForward.trimEnd(),
326
326
  '',
327
327
  `## Constraints`,
328
- ...spec.context.map((line) => `- ${line}`),
328
+ ...((spec.context ?? []).map((line) => `- ${line}`)),
329
329
  '',
330
330
  ...(spec.taskContract
331
331
  ? [
@@ -3413,7 +3413,7 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
3413
3413
  main().catch((err) => {
3414
3414
  // main() is async and may throw. The try/catch inside main() handles
3415
3415
  // errors within its body, but rejections from the Promise itself land here.
3416
- console.error('Fatal error:', err.message);
3416
+ console.error('Fatal error:', err.message, err.stack);
3417
3417
  process.exit(1);
3418
3418
  });
3419
3419
  }