principles-disciple 1.42.0 → 1.44.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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/commands/archive-impl.ts +5 -3
- package/src/commands/capabilities.ts +1 -1
- package/src/commands/context.ts +1 -0
- package/src/commands/disable-impl.ts +1 -1
- package/src/commands/evolution-status.ts +2 -2
- package/src/commands/export.ts +6 -6
- package/src/commands/nocturnal-train.ts +1 -1
- package/src/commands/principle-rollback.ts +1 -1
- package/src/commands/rollback.ts +0 -1
- package/src/commands/samples.ts +1 -1
- package/src/commands/thinking-os.ts +1 -0
- package/src/commands/workflow-debug.ts +1 -1
- package/src/core/adaptive-thresholds.ts +3 -3
- package/src/core/config.ts +2 -1
- package/src/core/dictionary.ts +1 -0
- package/src/core/event-log.ts +3 -3
- package/src/core/evolution-engine.ts +1 -1
- package/src/core/external-training-contract.ts +1 -1
- package/src/core/merge-gate-audit.ts +3 -3
- package/src/core/nocturnal-arbiter.ts +1 -1
- package/src/core/nocturnal-compliance.ts +28 -28
- package/src/core/nocturnal-executability.ts +1 -1
- package/src/core/nocturnal-reasoning-deriver.ts +4 -4
- package/src/core/nocturnal-rule-implementation-validator.ts +1 -1
- package/src/core/nocturnal-snapshot-contract.ts +1 -1
- package/src/core/pain-context-extractor.ts +2 -2
- package/src/core/path-resolver.ts +1 -0
- package/src/core/pd-task-reconciler.ts +1 -0
- package/src/core/pd-task-service.ts +1 -1
- package/src/core/pd-task-store.ts +1 -0
- package/src/core/principle-internalization/deprecated-readiness.ts +1 -1
- package/src/core/principle-internalization/principle-lifecycle-service.ts +1 -1
- package/src/core/principle-training-state.ts +2 -2
- package/src/core/principle-tree-migration.ts +1 -1
- package/src/core/profile.ts +1 -1
- package/src/core/promotion-gate.ts +0 -2
- package/src/core/replay-engine.ts +1 -0
- package/src/core/risk-calculator.ts +2 -1
- package/src/core/rule-host.ts +1 -1
- package/src/core/session-tracker.ts +1 -0
- package/src/core/shadow-observation-registry.ts +1 -1
- package/src/core/thinking-models.ts +1 -1
- package/src/core/thinking-os-parser.ts +1 -1
- package/src/core/trajectory.ts +2 -4
- package/src/core/workspace-context.ts +1 -1
- package/src/hooks/bash-risk.ts +2 -2
- package/src/hooks/edit-verification.ts +4 -4
- package/src/hooks/gate.ts +8 -8
- package/src/hooks/gfi-gate.ts +2 -2
- package/src/hooks/lifecycle-routing.ts +1 -1
- package/src/hooks/pain.ts +2 -2
- package/src/hooks/progressive-trust-gate.ts +3 -3
- package/src/hooks/prompt.ts +3 -5
- package/src/hooks/thinking-checkpoint.ts +1 -1
- package/src/index.ts +8 -8
- package/src/service/central-database.ts +3 -2
- package/src/service/central-health-service.ts +2 -1
- package/src/service/central-overview-service.ts +3 -2
- package/src/service/control-ui-query-service.ts +2 -2
- package/src/service/event-log-auditor.ts +2 -2
- package/src/service/evolution-query-service.ts +3 -3
- package/src/service/evolution-worker.ts +11 -18
- package/src/service/health-query-service.ts +11 -10
- package/src/service/monitoring-query-service.ts +4 -4
- package/src/service/nocturnal-runtime.ts +0 -3
- package/src/service/nocturnal-service.ts +8 -8
- package/src/service/nocturnal-target-selector.ts +2 -2
- package/src/service/queue-io.ts +5 -5
- package/src/service/runtime-summary-service.ts +1 -1
- package/src/service/sleep-cycle.ts +1 -1
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +1 -1
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +1 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +1 -1
- package/src/service/subagent-workflow/subagent-error-utils.ts +1 -1
- package/src/service/subagent-workflow/workflow-store.ts +3 -2
- package/src/service/workflow-watchdog.ts +1 -1
- package/src/tools/critique-prompt.ts +1 -1
- package/src/tools/model-index.ts +1 -1
- package/src/utils/file-lock.ts +1 -1
- package/src/utils/io.ts +1 -1
- package/src/utils/retry.ts +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
import * as fs from 'fs';
|
|
2
3
|
import * as path from 'path';
|
|
3
4
|
import { readPainFlagData } from '../core/pain.js';
|
|
@@ -554,7 +555,7 @@ export class HealthQueryService {
|
|
|
554
555
|
const streamPath = resolvePdPath(this.workspaceDir, 'EVOLUTION_STREAM');
|
|
555
556
|
if (!fs.existsSync(streamPath)) return [];
|
|
556
557
|
|
|
557
|
-
|
|
558
|
+
|
|
558
559
|
let lines: string[];
|
|
559
560
|
try {
|
|
560
561
|
const raw = fs.readFileSync(streamPath, 'utf8').trim();
|
|
@@ -567,7 +568,7 @@ export class HealthQueryService {
|
|
|
567
568
|
const records: RecentPrincipleChange[] = [];
|
|
568
569
|
for (const line of lines) {
|
|
569
570
|
|
|
570
|
-
|
|
571
|
+
|
|
571
572
|
let event: EvolutionStreamRecord | null;
|
|
572
573
|
try {
|
|
573
574
|
event = JSON.parse(line) as EvolutionStreamRecord;
|
|
@@ -788,7 +789,7 @@ export class HealthQueryService {
|
|
|
788
789
|
|
|
789
790
|
|
|
790
791
|
|
|
791
|
-
|
|
792
|
+
|
|
792
793
|
private getEventDedupKey(entry: EventLogEntry): string {
|
|
793
794
|
const eventId = typeof entry.data?.eventId === 'string' ? entry.data.eventId : null;
|
|
794
795
|
if (eventId) {
|
|
@@ -860,7 +861,7 @@ export class HealthQueryService {
|
|
|
860
861
|
|
|
861
862
|
|
|
862
863
|
|
|
863
|
-
|
|
864
|
+
|
|
864
865
|
private resolveGateType(row: GateBlockRow): string {
|
|
865
866
|
if (typeof row.gate_type === 'string' && row.gate_type.trim().length > 0) {
|
|
866
867
|
return row.gate_type;
|
|
@@ -885,7 +886,7 @@ export class HealthQueryService {
|
|
|
885
886
|
}
|
|
886
887
|
|
|
887
888
|
|
|
888
|
-
|
|
889
|
+
|
|
889
890
|
private scoreToStatus(score: number): string {
|
|
890
891
|
if (score >= 70) return 'healthy';
|
|
891
892
|
if (score >= 40) return 'warning';
|
|
@@ -893,7 +894,7 @@ export class HealthQueryService {
|
|
|
893
894
|
}
|
|
894
895
|
|
|
895
896
|
|
|
896
|
-
|
|
897
|
+
|
|
897
898
|
private evolutionToStatus(tier: string, points: number): string {
|
|
898
899
|
const lower = tier.toLowerCase();
|
|
899
900
|
if (lower === 'forest' || lower === 'tree') return 'healthy';
|
|
@@ -902,7 +903,7 @@ export class HealthQueryService {
|
|
|
902
903
|
}
|
|
903
904
|
|
|
904
905
|
|
|
905
|
-
|
|
906
|
+
|
|
906
907
|
private safeListFiles(dirPath: string, predicate: (_name: string) => boolean): string[] {
|
|
907
908
|
if (!fs.existsSync(dirPath)) return [];
|
|
908
909
|
try {
|
|
@@ -915,7 +916,7 @@ export class HealthQueryService {
|
|
|
915
916
|
}
|
|
916
917
|
|
|
917
918
|
|
|
918
|
-
|
|
919
|
+
|
|
919
920
|
private readJsonFile<T>(filePath: string, fallback: T): T {
|
|
920
921
|
if (!fs.existsSync(filePath)) return fallback;
|
|
921
922
|
try {
|
|
@@ -926,13 +927,13 @@ export class HealthQueryService {
|
|
|
926
927
|
}
|
|
927
928
|
|
|
928
929
|
|
|
929
|
-
|
|
930
|
+
|
|
930
931
|
private asNumber(value: unknown, fallback: number): number {
|
|
931
932
|
return Number.isFinite(value) ? Number(value) : fallback;
|
|
932
933
|
}
|
|
933
934
|
|
|
934
935
|
|
|
935
|
-
|
|
936
|
+
|
|
936
937
|
private asNullableNumber(value: unknown): number | null {
|
|
937
938
|
if (Number.isFinite(value)) return Number(value);
|
|
938
939
|
if (typeof value === 'string' && value.trim().length > 0) {
|
|
@@ -36,7 +36,7 @@ export class MonitoringQueryService {
|
|
|
36
36
|
const now = Date.now();
|
|
37
37
|
const workflowsWithStuckDetection = workflows.map(wf => {
|
|
38
38
|
// Parse metadata for timeout configuration
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
const metadata = parseWorkflowMetadata(wf.metadata_json);
|
|
41
41
|
const timeoutMs = metadata.timeoutMs ?? 15 * 60 * 1000; // Default 15 minutes
|
|
42
42
|
|
|
@@ -85,10 +85,10 @@ export class MonitoringQueryService {
|
|
|
85
85
|
|
|
86
86
|
// Determine status
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
let status: 'pending' | 'running' | 'completed' | 'failed';
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
let reason: string | undefined;
|
|
93
93
|
|
|
94
94
|
if (!startEvent) {
|
|
@@ -110,7 +110,7 @@ export class MonitoringQueryService {
|
|
|
110
110
|
|
|
111
111
|
// Calculate duration if stage started and completed/failed
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
let duration: number | undefined;
|
|
115
115
|
if (startEvent && (completeEvent || failedEvent)) {
|
|
116
116
|
const endEvent = completeEvent || failedEvent;
|
|
@@ -390,9 +390,6 @@ export function checkCooldown(
|
|
|
390
390
|
} = {}
|
|
391
391
|
): CooldownCheckResult {
|
|
392
392
|
const {
|
|
393
|
-
|
|
394
|
-
globalCooldownMs: _globalCooldownMs = DEFAULT_GLOBAL_COOLDOWN_MS,
|
|
395
|
-
principleCooldownMs: _principleCooldownMs = DEFAULT_PRINCIPLE_COOLDOWN_MS,
|
|
396
393
|
maxRunsPerWindow = DEFAULT_MAX_RUNS_PER_WINDOW,
|
|
397
394
|
quotaWindowMs = DEFAULT_QUOTA_WINDOW_MS,
|
|
398
395
|
} = options;
|
|
@@ -116,7 +116,7 @@ function incrementGeneratedSampleCount(stateDir: string, principleId: string): v
|
|
|
116
116
|
state.generatedSampleCount += 1;
|
|
117
117
|
setPrincipleState(stateDir, state);
|
|
118
118
|
} catch (err) {
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
console.warn(`[nocturnal-service] Failed to sync generatedSampleCount for ${principleId}:`, err instanceof Error ? err.stack : err);
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -522,7 +522,7 @@ function persistCodeCandidate(
|
|
|
522
522
|
try {
|
|
523
523
|
refreshPrincipleLifecycle(workspaceDir, stateDir);
|
|
524
524
|
} catch (err) {
|
|
525
|
-
|
|
525
|
+
|
|
526
526
|
console.warn('[nocturnal-service] Lifecycle refresh failed after code candidate persistence:', err instanceof Error ? err.stack : err);
|
|
527
527
|
}
|
|
528
528
|
return {
|
|
@@ -702,7 +702,7 @@ export function executeNocturnalReflection(
|
|
|
702
702
|
): NocturnalRunResult {
|
|
703
703
|
// Use provided logger or fallback to console
|
|
704
704
|
const logger = options.logger;
|
|
705
|
-
|
|
705
|
+
|
|
706
706
|
const warn = logger?.warn?.bind(logger) ?? console.warn.bind(console);
|
|
707
707
|
|
|
708
708
|
const diagnostics: NocturnalRunDiagnostics = {
|
|
@@ -882,7 +882,7 @@ export function executeNocturnalReflection(
|
|
|
882
882
|
diagnostics,
|
|
883
883
|
};
|
|
884
884
|
}
|
|
885
|
-
trinityArtifact = trinityResult.artifact!;
|
|
885
|
+
trinityArtifact = trinityResult.artifact!;
|
|
886
886
|
// Convert Trinity draft to arbiter-compatible artifact
|
|
887
887
|
const artifactData = draftToArtifact(trinityArtifact);
|
|
888
888
|
rawJson = JSON.stringify(artifactData);
|
|
@@ -933,7 +933,7 @@ export function executeNocturnalReflection(
|
|
|
933
933
|
diagnostics,
|
|
934
934
|
};
|
|
935
935
|
}
|
|
936
|
-
trinityArtifact = trinityResult.artifact!;
|
|
936
|
+
trinityArtifact = trinityResult.artifact!;
|
|
937
937
|
// Convert Trinity draft to arbiter-compatible artifact
|
|
938
938
|
const artifactData = draftToArtifact(trinityArtifact);
|
|
939
939
|
rawJson = JSON.stringify(artifactData);
|
|
@@ -1187,7 +1187,7 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
1187
1187
|
): Promise<NocturnalRunResult> {
|
|
1188
1188
|
// Use provided logger or fallback to console
|
|
1189
1189
|
const logger = options.logger;
|
|
1190
|
-
|
|
1190
|
+
|
|
1191
1191
|
const warn = logger?.warn?.bind(logger) ?? console.warn.bind(console);
|
|
1192
1192
|
|
|
1193
1193
|
const diagnostics: NocturnalRunDiagnostics = {
|
|
@@ -1387,7 +1387,7 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
1387
1387
|
adjustThresholdsFromSignals(stateDir, { malformedRate: 1.0, arbiterRejectRate: 0.0, executabilityRejectRate: 0.0, qualityDelta: 0.0 });
|
|
1388
1388
|
return { success: false, noTargetSelected: false, validationFailed: true, validationFailures: [`Trinity override failed: ${failures.join('; ')}`], snapshot, diagnostics };
|
|
1389
1389
|
}
|
|
1390
|
-
trinityArtifact = trinityResult.artifact!;
|
|
1390
|
+
trinityArtifact = trinityResult.artifact!;
|
|
1391
1391
|
const artifactData = draftToArtifact(trinityArtifact);
|
|
1392
1392
|
rawJson = JSON.stringify(artifactData);
|
|
1393
1393
|
} else {
|
|
@@ -1414,7 +1414,7 @@ async function executeNocturnalReflectionWithAdapter(
|
|
|
1414
1414
|
adjustThresholdsFromSignals(stateDir, { malformedRate: 1.0, arbiterRejectRate: 0.0, executabilityRejectRate: 0.0, qualityDelta: 0.0 });
|
|
1415
1415
|
return { success: false, noTargetSelected: false, validationFailed: true, validationFailures: failures, snapshot, diagnostics };
|
|
1416
1416
|
}
|
|
1417
|
-
trinityArtifact = trinityResult.artifact!;
|
|
1417
|
+
trinityArtifact = trinityResult.artifact!;
|
|
1418
1418
|
const artifactData = draftToArtifact(trinityArtifact);
|
|
1419
1419
|
rawJson = JSON.stringify(artifactData);
|
|
1420
1420
|
} else {
|
|
@@ -288,7 +288,7 @@ export class NocturnalTargetSelector {
|
|
|
288
288
|
};
|
|
289
289
|
|
|
290
290
|
|
|
291
|
-
|
|
291
|
+
|
|
292
292
|
constructor(
|
|
293
293
|
workspaceDir: string,
|
|
294
294
|
stateDir: string,
|
|
@@ -533,7 +533,7 @@ export class NocturnalTargetSelector {
|
|
|
533
533
|
* This is a convenience wrapper for the common case.
|
|
534
534
|
*/
|
|
535
535
|
|
|
536
|
-
|
|
536
|
+
|
|
537
537
|
export function selectNocturnalTarget(
|
|
538
538
|
workspaceDir: string,
|
|
539
539
|
stateDir: string,
|
package/src/service/queue-io.ts
CHANGED
|
@@ -160,9 +160,9 @@ export function readRecentPainContext(wctx: WorkspaceContext): RecentPainContext
|
|
|
160
160
|
}
|
|
161
161
|
} catch (err) {
|
|
162
162
|
// Best effort — non-fatal, but surface unexpected errors
|
|
163
|
-
|
|
163
|
+
|
|
164
164
|
console.warn(`[queue-io] Failed to read pain context (non-fatal): ${String(err)}`);
|
|
165
|
-
|
|
165
|
+
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
return { mostRecent: null, recentPainCount: 0, recentMaxPainScore: 0 };
|
|
@@ -185,7 +185,7 @@ export function shouldSkipForDedup(
|
|
|
185
185
|
const recentSimilarReflection = hasRecentSimilarReflection(queue, painSourceKey, now);
|
|
186
186
|
|
|
187
187
|
if (recentSimilarReflection) {
|
|
188
|
-
const completedTime = new Date(recentSimilarReflection.completed_at!).getTime();
|
|
188
|
+
const completedTime = new Date(recentSimilarReflection.completed_at!).getTime();
|
|
189
189
|
logger?.debug?.(`[PD:EvolutionWorker] Skipping sleep_reflection — similar reflection completed ${Math.round((now - completedTime) / 60000)}min ago (same pain pattern: ${painSourceKey})`);
|
|
190
190
|
return true;
|
|
191
191
|
}
|
|
@@ -358,9 +358,9 @@ export function loadEvolutionQueue(queuePath: string): EvolutionQueueItem[] {
|
|
|
358
358
|
rawQueue = [];
|
|
359
359
|
} else {
|
|
360
360
|
// Corrupted JSON or other read error — warn and recover with empty queue
|
|
361
|
-
|
|
361
|
+
|
|
362
362
|
console.warn(`[queue-io] Failed to load evolution queue (recovering with empty): ${String(err)}`);
|
|
363
|
-
|
|
363
|
+
|
|
364
364
|
rawQueue = [];
|
|
365
365
|
}
|
|
366
366
|
}
|
|
@@ -420,7 +420,7 @@ export class RuntimeSummaryService {
|
|
|
420
420
|
* Queue is the only authoritative execution truth source.
|
|
421
421
|
*/
|
|
422
422
|
|
|
423
|
-
|
|
423
|
+
|
|
424
424
|
private static buildDirectiveSummary(
|
|
425
425
|
queue: QueueItem[] | null,
|
|
426
426
|
directive: DirectiveFile | null,
|
|
@@ -71,7 +71,7 @@ export interface CycleOptions {
|
|
|
71
71
|
* @param options.heartbeatCounterRef — mutable counter, incremented by runCycle
|
|
72
72
|
*/
|
|
73
73
|
export async function runCycle(options: CycleOptions): Promise<WorkerStatusReport> {
|
|
74
|
-
const { wctx, logger,
|
|
74
|
+
const { wctx, logger, api: _api, heartbeatCounterRef } = options;
|
|
75
75
|
const cycleStart = Date.now();
|
|
76
76
|
heartbeatCounterRef.value++;
|
|
77
77
|
|
|
@@ -130,7 +130,7 @@ export const deepReflectWorkflowSpec: SubagentWorkflowSpec<DeepReflectResult> =
|
|
|
130
130
|
} else if (Array.isArray(lastMessage?.content)) {
|
|
131
131
|
insights = (lastMessage.content as { type?: string; text?: string }[])
|
|
132
132
|
.filter((c) => c?.type === 'text' && typeof c.text === 'string')
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
.map((c) => c.text!)
|
|
135
135
|
.join('\n');
|
|
136
136
|
}
|
|
@@ -453,7 +453,7 @@ export class NocturnalWorkflowManager implements WorkflowManager {
|
|
|
453
453
|
|
|
454
454
|
async sweepExpiredWorkflows(
|
|
455
455
|
maxAgeMs = 30 * 60 * 1000,
|
|
456
|
-
|
|
456
|
+
|
|
457
457
|
subagentRuntime?: any,
|
|
458
458
|
|
|
459
459
|
agentSession?: {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Callers should suppress warnings for these errors — they are not real failures.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
export function isExpectedSubagentError(err: unknown): boolean {
|
|
10
10
|
const msg = String(err);
|
|
11
11
|
return (
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
import Database from 'better-sqlite3';
|
|
2
3
|
import * as fs from 'fs';
|
|
3
4
|
import * as path from 'path';
|
|
@@ -233,7 +234,7 @@ export class WorkflowStore {
|
|
|
233
234
|
}
|
|
234
235
|
|
|
235
236
|
|
|
236
|
-
|
|
237
|
+
|
|
237
238
|
recordEvent(
|
|
238
239
|
workflowId: string,
|
|
239
240
|
eventType: string,
|
|
@@ -270,7 +271,7 @@ export class WorkflowStore {
|
|
|
270
271
|
* same idempotency_key already exists, this is a no-op (idempotent).
|
|
271
272
|
*/
|
|
272
273
|
|
|
273
|
-
|
|
274
|
+
|
|
274
275
|
recordStageOutput(
|
|
275
276
|
workflowId: string,
|
|
276
277
|
stage: 'dreamer' | 'philosopher',
|
package/src/tools/model-index.ts
CHANGED
|
@@ -62,7 +62,7 @@ export function loadModelIndex(
|
|
|
62
62
|
const customConfig = loadCustomConfig(wctx);
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
let modelsDir: string;
|
|
67
67
|
if (customConfig?.modelsDir) {
|
|
68
68
|
modelsDir = path.isAbsolute(customConfig.modelsDir)
|
package/src/utils/file-lock.ts
CHANGED
|
@@ -352,7 +352,7 @@ export async function withAsyncLock<T>(
|
|
|
352
352
|
try {
|
|
353
353
|
return await fn();
|
|
354
354
|
} finally {
|
|
355
|
-
|
|
355
|
+
|
|
356
356
|
resolveRelease!();
|
|
357
357
|
// 清理已完成的队列
|
|
358
358
|
if (asyncLockQueues.get(lockPath) === currentQueue) {
|
package/src/utils/io.ts
CHANGED
|
@@ -126,7 +126,7 @@ export function parseKvLines(text: string): Record<string, string> {
|
|
|
126
126
|
return result;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
|
|
130
130
|
export function serializeKvLines(data: Record<string, any>): string {
|
|
131
131
|
const lines: string[] = [];
|
|
132
132
|
const keys = Object.keys(data).sort();
|
package/src/utils/retry.ts
CHANGED
|
@@ -424,7 +424,7 @@ export function computeDynamicTimeout(
|
|
|
424
424
|
if (history.length < MIN_SAMPLES) {
|
|
425
425
|
// Not enough data — use the spec's static timeout
|
|
426
426
|
const fallback = clampTimeout(defaultTimeout);
|
|
427
|
-
|
|
427
|
+
|
|
428
428
|
console.info(`[PD:DynamicTimeout] Insufficient samples (${history.length} < ${MIN_SAMPLES}) for '${workflowType}', falling back to static timeout: ${fallback}ms`);
|
|
429
429
|
return fallback;
|
|
430
430
|
}
|
|
@@ -432,7 +432,7 @@ export function computeDynamicTimeout(
|
|
|
432
432
|
const p95 = percentile(history, 95);
|
|
433
433
|
const adaptive = p95 * SAFETY_MULTIPLIER;
|
|
434
434
|
const result = clampTimeout(adaptive);
|
|
435
|
-
|
|
435
|
+
|
|
436
436
|
console.info(`[PD:DynamicTimeout] Computed adaptive timeout for '${workflowType}': P95=${p95}ms (from ${history.length} samples) × ${SAFETY_MULTIPLIER} = ${result}ms`);
|
|
437
437
|
return result;
|
|
438
438
|
}
|