@telora/factory 0.4.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.
- package/dist/audit.d.ts +69 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +376 -0
- package/dist/audit.js.map +1 -0
- package/dist/builder-completion.d.ts +35 -0
- package/dist/builder-completion.d.ts.map +1 -0
- package/dist/builder-completion.js +375 -0
- package/dist/builder-completion.js.map +1 -0
- package/dist/builder-spawner.d.ts +40 -0
- package/dist/builder-spawner.d.ts.map +1 -0
- package/dist/builder-spawner.js +493 -0
- package/dist/builder-spawner.js.map +1 -0
- package/dist/completion-gate.d.ts +52 -0
- package/dist/completion-gate.d.ts.map +1 -0
- package/dist/completion-gate.js +336 -0
- package/dist/completion-gate.js.map +1 -0
- package/dist/completion-report.d.ts +36 -0
- package/dist/completion-report.d.ts.map +1 -0
- package/dist/completion-report.js +348 -0
- package/dist/completion-report.js.map +1 -0
- package/dist/completion.d.ts +58 -0
- package/dist/completion.d.ts.map +1 -0
- package/dist/completion.js +287 -0
- package/dist/completion.js.map +1 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -0
- package/dist/context-manager.d.ts +152 -0
- package/dist/context-manager.d.ts.map +1 -0
- package/dist/context-manager.js +421 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/crash-detection.d.ts +70 -0
- package/dist/crash-detection.d.ts.map +1 -0
- package/dist/crash-detection.js +123 -0
- package/dist/crash-detection.js.map +1 -0
- package/dist/crash-recovery.d.ts +83 -0
- package/dist/crash-recovery.d.ts.map +1 -0
- package/dist/crash-recovery.js +522 -0
- package/dist/crash-recovery.js.map +1 -0
- package/dist/crash-resolution.d.ts +34 -0
- package/dist/crash-resolution.d.ts.map +1 -0
- package/dist/crash-resolution.js +382 -0
- package/dist/crash-resolution.js.map +1 -0
- package/dist/escalation.d.ts +150 -0
- package/dist/escalation.d.ts.map +1 -0
- package/dist/escalation.js +352 -0
- package/dist/escalation.js.map +1 -0
- package/dist/execution-target.d.ts +31 -0
- package/dist/execution-target.d.ts.map +1 -0
- package/dist/execution-target.js +71 -0
- package/dist/execution-target.js.map +1 -0
- package/dist/execution-unit-init.d.ts +28 -0
- package/dist/execution-unit-init.d.ts.map +1 -0
- package/dist/execution-unit-init.js +115 -0
- package/dist/execution-unit-init.js.map +1 -0
- package/dist/execution.d.ts +17 -0
- package/dist/execution.d.ts.map +1 -0
- package/dist/execution.js +20 -0
- package/dist/execution.js.map +1 -0
- package/dist/factory-engine.d.ts +100 -0
- package/dist/factory-engine.d.ts.map +1 -0
- package/dist/factory-engine.js +243 -0
- package/dist/factory-engine.js.map +1 -0
- package/dist/gap-detection.d.ts +43 -0
- package/dist/gap-detection.d.ts.map +1 -0
- package/dist/gap-detection.js +149 -0
- package/dist/gap-detection.js.map +1 -0
- package/dist/gate-context.d.ts +23 -0
- package/dist/gate-context.d.ts.map +1 -0
- package/dist/gate-context.js +63 -0
- package/dist/gate-context.js.map +1 -0
- package/dist/gate-engine.d.ts +55 -0
- package/dist/gate-engine.d.ts.map +1 -0
- package/dist/gate-engine.js +191 -0
- package/dist/gate-engine.js.map +1 -0
- package/dist/gates/adversarial.d.ts +59 -0
- package/dist/gates/adversarial.d.ts.map +1 -0
- package/dist/gates/adversarial.js +426 -0
- package/dist/gates/adversarial.js.map +1 -0
- package/dist/gates/adversary-spawner.d.ts +35 -0
- package/dist/gates/adversary-spawner.d.ts.map +1 -0
- package/dist/gates/adversary-spawner.js +286 -0
- package/dist/gates/adversary-spawner.js.map +1 -0
- package/dist/gates/adversary-test-dir.d.ts +41 -0
- package/dist/gates/adversary-test-dir.d.ts.map +1 -0
- package/dist/gates/adversary-test-dir.js +150 -0
- package/dist/gates/adversary-test-dir.js.map +1 -0
- package/dist/gates/behavioral-parser.d.ts +32 -0
- package/dist/gates/behavioral-parser.d.ts.map +1 -0
- package/dist/gates/behavioral-parser.js +190 -0
- package/dist/gates/behavioral-parser.js.map +1 -0
- package/dist/gates/behavioral-runner.d.ts +36 -0
- package/dist/gates/behavioral-runner.d.ts.map +1 -0
- package/dist/gates/behavioral-runner.js +306 -0
- package/dist/gates/behavioral-runner.js.map +1 -0
- package/dist/gates/behavioral.d.ts +37 -0
- package/dist/gates/behavioral.d.ts.map +1 -0
- package/dist/gates/behavioral.js +485 -0
- package/dist/gates/behavioral.js.map +1 -0
- package/dist/gates/deterministic.d.ts +24 -0
- package/dist/gates/deterministic.d.ts.map +1 -0
- package/dist/gates/deterministic.js +186 -0
- package/dist/gates/deterministic.js.map +1 -0
- package/dist/git-factory.d.ts +59 -0
- package/dist/git-factory.d.ts.map +1 -0
- package/dist/git-factory.js +102 -0
- package/dist/git-factory.js.map +1 -0
- package/dist/guard-evaluation.d.ts +48 -0
- package/dist/guard-evaluation.d.ts.map +1 -0
- package/dist/guard-evaluation.js +416 -0
- package/dist/guard-evaluation.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/instance-completion.d.ts +34 -0
- package/dist/instance-completion.d.ts.map +1 -0
- package/dist/instance-completion.js +366 -0
- package/dist/instance-completion.js.map +1 -0
- package/dist/instance-lifecycle.d.ts +15 -0
- package/dist/instance-lifecycle.d.ts.map +1 -0
- package/dist/instance-lifecycle.js +18 -0
- package/dist/instance-lifecycle.js.map +1 -0
- package/dist/instance-phase-dispatch.d.ts +75 -0
- package/dist/instance-phase-dispatch.d.ts.map +1 -0
- package/dist/instance-phase-dispatch.js +674 -0
- package/dist/instance-phase-dispatch.js.map +1 -0
- package/dist/instance-poll-loop.d.ts +43 -0
- package/dist/instance-poll-loop.d.ts.map +1 -0
- package/dist/instance-poll-loop.js +360 -0
- package/dist/instance-poll-loop.js.map +1 -0
- package/dist/instance-state-machine.d.ts +52 -0
- package/dist/instance-state-machine.d.ts.map +1 -0
- package/dist/instance-state-machine.js +235 -0
- package/dist/instance-state-machine.js.map +1 -0
- package/dist/log-manager.d.ts +28 -0
- package/dist/log-manager.d.ts.map +1 -0
- package/dist/log-manager.js +71 -0
- package/dist/log-manager.js.map +1 -0
- package/dist/pipeline-evaluator.d.ts +61 -0
- package/dist/pipeline-evaluator.d.ts.map +1 -0
- package/dist/pipeline-evaluator.js +107 -0
- package/dist/pipeline-evaluator.js.map +1 -0
- package/dist/pipeline-metrics.d.ts +52 -0
- package/dist/pipeline-metrics.d.ts.map +1 -0
- package/dist/pipeline-metrics.js +40 -0
- package/dist/pipeline-metrics.js.map +1 -0
- package/dist/pipeline-traversal.d.ts +43 -0
- package/dist/pipeline-traversal.d.ts.map +1 -0
- package/dist/pipeline-traversal.js +68 -0
- package/dist/pipeline-traversal.js.map +1 -0
- package/dist/plan-parser.d.ts +76 -0
- package/dist/plan-parser.d.ts.map +1 -0
- package/dist/plan-parser.js +223 -0
- package/dist/plan-parser.js.map +1 -0
- package/dist/planning-phase.d.ts +52 -0
- package/dist/planning-phase.d.ts.map +1 -0
- package/dist/planning-phase.js +444 -0
- package/dist/planning-phase.js.map +1 -0
- package/dist/planning-prompt.d.ts +64 -0
- package/dist/planning-prompt.d.ts.map +1 -0
- package/dist/planning-prompt.js +251 -0
- package/dist/planning-prompt.js.map +1 -0
- package/dist/planning.d.ts +16 -0
- package/dist/planning.d.ts.map +1 -0
- package/dist/planning.js +17 -0
- package/dist/planning.js.map +1 -0
- package/dist/process-runner.d.ts +41 -0
- package/dist/process-runner.d.ts.map +1 -0
- package/dist/process-runner.js +81 -0
- package/dist/process-runner.js.map +1 -0
- package/dist/product-config.d.ts +34 -0
- package/dist/product-config.d.ts.map +1 -0
- package/dist/product-config.js +43 -0
- package/dist/product-config.js.map +1 -0
- package/dist/queries/cycle-evaluations.d.ts +23 -0
- package/dist/queries/cycle-evaluations.d.ts.map +1 -0
- package/dist/queries/cycle-evaluations.js +37 -0
- package/dist/queries/cycle-evaluations.js.map +1 -0
- package/dist/queries/escalations.d.ts +30 -0
- package/dist/queries/escalations.d.ts.map +1 -0
- package/dist/queries/escalations.js +42 -0
- package/dist/queries/escalations.js.map +1 -0
- package/dist/queries/execution-units.d.ts +76 -0
- package/dist/queries/execution-units.d.ts.map +1 -0
- package/dist/queries/execution-units.js +109 -0
- package/dist/queries/execution-units.js.map +1 -0
- package/dist/queries/gate-results.d.ts +32 -0
- package/dist/queries/gate-results.d.ts.map +1 -0
- package/dist/queries/gate-results.js +44 -0
- package/dist/queries/gate-results.js.map +1 -0
- package/dist/queries/instances.d.ts +51 -0
- package/dist/queries/instances.d.ts.map +1 -0
- package/dist/queries/instances.js +77 -0
- package/dist/queries/instances.js.map +1 -0
- package/dist/queries/sessions.d.ts +50 -0
- package/dist/queries/sessions.d.ts.map +1 -0
- package/dist/queries/sessions.js +81 -0
- package/dist/queries/sessions.js.map +1 -0
- package/dist/queries/shared.d.ts +38 -0
- package/dist/queries/shared.d.ts.map +1 -0
- package/dist/queries/shared.js +119 -0
- package/dist/queries/shared.js.map +1 -0
- package/dist/queries/specs.d.ts +12 -0
- package/dist/queries/specs.d.ts.map +1 -0
- package/dist/queries/specs.js +21 -0
- package/dist/queries/specs.js.map +1 -0
- package/dist/queries/strategies.d.ts +14 -0
- package/dist/queries/strategies.d.ts.map +1 -0
- package/dist/queries/strategies.js +18 -0
- package/dist/queries/strategies.js.map +1 -0
- package/dist/queries/work-units.d.ts +42 -0
- package/dist/queries/work-units.d.ts.map +1 -0
- package/dist/queries/work-units.js +57 -0
- package/dist/queries/work-units.js.map +1 -0
- package/dist/queries/workflows.d.ts +29 -0
- package/dist/queries/workflows.d.ts.map +1 -0
- package/dist/queries/workflows.js +103 -0
- package/dist/queries/workflows.js.map +1 -0
- package/dist/remediation-units.d.ts +40 -0
- package/dist/remediation-units.d.ts.map +1 -0
- package/dist/remediation-units.js +263 -0
- package/dist/remediation-units.js.map +1 -0
- package/dist/replanning.d.ts +72 -0
- package/dist/replanning.d.ts.map +1 -0
- package/dist/replanning.js +403 -0
- package/dist/replanning.js.map +1 -0
- package/dist/resource-limits.d.ts +62 -0
- package/dist/resource-limits.d.ts.map +1 -0
- package/dist/resource-limits.js +322 -0
- package/dist/resource-limits.js.map +1 -0
- package/dist/scheduler.d.ts +98 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +203 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/session-adapter.d.ts +89 -0
- package/dist/session-adapter.d.ts.map +1 -0
- package/dist/session-adapter.js +108 -0
- package/dist/session-adapter.js.map +1 -0
- package/dist/sop-generator.d.ts +29 -0
- package/dist/sop-generator.d.ts.map +1 -0
- package/dist/sop-generator.js +235 -0
- package/dist/sop-generator.js.map +1 -0
- package/dist/spec-profiles.d.ts +41 -0
- package/dist/spec-profiles.d.ts.map +1 -0
- package/dist/spec-profiles.js +131 -0
- package/dist/spec-profiles.js.map +1 -0
- package/dist/strategy-design-graph.d.ts +23 -0
- package/dist/strategy-design-graph.d.ts.map +1 -0
- package/dist/strategy-design-graph.js +205 -0
- package/dist/strategy-design-graph.js.map +1 -0
- package/dist/strategy-design-prompt.d.ts +28 -0
- package/dist/strategy-design-prompt.d.ts.map +1 -0
- package/dist/strategy-design-prompt.js +108 -0
- package/dist/strategy-design-prompt.js.map +1 -0
- package/dist/strategy-design-schema.d.ts +767 -0
- package/dist/strategy-design-schema.d.ts.map +1 -0
- package/dist/strategy-design-schema.js +126 -0
- package/dist/strategy-design-schema.js.map +1 -0
- package/dist/strategy-design.d.ts +69 -0
- package/dist/strategy-design.d.ts.map +1 -0
- package/dist/strategy-design.js +411 -0
- package/dist/strategy-design.js.map +1 -0
- package/dist/strategy-gating.d.ts +31 -0
- package/dist/strategy-gating.d.ts.map +1 -0
- package/dist/strategy-gating.js +276 -0
- package/dist/strategy-gating.js.map +1 -0
- package/dist/team-prompt-builder.d.ts +47 -0
- package/dist/team-prompt-builder.d.ts.map +1 -0
- package/dist/team-prompt-builder.js +362 -0
- package/dist/team-prompt-builder.js.map +1 -0
- package/dist/trace-engine.d.ts +40 -0
- package/dist/trace-engine.d.ts.map +1 -0
- package/dist/trace-engine.js +344 -0
- package/dist/trace-engine.js.map +1 -0
- package/dist/types.d.ts +612 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/unit-session-lifecycle.d.ts +78 -0
- package/dist/unit-session-lifecycle.d.ts.map +1 -0
- package/dist/unit-session-lifecycle.js +141 -0
- package/dist/unit-session-lifecycle.js.map +1 -0
- package/dist/unit-session.d.ts +30 -0
- package/dist/unit-session.d.ts.map +1 -0
- package/dist/unit-session.js +370 -0
- package/dist/unit-session.js.map +1 -0
- package/dist/watchdogs.d.ts +33 -0
- package/dist/watchdogs.d.ts.map +1 -0
- package/dist/watchdogs.js +170 -0
- package/dist/watchdogs.js.map +1 -0
- package/dist/work-unit-scheduler.d.ts +34 -0
- package/dist/work-unit-scheduler.d.ts.map +1 -0
- package/dist/work-unit-scheduler.js +91 -0
- package/dist/work-unit-scheduler.js.map +1 -0
- package/dist/workflow-transition.d.ts +90 -0
- package/dist/workflow-transition.d.ts.map +1 -0
- package/dist/workflow-transition.js +340 -0
- package/dist/workflow-transition.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory instance state machine -- workflow-governed status transitions,
|
|
3
|
+
* error handling, pause timeout enforcement, and resume recovery.
|
|
4
|
+
*
|
|
5
|
+
* This module is a leaf in the dependency graph: it does not import from
|
|
6
|
+
* the sibling instance-* modules, so it cannot create circular imports.
|
|
7
|
+
*/
|
|
8
|
+
import { getInstanceBlueprint, getInstanceStatus, updateInstanceStatus, updateInstanceWorkflowStage } from './queries/instances.js';
|
|
9
|
+
import { updateStrategyExecutionStatus } from './queries/strategies.js';
|
|
10
|
+
import { getInstanceWorkUnits, updateWorkUnitStatus } from './queries/work-units.js';
|
|
11
|
+
import { restoreExecutionUnits } from './execution-unit-init.js';
|
|
12
|
+
import { cleanupAdversaryTestDir } from './gates/adversarial.js';
|
|
13
|
+
import { attemptTransition, getOrResolveWorkflow } from './workflow-transition.js';
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// Workflow-governed instance status transitions
|
|
16
|
+
// ============================================================================
|
|
17
|
+
/**
|
|
18
|
+
* Build a minimal EvaluationContext from the current instance state.
|
|
19
|
+
* Used for guard condition evaluation during workflow transitions.
|
|
20
|
+
*/
|
|
21
|
+
export function buildInstanceEvalContext(state) {
|
|
22
|
+
if (!state) {
|
|
23
|
+
return {
|
|
24
|
+
deliveryId: '',
|
|
25
|
+
openIssueCount: 0,
|
|
26
|
+
totalIssueCount: 0,
|
|
27
|
+
issuesByStatus: {},
|
|
28
|
+
issuesByPriority: {},
|
|
29
|
+
lastExitCode: 0,
|
|
30
|
+
sessionCount: 0,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const elapsedSeconds = Math.floor((Date.now() - state.startedAt.getTime()) / 1000);
|
|
34
|
+
return {
|
|
35
|
+
deliveryId: '',
|
|
36
|
+
openIssueCount: 0,
|
|
37
|
+
totalIssueCount: 0,
|
|
38
|
+
issuesByStatus: {},
|
|
39
|
+
issuesByPriority: {},
|
|
40
|
+
lastExitCode: 0,
|
|
41
|
+
sessionCount: state.activeBuilderSessions.size,
|
|
42
|
+
tokensUsed: state.tokensUsed,
|
|
43
|
+
tokenBudget: state.blueprint.maxTokenBudget,
|
|
44
|
+
cycleCount: state.completionGateIterations,
|
|
45
|
+
wallClockSeconds: elapsedSeconds,
|
|
46
|
+
wallClockLimitSeconds: state.blueprint.maxWallClockHours
|
|
47
|
+
? state.blueprint.maxWallClockHours * 3600
|
|
48
|
+
: null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Transition a factory instance through the workflow state machine.
|
|
53
|
+
*
|
|
54
|
+
* Attempts a workflow-governed transition from the current status to the
|
|
55
|
+
* target status. If the workflow allows the transition (or no workflow
|
|
56
|
+
* exists), updates both the in-memory state and the database.
|
|
57
|
+
*
|
|
58
|
+
* @param state The in-memory instance state
|
|
59
|
+
* @param targetStatus The target instance status
|
|
60
|
+
* @param reason Optional reason (used for failed/completed messages)
|
|
61
|
+
*/
|
|
62
|
+
export async function transitionInstanceStatus(state, targetStatus, reason) {
|
|
63
|
+
const currentStatus = state.status;
|
|
64
|
+
// Attempt workflow transition
|
|
65
|
+
const ctx = buildInstanceEvalContext(state);
|
|
66
|
+
const transResult = await attemptTransition(state.workflow, currentStatus, targetStatus, state.productId, // organizationId placeholder -- factory uses productId for scoping
|
|
67
|
+
'factory_instance', state.instanceId, ctx);
|
|
68
|
+
if (!transResult.allowed) {
|
|
69
|
+
console.log(`[factory] Instance ${state.instanceId} transition ${currentStatus} -> ${targetStatus} ` +
|
|
70
|
+
`blocked by workflow guards`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Update in-memory state
|
|
74
|
+
state.status = targetStatus;
|
|
75
|
+
if (transResult.newStageId) {
|
|
76
|
+
state.currentWorkflowStageId = transResult.newStageId;
|
|
77
|
+
}
|
|
78
|
+
// Build DB update fields
|
|
79
|
+
const fields = {};
|
|
80
|
+
if (transResult.newStageId) {
|
|
81
|
+
await updateInstanceWorkflowStage(state.instanceId, transResult.newStageId, targetStatus);
|
|
82
|
+
}
|
|
83
|
+
if (reason && (targetStatus === 'failed' || targetStatus === 'completed')) {
|
|
84
|
+
fields.completionMessage = reason;
|
|
85
|
+
fields.completedAt = new Date().toISOString();
|
|
86
|
+
}
|
|
87
|
+
// Only call updateInstanceStatus if we have extra fields to set
|
|
88
|
+
// (workflow stage is already updated above)
|
|
89
|
+
if (Object.keys(fields).length > 0 || !transResult.newStageId) {
|
|
90
|
+
await updateInstanceStatus(state.instanceId, targetStatus, fields);
|
|
91
|
+
}
|
|
92
|
+
// Clean up external adversary test directory at terminal states
|
|
93
|
+
if ((targetStatus === 'completed' || targetStatus === 'failed') && state.worktreePath) {
|
|
94
|
+
cleanupAdversaryTestDir(state.worktreePath);
|
|
95
|
+
}
|
|
96
|
+
// Leave in the map -- monitorActiveInstances will clean it up on the next poll
|
|
97
|
+
if (targetStatus === 'failed') {
|
|
98
|
+
console.error(`[factory] Instance ${state.instanceId} failed: ${reason ?? 'unknown'}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// ============================================================================
|
|
102
|
+
// Error handling
|
|
103
|
+
// ============================================================================
|
|
104
|
+
/**
|
|
105
|
+
* Transition an instance to "failed" and remove it from active tracking.
|
|
106
|
+
*/
|
|
107
|
+
export function handleInstanceFailure(state, reason) {
|
|
108
|
+
transitionInstanceStatus(state, 'failed', reason).catch((error) => {
|
|
109
|
+
console.error(`[factory] Failed to persist failure status for instance ${state.instanceId}:`, error.message);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
// ============================================================================
|
|
113
|
+
// Pause timeout enforcement
|
|
114
|
+
// ============================================================================
|
|
115
|
+
/**
|
|
116
|
+
* Recover execution state when a paused instance is resumed.
|
|
117
|
+
*
|
|
118
|
+
* When a factory instance is paused (e.g., resource limit hit), its sessions
|
|
119
|
+
* are terminated but work units and strategies remain in their mid-flight states
|
|
120
|
+
* (in_progress). The scheduler only picks up 'pending' strategies, so without
|
|
121
|
+
* this recovery the instance is deadlocked after resume.
|
|
122
|
+
*
|
|
123
|
+
* Mirrors the orphan-reset logic in adoptActiveInstance but runs live (no
|
|
124
|
+
* daemon restart required).
|
|
125
|
+
*/
|
|
126
|
+
export async function recoverResumedInstance(state) {
|
|
127
|
+
console.log(`[factory] Resume recovery: restoring execution state for instance ${state.instanceId}`);
|
|
128
|
+
// 1. Restore execution units from DB (handles the case where the daemon
|
|
129
|
+
// restarted while the instance was paused and state.executionUnits is empty).
|
|
130
|
+
try {
|
|
131
|
+
await restoreExecutionUnits(state);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
console.error(`[factory] Resume recovery: failed to restore execution units:`, err.message);
|
|
135
|
+
}
|
|
136
|
+
// 2. Reset in_progress work units back to ready so the scheduler can
|
|
137
|
+
// re-dispatch them to a fresh session.
|
|
138
|
+
try {
|
|
139
|
+
const workUnits = await getInstanceWorkUnits(state.instanceId);
|
|
140
|
+
// Only reset agent-owned work units; infrastructure-owned units are
|
|
141
|
+
// managed by the engine and should not be re-dispatched to agents.
|
|
142
|
+
const orphaned = workUnits.filter((wu) => wu.status === 'in_progress' && !wu.infrastructureOwned);
|
|
143
|
+
for (const wu of orphaned) {
|
|
144
|
+
await updateWorkUnitStatus(wu.id, 'ready');
|
|
145
|
+
console.log(`[factory] Resume recovery: reset work unit ${wu.id} (${wu.title}) in_progress -> ready`);
|
|
146
|
+
}
|
|
147
|
+
if (orphaned.length > 0) {
|
|
148
|
+
console.log(`[factory] Resume recovery: reset ${orphaned.length} work unit(s) to ready`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
console.error(`[factory] Resume recovery: failed to reset work units:`, err.message);
|
|
153
|
+
}
|
|
154
|
+
// 3. Reset in_progress / gate_fix_pending strategies back to pending so the
|
|
155
|
+
// scheduler is eligible to assign execution units to them again.
|
|
156
|
+
try {
|
|
157
|
+
const { getStrategiesByFactoryInstance } = await import('./strategy-design.js');
|
|
158
|
+
const strategies = await getStrategiesByFactoryInstance(state.instanceId);
|
|
159
|
+
let resetCount = 0;
|
|
160
|
+
for (const strategy of strategies) {
|
|
161
|
+
if (strategy.executionStatus === 'in_progress' || strategy.executionStatus === 'gate_fix_pending') {
|
|
162
|
+
await updateStrategyExecutionStatus(strategy.id, 'pending');
|
|
163
|
+
resetCount++;
|
|
164
|
+
console.log(`[factory] Resume recovery: reset strategy "${strategy.name}" ` +
|
|
165
|
+
`${strategy.executionStatus} -> pending`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (resetCount > 0) {
|
|
169
|
+
console.log(`[factory] Resume recovery: reset ${resetCount} strategy/strategies to pending`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
console.error(`[factory] Resume recovery: failed to reset strategies:`, err.message);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Check whether a paused instance has exceeded its pause timeout.
|
|
178
|
+
*
|
|
179
|
+
* If `blueprint.pauseTimeoutHours` is set and the instance has been paused
|
|
180
|
+
* longer than that, auto-fail it. This prevents paused instances from sitting
|
|
181
|
+
* indefinitely when humans forget about them.
|
|
182
|
+
*/
|
|
183
|
+
export async function checkPauseTimeout(state) {
|
|
184
|
+
// Re-read status from DB to detect UI-driven resume
|
|
185
|
+
try {
|
|
186
|
+
const dbStatus = await getInstanceStatus(state.instanceId);
|
|
187
|
+
if (dbStatus !== 'paused') {
|
|
188
|
+
console.log(`[factory] Instance ${state.instanceId} status changed in DB: paused -> ${dbStatus}`);
|
|
189
|
+
state.status = dbStatus;
|
|
190
|
+
state.escalatedAt = null;
|
|
191
|
+
// If resumed to building, refresh blueprint (user may have updated limits)
|
|
192
|
+
// and restore execution state so the scheduler can continue.
|
|
193
|
+
if (dbStatus === 'building') {
|
|
194
|
+
try {
|
|
195
|
+
const { blueprint: freshBlueprint } = await getInstanceBlueprint(state.instanceId);
|
|
196
|
+
state.blueprint = freshBlueprint;
|
|
197
|
+
console.log(`[factory] Instance ${state.instanceId} blueprint refreshed on resume ` +
|
|
198
|
+
`(maxWorkUnits: ${freshBlueprint.maxWorkUnits})`);
|
|
199
|
+
}
|
|
200
|
+
catch (bpErr) {
|
|
201
|
+
console.error(`[factory] Failed to refresh blueprint on resume for instance ${state.instanceId}:`, bpErr.message);
|
|
202
|
+
}
|
|
203
|
+
await recoverResumedInstance(state);
|
|
204
|
+
}
|
|
205
|
+
// Next poll cycle will handle the instance in its new status
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
console.error(`[factory] Failed to re-read status for paused instance ${state.instanceId}:`, error.message);
|
|
211
|
+
}
|
|
212
|
+
const { pauseTimeoutHours } = state.blueprint;
|
|
213
|
+
// No timeout configured -- paused instances sit indefinitely (legacy behavior)
|
|
214
|
+
if (pauseTimeoutHours === null) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
// Need escalatedAt to know when the pause started
|
|
218
|
+
if (!state.escalatedAt) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const escalatedAtMs = new Date(state.escalatedAt).getTime();
|
|
222
|
+
const elapsedHours = (Date.now() - escalatedAtMs) / (1000 * 60 * 60);
|
|
223
|
+
if (elapsedHours > pauseTimeoutHours) {
|
|
224
|
+
const reason = `Paused instance timed out after ${elapsedHours.toFixed(1)} hours ` +
|
|
225
|
+
`(pause timeout: ${pauseTimeoutHours} hours). ` +
|
|
226
|
+
`The escalation was not resolved in time.`;
|
|
227
|
+
console.log(`[factory] Instance ${state.instanceId} pause timeout exceeded: ` +
|
|
228
|
+
`${elapsedHours.toFixed(1)}h > ${pauseTimeoutHours}h -- auto-failing`);
|
|
229
|
+
handleInstanceFailure(state, reason);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Re-export getOrResolveWorkflow so transitionToPending can use it without
|
|
233
|
+
// importing workflow-transition directly (keeps the dependency direction clean).
|
|
234
|
+
export { getOrResolveWorkflow };
|
|
235
|
+
//# sourceMappingURL=instance-state-machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-state-machine.js","sourceRoot":"","sources":["../src/instance-state-machine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory-specific log manager -- thin wrapper around @telora/daemon-core.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the shared types and provides a factory-specific pruneFactoryLogs
|
|
5
|
+
* overload that accepts FactoryConfig (which has logDir but not the retention
|
|
6
|
+
* thresholds). Defaults match the daemon's defaults (7 days, 1 GB, 500 files).
|
|
7
|
+
*/
|
|
8
|
+
import { type LogManagerDeps, type PruneResult } from '@telora/daemon-core';
|
|
9
|
+
import type { FactoryConfig } from './types.js';
|
|
10
|
+
export type { LogManagerDeps, LogRetentionConfig, PruneResult } from '@telora/daemon-core';
|
|
11
|
+
/**
|
|
12
|
+
* Create LogManagerDeps that preserve logs for escalated factory instances.
|
|
13
|
+
*
|
|
14
|
+
* Bridges factory instance IDs (from active escalations) to log session keys
|
|
15
|
+
* by scanning the log directory and matching session keys whose prefix contains
|
|
16
|
+
* the escalated instance ID (first 8 chars, matching the log filename pattern
|
|
17
|
+
* `factory-{instanceId:8}-wu-{workUnitId:8}-{timestamp}`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function createFactoryLogManagerDeps(config: FactoryConfig): LogManagerDeps;
|
|
20
|
+
/**
|
|
21
|
+
* Prune old factory log files using factory configuration.
|
|
22
|
+
*
|
|
23
|
+
* Applies the same retention algorithm as the daemon: age-based, then
|
|
24
|
+
* file-count, then total-size pruning -- with escalation-aware preservation
|
|
25
|
+
* when deps.getActiveEscalationSessionIds is provided.
|
|
26
|
+
*/
|
|
27
|
+
export declare function pruneFactoryLogs(config: FactoryConfig, deps?: LogManagerDeps): Promise<PruneResult>;
|
|
28
|
+
//# sourceMappingURL=log-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-manager.d.ts","sourceRoot":"","sources":["../src/log-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAGL,KAAK,cAAc,EAEnB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAyB3F;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,CA2BjF;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,cAAc,GACpB,OAAO,CAAC,WAAW,CAAC,CAEtB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory-specific log manager -- thin wrapper around @telora/daemon-core.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the shared types and provides a factory-specific pruneFactoryLogs
|
|
5
|
+
* overload that accepts FactoryConfig (which has logDir but not the retention
|
|
6
|
+
* thresholds). Defaults match the daemon's defaults (7 days, 1 GB, 500 files).
|
|
7
|
+
*/
|
|
8
|
+
import { pruneOldLogs as corePruneOldLogs, scanLogDirectory, } from '@telora/daemon-core';
|
|
9
|
+
import { getActiveEscalationInstanceIds } from './queries/escalations.js';
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Default retention thresholds (match daemon defaults)
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
const DEFAULT_LOG_MAX_AGE_DAYS = 7;
|
|
14
|
+
const DEFAULT_LOG_MAX_TOTAL_BYTES = 1_073_741_824; // 1 GB
|
|
15
|
+
const DEFAULT_LOG_MAX_FILES = 500;
|
|
16
|
+
/**
|
|
17
|
+
* Build a LogRetentionConfig from FactoryConfig with sensible defaults.
|
|
18
|
+
*
|
|
19
|
+
* FactoryConfig provides logDir; retention thresholds use daemon-equivalent
|
|
20
|
+
* defaults since BaseConfig does not include them.
|
|
21
|
+
*/
|
|
22
|
+
function buildRetentionConfig(config) {
|
|
23
|
+
return {
|
|
24
|
+
logDir: config.logDir,
|
|
25
|
+
logMaxAgeDays: DEFAULT_LOG_MAX_AGE_DAYS,
|
|
26
|
+
logMaxTotalBytes: DEFAULT_LOG_MAX_TOTAL_BYTES,
|
|
27
|
+
logMaxFiles: DEFAULT_LOG_MAX_FILES,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Create LogManagerDeps that preserve logs for escalated factory instances.
|
|
32
|
+
*
|
|
33
|
+
* Bridges factory instance IDs (from active escalations) to log session keys
|
|
34
|
+
* by scanning the log directory and matching session keys whose prefix contains
|
|
35
|
+
* the escalated instance ID (first 8 chars, matching the log filename pattern
|
|
36
|
+
* `factory-{instanceId:8}-wu-{workUnitId:8}-{timestamp}`).
|
|
37
|
+
*/
|
|
38
|
+
export function createFactoryLogManagerDeps(config) {
|
|
39
|
+
return {
|
|
40
|
+
getActiveEscalationSessionIds: async () => {
|
|
41
|
+
const instanceIds = await getActiveEscalationInstanceIds();
|
|
42
|
+
if (instanceIds.length === 0)
|
|
43
|
+
return new Set();
|
|
44
|
+
// Build set of instance ID prefixes for matching (first 8 chars)
|
|
45
|
+
const prefixes = new Set(instanceIds.map((id) => `factory-${id.slice(0, 8)}`));
|
|
46
|
+
// Scan log directory and collect session keys that match any prefix
|
|
47
|
+
const logFiles = scanLogDirectory(config.logDir);
|
|
48
|
+
const preserved = new Set();
|
|
49
|
+
for (const file of logFiles) {
|
|
50
|
+
for (const prefix of prefixes) {
|
|
51
|
+
if (file.sessionKey.startsWith(prefix)) {
|
|
52
|
+
preserved.add(file.sessionKey);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return preserved;
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Prune old factory log files using factory configuration.
|
|
63
|
+
*
|
|
64
|
+
* Applies the same retention algorithm as the daemon: age-based, then
|
|
65
|
+
* file-count, then total-size pruning -- with escalation-aware preservation
|
|
66
|
+
* when deps.getActiveEscalationSessionIds is provided.
|
|
67
|
+
*/
|
|
68
|
+
export async function pruneFactoryLogs(config, deps) {
|
|
69
|
+
return corePruneOldLogs(buildRetentionConfig(config), deps);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=log-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-manager.js","sourceRoot":"","sources":["../src/log-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,YAAY,IAAI,gBAAgB,EAChC,gBAAgB,GAIjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAC;AAI1E,8EAA8E;AAC9E,uDAAuD;AACvD,8EAA8E;AAE9E,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACnC,MAAM,2BAA2B,GAAG,aAAa,CAAC,CAAC,OAAO;AAC1D,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,MAAqB;IACjD,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,aAAa,EAAE,wBAAwB;QACvC,gBAAgB,EAAE,2BAA2B;QAC7C,WAAW,EAAE,qBAAqB;KACnC,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAAqB;IAC/D,OAAO;QACL,6BAA6B,EAAE,KAAK,IAA0B,EAAE;YAC9D,MAAM,WAAW,GAAG,MAAM,8BAA8B,EAAE,CAAC;YAC3D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,GAAG,EAAE,CAAC;YAE/C,iEAAiE;YACjE,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CACrD,CAAC;YAEF,oEAAoE;YACpE,MAAM,QAAQ,GAAG,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACjD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;YAEpC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC5B,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;oBAC9B,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;wBACvC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;wBAC/B,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;YAED,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAqB,EACrB,IAAqB;IAErB,OAAO,gBAAgB,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;AAC9D,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline Condition Evaluator
|
|
3
|
+
*
|
|
4
|
+
* Evaluates edge conditions against execution metrics to determine
|
|
5
|
+
* which pipeline node to advance to next.
|
|
6
|
+
*/
|
|
7
|
+
import type { PipelineExecutionMetrics } from './pipeline-metrics.js';
|
|
8
|
+
/** A single condition from JSONB (matches the existing EdgeCondition type). */
|
|
9
|
+
interface SingleDbCondition {
|
|
10
|
+
field: string;
|
|
11
|
+
operator: string;
|
|
12
|
+
value: string | number | boolean;
|
|
13
|
+
}
|
|
14
|
+
/** A compound condition from JSONB (AND/OR combinator). */
|
|
15
|
+
interface CompoundDbCondition {
|
|
16
|
+
combinator: 'AND' | 'OR';
|
|
17
|
+
conditions: SingleDbCondition[];
|
|
18
|
+
}
|
|
19
|
+
/** Edge condition as stored in JSONB (can be either format). */
|
|
20
|
+
type DbEdgeCondition = SingleDbCondition | CompoundDbCondition;
|
|
21
|
+
/** An edge from the pipeline graph. */
|
|
22
|
+
interface PipelineEdgeForEval {
|
|
23
|
+
id: string;
|
|
24
|
+
from: string;
|
|
25
|
+
to: string;
|
|
26
|
+
condition?: DbEdgeCondition | null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Evaluate an edge condition against execution metrics.
|
|
30
|
+
*
|
|
31
|
+
* @param condition - The edge condition (null means unconditional = always true)
|
|
32
|
+
* @param metrics - Current execution metrics
|
|
33
|
+
* @returns true if the condition is satisfied
|
|
34
|
+
*/
|
|
35
|
+
export declare function evaluateCondition(condition: DbEdgeCondition | null | undefined, metrics: PipelineExecutionMetrics): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Find the next pipeline node to advance to.
|
|
38
|
+
*
|
|
39
|
+
* Evaluates all outgoing edges from the current node in order.
|
|
40
|
+
* Returns the target node ID of the first edge whose condition is satisfied,
|
|
41
|
+
* or null if no edge matches (triggers escalation).
|
|
42
|
+
*
|
|
43
|
+
* @param currentNodeId - The current pipeline node ID
|
|
44
|
+
* @param edges - All edges in the pipeline graph
|
|
45
|
+
* @param metrics - Current execution metrics
|
|
46
|
+
* @returns The target node ID, or null if no match
|
|
47
|
+
*/
|
|
48
|
+
export declare function findNextNode(currentNodeId: string, edges: PipelineEdgeForEval[], metrics: PipelineExecutionMetrics): string | null;
|
|
49
|
+
/**
|
|
50
|
+
* Check if a node is a terminal node (has no outgoing edges).
|
|
51
|
+
*/
|
|
52
|
+
export declare function isTerminalNode(nodeId: string, edges: PipelineEdgeForEval[]): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Find the entry node of a pipeline (the node with no incoming edges).
|
|
55
|
+
* Returns the first such node found, or null if none exists.
|
|
56
|
+
*/
|
|
57
|
+
export declare function findEntryNode(nodes: Array<{
|
|
58
|
+
id: string;
|
|
59
|
+
}>, edges: PipelineEdgeForEval[]): string | null;
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=pipeline-evaluator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-evaluator.d.ts","sourceRoot":"","sources":["../src/pipeline-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEtE,+EAA+E;AAC/E,UAAU,iBAAiB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAClC;AAED,2DAA2D;AAC3D,UAAU,mBAAmB;IAC3B,UAAU,EAAE,KAAK,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,iBAAiB,EAAE,CAAC;CACjC;AAED,gEAAgE;AAChE,KAAK,eAAe,GAAG,iBAAiB,GAAG,mBAAmB,CAAC;AAE/D,uCAAuC;AACvC,UAAU,mBAAmB;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;CACpC;AA6CD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,EAC7C,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAeT;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,mBAAmB,EAAE,EAC5B,OAAO,EAAE,wBAAwB,GAChC,MAAM,GAAG,IAAI,CAiBf;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,mBAAmB,EAAE,GAC3B,OAAO,CAET;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,EAC5B,KAAK,EAAE,mBAAmB,EAAE,GAC3B,MAAM,GAAG,IAAI,CAIf"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline Condition Evaluator
|
|
3
|
+
*
|
|
4
|
+
* Evaluates edge conditions against execution metrics to determine
|
|
5
|
+
* which pipeline node to advance to next.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Check if a raw condition object is a compound condition.
|
|
9
|
+
*/
|
|
10
|
+
function isCompoundCondition(condition) {
|
|
11
|
+
return (typeof condition === 'object' &&
|
|
12
|
+
condition !== null &&
|
|
13
|
+
'combinator' in condition &&
|
|
14
|
+
Array.isArray(condition.conditions));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Evaluate a single condition against metrics.
|
|
18
|
+
*/
|
|
19
|
+
function evaluateSingleCondition(condition, metrics) {
|
|
20
|
+
const metricValue = metrics[condition.field];
|
|
21
|
+
if (metricValue === undefined)
|
|
22
|
+
return false;
|
|
23
|
+
const actual = metricValue;
|
|
24
|
+
const expected = condition.value;
|
|
25
|
+
switch (condition.operator) {
|
|
26
|
+
case 'eq':
|
|
27
|
+
return actual === expected;
|
|
28
|
+
case 'neq':
|
|
29
|
+
return actual !== expected;
|
|
30
|
+
case 'gt':
|
|
31
|
+
return actual > expected;
|
|
32
|
+
case 'gte':
|
|
33
|
+
return actual >= expected;
|
|
34
|
+
case 'lt':
|
|
35
|
+
return actual < expected;
|
|
36
|
+
case 'lte':
|
|
37
|
+
return actual <= expected;
|
|
38
|
+
default:
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Evaluate an edge condition against execution metrics.
|
|
44
|
+
*
|
|
45
|
+
* @param condition - The edge condition (null means unconditional = always true)
|
|
46
|
+
* @param metrics - Current execution metrics
|
|
47
|
+
* @returns true if the condition is satisfied
|
|
48
|
+
*/
|
|
49
|
+
export function evaluateCondition(condition, metrics) {
|
|
50
|
+
// Null/undefined = unconditional (always true)
|
|
51
|
+
if (!condition)
|
|
52
|
+
return true;
|
|
53
|
+
// Compound condition
|
|
54
|
+
if (isCompoundCondition(condition)) {
|
|
55
|
+
if (condition.combinator === 'AND') {
|
|
56
|
+
return condition.conditions.every((c) => evaluateSingleCondition(c, metrics));
|
|
57
|
+
}
|
|
58
|
+
// OR
|
|
59
|
+
return condition.conditions.some((c) => evaluateSingleCondition(c, metrics));
|
|
60
|
+
}
|
|
61
|
+
// Single condition
|
|
62
|
+
return evaluateSingleCondition(condition, metrics);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Find the next pipeline node to advance to.
|
|
66
|
+
*
|
|
67
|
+
* Evaluates all outgoing edges from the current node in order.
|
|
68
|
+
* Returns the target node ID of the first edge whose condition is satisfied,
|
|
69
|
+
* or null if no edge matches (triggers escalation).
|
|
70
|
+
*
|
|
71
|
+
* @param currentNodeId - The current pipeline node ID
|
|
72
|
+
* @param edges - All edges in the pipeline graph
|
|
73
|
+
* @param metrics - Current execution metrics
|
|
74
|
+
* @returns The target node ID, or null if no match
|
|
75
|
+
*/
|
|
76
|
+
export function findNextNode(currentNodeId, edges, metrics) {
|
|
77
|
+
// Get outgoing edges from current node
|
|
78
|
+
const outgoing = edges.filter((e) => e.from === currentNodeId);
|
|
79
|
+
// No outgoing edges = terminal node
|
|
80
|
+
if (outgoing.length === 0)
|
|
81
|
+
return null;
|
|
82
|
+
// Evaluate edges in order, return first match
|
|
83
|
+
for (const edge of outgoing) {
|
|
84
|
+
if (evaluateCondition(edge.condition, metrics)) {
|
|
85
|
+
return edge.to;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// No edge matched - this is the "escalation" case
|
|
89
|
+
// Return null to signal that no valid transition was found
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if a node is a terminal node (has no outgoing edges).
|
|
94
|
+
*/
|
|
95
|
+
export function isTerminalNode(nodeId, edges) {
|
|
96
|
+
return !edges.some((e) => e.from === nodeId);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Find the entry node of a pipeline (the node with no incoming edges).
|
|
100
|
+
* Returns the first such node found, or null if none exists.
|
|
101
|
+
*/
|
|
102
|
+
export function findEntryNode(nodes, edges) {
|
|
103
|
+
const nodesWithIncoming = new Set(edges.map((e) => e.to));
|
|
104
|
+
const entryNode = nodes.find((n) => !nodesWithIncoming.has(n.id));
|
|
105
|
+
return entryNode?.id ?? null;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=pipeline-evaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-evaluator.js","sourceRoot":"","sources":["../src/pipeline-evaluator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline Metrics Collector
|
|
3
|
+
*
|
|
4
|
+
* Assembles execution metrics from factory instance state
|
|
5
|
+
* for edge condition evaluation.
|
|
6
|
+
*/
|
|
7
|
+
/** All metrics available for pipeline edge condition evaluation. */
|
|
8
|
+
export interface PipelineExecutionMetrics {
|
|
9
|
+
gap_count: number;
|
|
10
|
+
gap_severity: string;
|
|
11
|
+
gate_pass_rate: number;
|
|
12
|
+
gates_failed: number;
|
|
13
|
+
cycle_count: number;
|
|
14
|
+
delivery_completion_pct: number;
|
|
15
|
+
qa_critical_failures: number;
|
|
16
|
+
qa_pass_rate: number;
|
|
17
|
+
wall_clock_minutes: number;
|
|
18
|
+
}
|
|
19
|
+
/** Default metrics when no data is available. */
|
|
20
|
+
export declare const DEFAULT_METRICS: PipelineExecutionMetrics;
|
|
21
|
+
/**
|
|
22
|
+
* Input data for metric collection. These come from various parts
|
|
23
|
+
* of the factory instance and gate results.
|
|
24
|
+
*/
|
|
25
|
+
export interface MetricCollectorInput {
|
|
26
|
+
/** Number of gaps/issues found in the current cycle. */
|
|
27
|
+
gapCount?: number;
|
|
28
|
+
/** Highest severity of gaps found. */
|
|
29
|
+
gapSeverity?: string;
|
|
30
|
+
/** Total gate checks run in this cycle. */
|
|
31
|
+
totalGateChecks?: number;
|
|
32
|
+
/** Number of gate checks that passed. */
|
|
33
|
+
passedGateChecks?: number;
|
|
34
|
+
/** Current build-gate cycle count. */
|
|
35
|
+
cycleCount?: number;
|
|
36
|
+
/** Percentage of work units completed (0-100). */
|
|
37
|
+
deliveryCompletionPct?: number;
|
|
38
|
+
/** Number of critical QA failures. */
|
|
39
|
+
qaCriticalFailures?: number;
|
|
40
|
+
/** Total QA checks run. */
|
|
41
|
+
totalQaChecks?: number;
|
|
42
|
+
/** Number of QA checks that passed. */
|
|
43
|
+
passedQaChecks?: number;
|
|
44
|
+
/** Wall clock minutes since instance started. */
|
|
45
|
+
wallClockMinutes?: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Collect execution metrics from available data.
|
|
49
|
+
* Metrics not provided default to safe values.
|
|
50
|
+
*/
|
|
51
|
+
export declare function collectMetrics(input: MetricCollectorInput): PipelineExecutionMetrics;
|
|
52
|
+
//# sourceMappingURL=pipeline-metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-metrics.d.ts","sourceRoot":"","sources":["../src/pipeline-metrics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,oEAAoE;AACpE,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,uBAAuB,EAAE,MAAM,CAAC;IAChC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,iDAAiD;AACjD,eAAO,MAAM,eAAe,EAAE,wBAU7B,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2CAA2C;IAC3C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sCAAsC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sCAAsC;IACtC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,2BAA2B;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iDAAiD;IACjD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,oBAAoB,GAAG,wBAAwB,CAiBpF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline Metrics Collector
|
|
3
|
+
*
|
|
4
|
+
* Assembles execution metrics from factory instance state
|
|
5
|
+
* for edge condition evaluation.
|
|
6
|
+
*/
|
|
7
|
+
/** Default metrics when no data is available. */
|
|
8
|
+
export const DEFAULT_METRICS = {
|
|
9
|
+
gap_count: 0,
|
|
10
|
+
gap_severity: 'low',
|
|
11
|
+
gate_pass_rate: 1,
|
|
12
|
+
gates_failed: 0,
|
|
13
|
+
cycle_count: 0,
|
|
14
|
+
delivery_completion_pct: 0,
|
|
15
|
+
qa_critical_failures: 0,
|
|
16
|
+
qa_pass_rate: 1,
|
|
17
|
+
wall_clock_minutes: 0,
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Collect execution metrics from available data.
|
|
21
|
+
* Metrics not provided default to safe values.
|
|
22
|
+
*/
|
|
23
|
+
export function collectMetrics(input) {
|
|
24
|
+
const totalGates = input.totalGateChecks ?? 0;
|
|
25
|
+
const passedGates = input.passedGateChecks ?? 0;
|
|
26
|
+
const totalQa = input.totalQaChecks ?? 0;
|
|
27
|
+
const passedQa = input.passedQaChecks ?? 0;
|
|
28
|
+
return {
|
|
29
|
+
gap_count: input.gapCount ?? 0,
|
|
30
|
+
gap_severity: input.gapSeverity ?? 'low',
|
|
31
|
+
gate_pass_rate: totalGates > 0 ? passedGates / totalGates : 1,
|
|
32
|
+
gates_failed: totalGates > 0 ? totalGates - passedGates : 0,
|
|
33
|
+
cycle_count: input.cycleCount ?? 0,
|
|
34
|
+
delivery_completion_pct: input.deliveryCompletionPct ?? 0,
|
|
35
|
+
qa_critical_failures: input.qaCriticalFailures ?? 0,
|
|
36
|
+
qa_pass_rate: totalQa > 0 ? passedQa / totalQa : 1,
|
|
37
|
+
wall_clock_minutes: input.wallClockMinutes ?? 0,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=pipeline-metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-metrics.js","sourceRoot":"","sources":["../src/pipeline-metrics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAeH,iDAAiD;AACjD,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD,SAAS,EAAE,CAAC;IACZ,YAAY,EAAE,KAAK;IACnB,cAAc,EAAE,CAAC;IACjB,YAAY,EAAE,CAAC;IACf,WAAW,EAAE,CAAC;IACd,uBAAuB,EAAE,CAAC;IAC1B,oBAAoB,EAAE,CAAC;IACvB,YAAY,EAAE,CAAC;IACf,kBAAkB,EAAE,CAAC;CACtB,CAAC;AA6BF;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAA2B;IACxD,MAAM,UAAU,GAAG,KAAK,CAAC,eAAe,IAAI,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,cAAc,IAAI,CAAC,CAAC;IAE3C,OAAO;QACL,SAAS,EAAE,KAAK,CAAC,QAAQ,IAAI,CAAC;QAC9B,YAAY,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK;QACxC,cAAc,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC7D,YAAY,EAAE,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC3D,WAAW,EAAE,KAAK,CAAC,UAAU,IAAI,CAAC;QAClC,uBAAuB,EAAE,KAAK,CAAC,qBAAqB,IAAI,CAAC;QACzD,oBAAoB,EAAE,KAAK,CAAC,kBAAkB,IAAI,CAAC;QACnD,YAAY,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAClD,kBAAkB,EAAE,KAAK,CAAC,gBAAgB,IAAI,CAAC;KAChD,CAAC;AACJ,CAAC"}
|