@telora/daemon 0.16.44 → 0.17.2
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/build-info.json +6 -3
- package/dist/completion/event.d.ts +17 -0
- package/dist/completion/event.d.ts.map +1 -1
- package/dist/completion/event.js +46 -12
- package/dist/completion/event.js.map +1 -1
- package/dist/escalations.d.ts +38 -0
- package/dist/escalations.d.ts.map +1 -0
- package/dist/escalations.js +38 -0
- package/dist/escalations.js.map +1 -0
- package/dist/focus-engine.d.ts.map +1 -1
- package/dist/focus-engine.js +28 -0
- package/dist/focus-engine.js.map +1 -1
- package/dist/prd-clearance-engine.d.ts +121 -0
- package/dist/prd-clearance-engine.d.ts.map +1 -0
- package/dist/prd-clearance-engine.js +164 -0
- package/dist/prd-clearance-engine.js.map +1 -0
- package/dist/prd-controller.d.ts +87 -0
- package/dist/prd-controller.d.ts.map +1 -0
- package/dist/prd-controller.js +319 -0
- package/dist/prd-controller.js.map +1 -0
- package/dist/prd-divergence.d.ts +76 -0
- package/dist/prd-divergence.d.ts.map +1 -0
- package/dist/prd-divergence.js +148 -0
- package/dist/prd-divergence.js.map +1 -0
- package/dist/queries/prd.d.ts +79 -0
- package/dist/queries/prd.d.ts.map +1 -0
- package/dist/queries/prd.js +116 -0
- package/dist/queries/prd.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRD obstacle clearance predicate engine -- Staged Assembly: PRD Layer.
|
|
3
|
+
*
|
|
4
|
+
* This module lifts the per-delivery verification engine one altitude up to the
|
|
5
|
+
* PRD Prerequisite Tree (PRT) obstacle. Where `verification-engine.ts` answers
|
|
6
|
+
* "is this delivery's injection cleared?", this answers "is this milestone's
|
|
7
|
+
* obstacle cleared?" -- and, in aggregate, "is the whole milestone complete?".
|
|
8
|
+
*
|
|
9
|
+
* The clearance predicate is BOTH the completion signal AND the divergence
|
|
10
|
+
* detector: a PRD (milestone) is done exactly when every obstacle's verifiable
|
|
11
|
+
* clearance predicate passes. (UDE #4 -> desired effect: milestone completion
|
|
12
|
+
* is computable.)
|
|
13
|
+
*
|
|
14
|
+
* Design constraints (delivery C):
|
|
15
|
+
* - PURE. No DB access, no reality-tree writes, no module-level mutable state.
|
|
16
|
+
* The caller fetches obstacles (from `prd_prt_nodes.clearance_predicate`) and
|
|
17
|
+
* passes them in; this module only computes verdicts.
|
|
18
|
+
* - Command execution is INJECTED via `ClearanceContext.runCommand` so tests
|
|
19
|
+
* never shell out. A `defaultRunCommand` is provided for real callers and
|
|
20
|
+
* mirrors `verification-engine.runDeterministicStrategy` (spawn `sh -c`, tail
|
|
21
|
+
* output at 4000 chars, exit 0 = pass) -- but returns the raw triple rather
|
|
22
|
+
* than a StrategyResult, keeping this module side-effect-light.
|
|
23
|
+
* - NO daemon-loop wiring here. Wiring into the focus/verification loop is a
|
|
24
|
+
* later delivery (D).
|
|
25
|
+
*
|
|
26
|
+
* Predicate kinds mirror the verification engine's strategy taxonomy:
|
|
27
|
+
* deterministic -- run shell checks; all exit 0 => cleared.
|
|
28
|
+
* behavioral -- runtime telemetry observation (deferred; no signal source).
|
|
29
|
+
* ai_inspection -- AI reads code/state and decides (deferred; no driver).
|
|
30
|
+
* human -- a human attests clearance (deferred; out of band).
|
|
31
|
+
*
|
|
32
|
+
* @module prd-clearance-engine
|
|
33
|
+
*/
|
|
34
|
+
import { spawn } from 'node:child_process';
|
|
35
|
+
const DEFAULT_CLEARANCE_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
|
|
36
|
+
const OUTPUT_TAIL_MAX = 4000;
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Default command runner (mirrors runDeterministicStrategy)
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
/**
|
|
41
|
+
* Real shell runner: spawn `sh -c <cmd>` in `cwd`, capture stdout/stderr tailed
|
|
42
|
+
* to 4000 chars, resolve `{ exitCode, stdoutTail, stderrTail }`. A spawn error
|
|
43
|
+
* resolves with `exitCode: null` (treated as a non-pass by callers). Mirrors
|
|
44
|
+
* `verification-engine.runDeterministicStrategy` but returns the raw triple.
|
|
45
|
+
*/
|
|
46
|
+
export const defaultRunCommand = (cmd, cwd) => {
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
const child = spawn('sh', ['-c', cmd], {
|
|
49
|
+
cwd,
|
|
50
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
51
|
+
});
|
|
52
|
+
let stdout = '';
|
|
53
|
+
let stderr = '';
|
|
54
|
+
const tail = (buf, max = OUTPUT_TAIL_MAX) => buf.length <= max ? buf : buf.slice(buf.length - max);
|
|
55
|
+
child.stdout?.on('data', (chunk) => {
|
|
56
|
+
stdout += chunk.toString('utf8');
|
|
57
|
+
stdout = tail(stdout);
|
|
58
|
+
});
|
|
59
|
+
child.stderr?.on('data', (chunk) => {
|
|
60
|
+
stderr += chunk.toString('utf8');
|
|
61
|
+
stderr = tail(stderr);
|
|
62
|
+
});
|
|
63
|
+
const timer = setTimeout(() => {
|
|
64
|
+
try {
|
|
65
|
+
child.kill('SIGKILL');
|
|
66
|
+
}
|
|
67
|
+
catch { /* ignore */ }
|
|
68
|
+
}, DEFAULT_CLEARANCE_TIMEOUT_MS);
|
|
69
|
+
child.on('error', (err) => {
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
resolve({
|
|
72
|
+
exitCode: null,
|
|
73
|
+
stdoutTail: stdout,
|
|
74
|
+
stderrTail: tail(`${stderr}\n${err.message}`),
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
child.on('close', (code) => {
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
resolve({ exitCode: code, stdoutTail: stdout, stderrTail: stderr });
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// Evaluation
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
const DEFERRAL_REASON = {
|
|
87
|
+
behavioral: 'behavioral clearance deferred -- no runtime telemetry source wired',
|
|
88
|
+
ai_inspection: 'ai_inspection clearance deferred -- no AI inspection driver wired',
|
|
89
|
+
human: 'human clearance deferred -- requires out-of-band human attestation',
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Evaluate a single obstacle's clearance predicate. PURE.
|
|
93
|
+
*
|
|
94
|
+
* - deterministic: run each check via `ctx.runCommand ?? defaultRunCommand`.
|
|
95
|
+
* exit 0 = passed. All pass => cleared. No checks (undefined/empty) =>
|
|
96
|
+
* not cleared, not deferred (a deterministic predicate with nothing to check
|
|
97
|
+
* cannot assert clearance).
|
|
98
|
+
* - behavioral | ai_inspection | human: deferred (cleared:false, deferred:true);
|
|
99
|
+
* evidence names the deferral reason.
|
|
100
|
+
*/
|
|
101
|
+
export async function evaluateClearance(predicate, ctx) {
|
|
102
|
+
if (predicate.kind !== 'deterministic') {
|
|
103
|
+
return {
|
|
104
|
+
kind: predicate.kind,
|
|
105
|
+
cleared: false,
|
|
106
|
+
deferred: true,
|
|
107
|
+
evidence: DEFERRAL_REASON[predicate.kind],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const checks = predicate.checks ?? [];
|
|
111
|
+
if (checks.length === 0) {
|
|
112
|
+
return {
|
|
113
|
+
kind: 'deterministic',
|
|
114
|
+
cleared: false,
|
|
115
|
+
deferred: false,
|
|
116
|
+
evidence: 'no checks defined -- deterministic predicate cannot assert clearance',
|
|
117
|
+
checkResults: [],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const run = ctx.runCommand ?? defaultRunCommand;
|
|
121
|
+
const checkResults = [];
|
|
122
|
+
for (const check of checks) {
|
|
123
|
+
const { exitCode } = await run(check.cmd, ctx.worktreeDir);
|
|
124
|
+
checkResults.push({
|
|
125
|
+
cmd: check.cmd,
|
|
126
|
+
exitCode,
|
|
127
|
+
passed: exitCode === 0,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const passedCount = checkResults.filter(r => r.passed).length;
|
|
131
|
+
const cleared = passedCount === checkResults.length;
|
|
132
|
+
return {
|
|
133
|
+
kind: 'deterministic',
|
|
134
|
+
cleared,
|
|
135
|
+
deferred: false,
|
|
136
|
+
evidence: cleared
|
|
137
|
+
? `deterministic clearance passed (${passedCount}/${checkResults.length} checks exit 0)`
|
|
138
|
+
: `deterministic clearance failed (${passedCount}/${checkResults.length} checks exit 0)`,
|
|
139
|
+
checkResults,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Aggregate clearance across all obstacles of a PRT -- the "milestone
|
|
144
|
+
* completion is computable" primitive. PURE; the caller fetches the obstacles
|
|
145
|
+
* (each carrying its `clearance_predicate`).
|
|
146
|
+
*
|
|
147
|
+
* - `allCleared` is true only when there is at least one obstacle AND every
|
|
148
|
+
* obstacle's verdict is cleared. (An empty obstacle set cannot assert a
|
|
149
|
+
* complete milestone.)
|
|
150
|
+
* - `deferredCount` counts obstacles whose predicate could not be evaluated
|
|
151
|
+
* automatically -- these block `allCleared` and flag where human/AI signal
|
|
152
|
+
* is still required.
|
|
153
|
+
*/
|
|
154
|
+
export async function evaluatePrtClearance(obstacles, ctx) {
|
|
155
|
+
const nodeVerdicts = [];
|
|
156
|
+
for (const obstacle of obstacles) {
|
|
157
|
+
const verdict = await evaluateClearance(obstacle.predicate, ctx);
|
|
158
|
+
nodeVerdicts.push({ nodeId: obstacle.nodeId, verdict });
|
|
159
|
+
}
|
|
160
|
+
const allCleared = obstacles.length > 0 && nodeVerdicts.every(nv => nv.verdict.cleared);
|
|
161
|
+
const deferredCount = nodeVerdicts.filter(nv => nv.verdict.deferred).length;
|
|
162
|
+
return { nodeVerdicts, allCleared, deferredCount };
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=prd-clearance-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prd-clearance-engine.js","sourceRoot":"","sources":["../src/prd-clearance-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRD-lifecycle controller (Delivery D).
|
|
3
|
+
*
|
|
4
|
+
* CARDINAL RULE: this controller adds NO new executor. Its only outputs are
|
|
5
|
+
* (a) materialize an overcome into a focus via the existing
|
|
6
|
+
* prd_overcome_materialize action, (b) arm a focus by setting
|
|
7
|
+
* assigned_agent_role_id via the existing focus_update action (the queue toggle
|
|
8
|
+
* the focus engine already polls), (c) mark obstacles cleared / the PRD done via
|
|
9
|
+
* the existing node/prd update actions. It never spawns agents and never creates
|
|
10
|
+
* a parallel execution path.
|
|
11
|
+
*
|
|
12
|
+
* It computes the Prerequisite-Tree (PRT) frontier for an active PRD and arms
|
|
13
|
+
* the frontier foci; on obstacle clearance it recomputes and arms the next
|
|
14
|
+
* frontier. The whole milestone then runs progressively over the existing
|
|
15
|
+
* Foci -> Delivery -> Issue executor.
|
|
16
|
+
*/
|
|
17
|
+
import type { DaemonConfig } from './types.js';
|
|
18
|
+
import { type ClearancePredicate, type ClearanceContext, type ClearanceVerdict } from './prd-clearance-engine.js';
|
|
19
|
+
import { type Prd, type PrtNode, type PrtEdge, type Pathway } from './queries/prd.js';
|
|
20
|
+
import { type FileEscalationInput } from './escalations.js';
|
|
21
|
+
/**
|
|
22
|
+
* Splits the armable overcome frontier into those still needing a focus
|
|
23
|
+
* (materialize) and those already materialized (arm).
|
|
24
|
+
*
|
|
25
|
+
* PRT frontier semantics (implemented exactly):
|
|
26
|
+
* - prerequisite edge P->Q means P must be cleared before Q.
|
|
27
|
+
* - overcome O is ARMABLE iff O.status !== 'cleared' AND every node P with a
|
|
28
|
+
* prerequisite edge P->O is in clearedNodeIds. No incoming prerequisite edge
|
|
29
|
+
* => initial frontier.
|
|
30
|
+
* - needsMaterialize = armable overcomes with focusId == null.
|
|
31
|
+
* - needsArm = armable overcomes with focusId set.
|
|
32
|
+
*/
|
|
33
|
+
export declare function computePrtFrontier(nodes: PrtNode[], edges: PrtEdge[], clearedNodeIds: Set<string>): {
|
|
34
|
+
needsMaterialize: PrtNode[];
|
|
35
|
+
needsArm: PrtNode[];
|
|
36
|
+
};
|
|
37
|
+
export interface PrdControllerDeps {
|
|
38
|
+
loadPrtGraph: (prdId: string) => Promise<{
|
|
39
|
+
nodes: PrtNode[];
|
|
40
|
+
edges: PrtEdge[];
|
|
41
|
+
}>;
|
|
42
|
+
evaluateClearance: (predicate: ClearancePredicate, ctx: ClearanceContext) => Promise<ClearanceVerdict>;
|
|
43
|
+
markNodeCleared: (nodeId: string) => Promise<void>;
|
|
44
|
+
materializeOvercome: (nodeId: string) => Promise<{
|
|
45
|
+
focusId: string;
|
|
46
|
+
}>;
|
|
47
|
+
armFocus: (focusId: string, agentRoleId: string) => Promise<void>;
|
|
48
|
+
markPrdDone: (prdId: string) => Promise<void>;
|
|
49
|
+
resolveArmRoleId: (prd: Prd) => Promise<string | null>;
|
|
50
|
+
loadPathways: (prdId: string) => Promise<Pathway[]>;
|
|
51
|
+
commitPathway: (prdId: string, pathwayId: string) => Promise<void>;
|
|
52
|
+
fileEscalation: (input: FileEscalationInput) => Promise<void>;
|
|
53
|
+
/** Org scope used when filing a no-surviving-path escalation. */
|
|
54
|
+
organizationId: string;
|
|
55
|
+
worktreeDir: string;
|
|
56
|
+
}
|
|
57
|
+
export interface PrdControllerTickResult {
|
|
58
|
+
obstaclesEvaluated: number;
|
|
59
|
+
obstaclesCleared: number;
|
|
60
|
+
materialized: number;
|
|
61
|
+
armed: number;
|
|
62
|
+
skippedNoRole: number;
|
|
63
|
+
prdDone: boolean;
|
|
64
|
+
/** True when this tick detected one or more divergence signals. */
|
|
65
|
+
diverged: boolean;
|
|
66
|
+
/** True when realign re-pointed the committed pathway (re-capture). */
|
|
67
|
+
pathSwitched: boolean;
|
|
68
|
+
/** True when divergence had no surviving path and a human was escalated. */
|
|
69
|
+
escalated: boolean;
|
|
70
|
+
}
|
|
71
|
+
export declare function runPrdControllerTick(prd: Prd, deps: PrdControllerDeps): Promise<PrdControllerTickResult>;
|
|
72
|
+
export interface PrdControllerTickAllResult {
|
|
73
|
+
obstaclesEvaluated: number;
|
|
74
|
+
obstaclesCleared: number;
|
|
75
|
+
materialized: number;
|
|
76
|
+
armed: number;
|
|
77
|
+
skippedNoRole: number;
|
|
78
|
+
prdsDone: number;
|
|
79
|
+
/** PRDs that detected divergence this pass. */
|
|
80
|
+
prdsDiverged: number;
|
|
81
|
+
/** PRDs whose committed pathway was re-pointed (re-capture). */
|
|
82
|
+
prdsPathSwitched: number;
|
|
83
|
+
/** PRDs escalated to a human for lack of a surviving path. */
|
|
84
|
+
prdsEscalated: number;
|
|
85
|
+
}
|
|
86
|
+
export declare function runPrdControllerTickAll(config: DaemonConfig, deps?: Partial<PrdControllerDeps>): Promise<PrdControllerTickAllResult>;
|
|
87
|
+
//# sourceMappingURL=prd-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prd-controller.d.ts","sourceRoot":"","sources":["../src/prd-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRD-lifecycle controller (Delivery D).
|
|
3
|
+
*
|
|
4
|
+
* CARDINAL RULE: this controller adds NO new executor. Its only outputs are
|
|
5
|
+
* (a) materialize an overcome into a focus via the existing
|
|
6
|
+
* prd_overcome_materialize action, (b) arm a focus by setting
|
|
7
|
+
* assigned_agent_role_id via the existing focus_update action (the queue toggle
|
|
8
|
+
* the focus engine already polls), (c) mark obstacles cleared / the PRD done via
|
|
9
|
+
* the existing node/prd update actions. It never spawns agents and never creates
|
|
10
|
+
* a parallel execution path.
|
|
11
|
+
*
|
|
12
|
+
* It computes the Prerequisite-Tree (PRT) frontier for an active PRD and arms
|
|
13
|
+
* the frontier foci; on obstacle clearance it recomputes and arms the next
|
|
14
|
+
* frontier. The whole milestone then runs progressively over the existing
|
|
15
|
+
* Foci -> Delivery -> Issue executor.
|
|
16
|
+
*/
|
|
17
|
+
import { configForProduct } from './config.js';
|
|
18
|
+
import { evaluateClearance, } from './prd-clearance-engine.js';
|
|
19
|
+
import { loadActivePrds, loadPrtGraph, materializeOvercome, armFocus, markNodeCleared, markPrdDone, loadPathways, commitPathway, } from './queries/prd.js';
|
|
20
|
+
import { fileEscalation } from './escalations.js';
|
|
21
|
+
import { detectDivergence, selectSurvivingPath, } from './prd-divergence.js';
|
|
22
|
+
/**
|
|
23
|
+
* Splits the armable overcome frontier into those still needing a focus
|
|
24
|
+
* (materialize) and those already materialized (arm).
|
|
25
|
+
*
|
|
26
|
+
* PRT frontier semantics (implemented exactly):
|
|
27
|
+
* - prerequisite edge P->Q means P must be cleared before Q.
|
|
28
|
+
* - overcome O is ARMABLE iff O.status !== 'cleared' AND every node P with a
|
|
29
|
+
* prerequisite edge P->O is in clearedNodeIds. No incoming prerequisite edge
|
|
30
|
+
* => initial frontier.
|
|
31
|
+
* - needsMaterialize = armable overcomes with focusId == null.
|
|
32
|
+
* - needsArm = armable overcomes with focusId set.
|
|
33
|
+
*/
|
|
34
|
+
export function computePrtFrontier(nodes, edges, clearedNodeIds) {
|
|
35
|
+
const needsMaterialize = [];
|
|
36
|
+
const needsArm = [];
|
|
37
|
+
for (const node of nodes) {
|
|
38
|
+
if (node.nodeType !== 'overcome') {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (node.status === 'cleared') {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const prereqs = edges.filter((edge) => edge.edgeType === 'prerequisite' && edge.toNodeId === node.id);
|
|
45
|
+
const allPrereqsCleared = prereqs.every((edge) => clearedNodeIds.has(edge.fromNodeId));
|
|
46
|
+
if (!allPrereqsCleared) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (node.focusId === null) {
|
|
50
|
+
needsMaterialize.push(node);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
needsArm.push(node);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return { needsMaterialize, needsArm };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Pure viability check for a pathway, computed from ACTUAL current tree state.
|
|
60
|
+
*
|
|
61
|
+
* A pathway is viable when every obstacle reachable on it is either already
|
|
62
|
+
* cleared OR still has at least one planned overcome that has NOT failed
|
|
63
|
+
* clearance this tick. If any gating obstacle is both uncleared and has no
|
|
64
|
+
* un-failed remedy, the pathway cannot reach the goal -> not viable.
|
|
65
|
+
*
|
|
66
|
+
* Pathway membership is approximated by pathwayId match on the node when the
|
|
67
|
+
* PrtNode carries one; absent per-node pathway tagging in the current schema,
|
|
68
|
+
* the whole tree is treated as the pathway's reachable set (single-pathway
|
|
69
|
+
* default). This stays a conservative, pure read of the tree -- it never
|
|
70
|
+
* mutates and never reverts.
|
|
71
|
+
*/
|
|
72
|
+
function isPathwayViable(_pathwayId, nodes, edges, clearedNodeIds, clearanceFailedObstacleIds) {
|
|
73
|
+
void _pathwayId;
|
|
74
|
+
const overcomesEdges = edges.filter((e) => e.edgeType === 'overcomes');
|
|
75
|
+
// Obstacle -> set of overcome ids that target it.
|
|
76
|
+
const remediesByObstacle = new Map();
|
|
77
|
+
for (const edge of overcomesEdges) {
|
|
78
|
+
const list = remediesByObstacle.get(edge.toNodeId) ?? [];
|
|
79
|
+
list.push(edge.fromNodeId);
|
|
80
|
+
remediesByObstacle.set(edge.toNodeId, list);
|
|
81
|
+
}
|
|
82
|
+
const nodeById = new Map(nodes.map((n) => [n.id, n]));
|
|
83
|
+
for (const node of nodes) {
|
|
84
|
+
if (node.nodeType !== 'obstacle') {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (clearedNodeIds.has(node.id)) {
|
|
88
|
+
continue; // already cleared -> not blocking
|
|
89
|
+
}
|
|
90
|
+
const remedies = remediesByObstacle.get(node.id) ?? [];
|
|
91
|
+
if (remedies.length === 0) {
|
|
92
|
+
// Open obstacle with no planned overcome -> dead end on this pathway.
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
// Viable only if at least one remedy has not failed clearance this tick.
|
|
96
|
+
const hasUnfailedRemedy = remedies.some((overcomeId) => {
|
|
97
|
+
const overcome = nodeById.get(overcomeId);
|
|
98
|
+
if (!overcome) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
// The remedy "failed" when its overcome cleared yet the obstacle is in
|
|
102
|
+
// the failed set (clearance_fail) -- treat that obstacle as un-remediable
|
|
103
|
+
// by this overcome.
|
|
104
|
+
return !clearanceFailedObstacleIds.has(node.id);
|
|
105
|
+
});
|
|
106
|
+
if (!hasUnfailedRemedy) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
export async function runPrdControllerTick(prd, deps) {
|
|
113
|
+
const { nodes, edges } = await deps.loadPrtGraph(prd.id);
|
|
114
|
+
const obstacles = nodes.filter((node) => node.nodeType === 'obstacle');
|
|
115
|
+
const clearedNodeIds = new Set();
|
|
116
|
+
// Pre-seed nodes already marked cleared in the DB.
|
|
117
|
+
for (const node of nodes) {
|
|
118
|
+
if (node.status === 'cleared') {
|
|
119
|
+
clearedNodeIds.add(node.id);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
let obstaclesEvaluated = 0;
|
|
123
|
+
let obstaclesCleared = 0;
|
|
124
|
+
// Obstacles whose predicate ran and definitively did NOT clear (not deferred).
|
|
125
|
+
// Feeds divergence detection (clearance_fail) and pathway viability.
|
|
126
|
+
const clearanceFailedObstacleIds = new Set();
|
|
127
|
+
// Evaluate clearance predicates; newly-cleared obstacles get persisted.
|
|
128
|
+
for (const obstacle of obstacles) {
|
|
129
|
+
if (!obstacle.clearancePredicate) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
obstaclesEvaluated += 1;
|
|
133
|
+
const verdict = await deps.evaluateClearance(obstacle.clearancePredicate, {
|
|
134
|
+
worktreeDir: deps.worktreeDir,
|
|
135
|
+
});
|
|
136
|
+
if (verdict.cleared) {
|
|
137
|
+
clearedNodeIds.add(obstacle.id);
|
|
138
|
+
if (obstacle.status !== 'cleared') {
|
|
139
|
+
await deps.markNodeCleared(obstacle.id);
|
|
140
|
+
obstaclesCleared += 1;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else if (!verdict.deferred) {
|
|
144
|
+
clearanceFailedObstacleIds.add(obstacle.id);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const { needsMaterialize, needsArm } = computePrtFrontier(nodes, edges, clearedNodeIds);
|
|
148
|
+
const roleId = await deps.resolveArmRoleId(prd);
|
|
149
|
+
let materialized = 0;
|
|
150
|
+
let armed = 0;
|
|
151
|
+
let skippedNoRole = 0;
|
|
152
|
+
for (const node of needsMaterialize) {
|
|
153
|
+
const { focusId } = await deps.materializeOvercome(node.id);
|
|
154
|
+
materialized += 1;
|
|
155
|
+
if (roleId) {
|
|
156
|
+
await deps.armFocus(focusId, roleId);
|
|
157
|
+
armed += 1;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
skippedNoRole += 1;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
for (const node of needsArm) {
|
|
164
|
+
if (node.focusId === null) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (roleId) {
|
|
168
|
+
await deps.armFocus(node.focusId, roleId);
|
|
169
|
+
armed += 1;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
skippedNoRole += 1;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// PRD complete when every obstacle is cleared.
|
|
176
|
+
const allObstaclesCleared = obstacles.length > 0 && obstacles.every((obstacle) => clearedNodeIds.has(obstacle.id));
|
|
177
|
+
let prdDone = false;
|
|
178
|
+
if (allObstaclesCleared) {
|
|
179
|
+
await deps.markPrdDone(prd.id);
|
|
180
|
+
prdDone = true;
|
|
181
|
+
}
|
|
182
|
+
// --- Realign (divergence detection + path-switch / escalate) -------------
|
|
183
|
+
//
|
|
184
|
+
// PLL re-capture. Runs only for a PRD that has a committed (locked) pathway.
|
|
185
|
+
// On divergence we re-acquire the best surviving path from the ACTUAL current
|
|
186
|
+
// tree state, or hand control to the human if none survives.
|
|
187
|
+
//
|
|
188
|
+
// NO-REVERT INVARIANT: this step performs NO revert. Dead-path residue (work
|
|
189
|
+
// already merged on an abandoned pathway) is new reality. We ONLY re-point
|
|
190
|
+
// committed_path_id via commitPathway and let the existing controller re-arm
|
|
191
|
+
// the frontier from the new path. Nothing here deletes focuses, commits, or
|
|
192
|
+
// merged work, and the goal is never lowered to fit a surviving path.
|
|
193
|
+
let diverged = false;
|
|
194
|
+
let pathSwitched = false;
|
|
195
|
+
let escalated = false;
|
|
196
|
+
if (prd.committedPathId) {
|
|
197
|
+
const signals = detectDivergence({
|
|
198
|
+
nodes,
|
|
199
|
+
edges,
|
|
200
|
+
clearedNodeIds,
|
|
201
|
+
clearanceFailedObstacleIds,
|
|
202
|
+
committedPathwayId: prd.committedPathId,
|
|
203
|
+
});
|
|
204
|
+
if (signals.length > 0) {
|
|
205
|
+
diverged = true;
|
|
206
|
+
const pathways = await deps.loadPathways(prd.id);
|
|
207
|
+
const pathwayStates = pathways.map((p) => ({
|
|
208
|
+
id: p.id,
|
|
209
|
+
status: p.status,
|
|
210
|
+
}));
|
|
211
|
+
const { survivor, switched } = selectSurvivingPath(pathwayStates, {
|
|
212
|
+
committedPathwayId: prd.committedPathId,
|
|
213
|
+
isPathwayViable: (pid) => isPathwayViable(pid, nodes, edges, clearedNodeIds, clearanceFailedObstacleIds),
|
|
214
|
+
});
|
|
215
|
+
if (survivor && switched) {
|
|
216
|
+
// Re-point the committed pathway (re-capture). No revert.
|
|
217
|
+
await deps.commitPathway(prd.id, survivor);
|
|
218
|
+
pathSwitched = true;
|
|
219
|
+
}
|
|
220
|
+
else if (!survivor) {
|
|
221
|
+
// No surviving path: the human owns intent -- escalate, never lower the goal.
|
|
222
|
+
escalated = true;
|
|
223
|
+
await deps.fileEscalation({
|
|
224
|
+
organizationId: deps.organizationId,
|
|
225
|
+
productId: prd.productId,
|
|
226
|
+
reason: 'prd_divergence_no_surviving_path',
|
|
227
|
+
kind: 'prd_divergence_no_surviving_path',
|
|
228
|
+
details: { prdId: prd.id, signals },
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
obstaclesEvaluated,
|
|
235
|
+
obstaclesCleared,
|
|
236
|
+
materialized,
|
|
237
|
+
armed,
|
|
238
|
+
skippedNoRole,
|
|
239
|
+
prdDone,
|
|
240
|
+
diverged,
|
|
241
|
+
pathSwitched,
|
|
242
|
+
escalated,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function defaultDeps(config) {
|
|
246
|
+
return {
|
|
247
|
+
loadPrtGraph: (prdId) => loadPrtGraph(prdId),
|
|
248
|
+
evaluateClearance: (predicate, ctx) => evaluateClearance(predicate, ctx),
|
|
249
|
+
markNodeCleared: (nodeId) => markNodeCleared(nodeId),
|
|
250
|
+
materializeOvercome: (nodeId) => materializeOvercome(nodeId),
|
|
251
|
+
armFocus: (focusId, agentRoleId) => armFocus(focusId, agentRoleId),
|
|
252
|
+
markPrdDone: (prdId) => markPrdDone(prdId),
|
|
253
|
+
resolveArmRoleId: async (_prd) => {
|
|
254
|
+
void _prd;
|
|
255
|
+
// TELORA_PRD_ARM_ROLE_ID must be set to the agent_roles UUID to use when
|
|
256
|
+
// arming frontier foci (sets product_focuses.assigned_agent_role_id).
|
|
257
|
+
// When unset, every frontier overcome is counted as skippedNoRole and no
|
|
258
|
+
// focus is ever armed -- the controller runs but produces no output.
|
|
259
|
+
return process.env.TELORA_PRD_ARM_ROLE_ID ?? null;
|
|
260
|
+
},
|
|
261
|
+
loadPathways: (prdId) => loadPathways(prdId),
|
|
262
|
+
commitPathway: (prdId, pathwayId) => commitPathway(prdId, pathwayId),
|
|
263
|
+
fileEscalation: (input) => fileEscalation(input),
|
|
264
|
+
organizationId: config.organizationId,
|
|
265
|
+
worktreeDir: config.worktreeDir,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
export async function runPrdControllerTickAll(config, deps) {
|
|
269
|
+
const totals = {
|
|
270
|
+
obstaclesEvaluated: 0,
|
|
271
|
+
obstaclesCleared: 0,
|
|
272
|
+
materialized: 0,
|
|
273
|
+
armed: 0,
|
|
274
|
+
skippedNoRole: 0,
|
|
275
|
+
prdsDone: 0,
|
|
276
|
+
prdsDiverged: 0,
|
|
277
|
+
prdsPathSwitched: 0,
|
|
278
|
+
prdsEscalated: 0,
|
|
279
|
+
};
|
|
280
|
+
for (const product of config.products) {
|
|
281
|
+
const productConfig = configForProduct(config, product);
|
|
282
|
+
const merged = { ...defaultDeps(productConfig), ...deps };
|
|
283
|
+
let prds;
|
|
284
|
+
try {
|
|
285
|
+
prds = await loadActivePrds(product.id);
|
|
286
|
+
}
|
|
287
|
+
catch (err) {
|
|
288
|
+
console.warn(`[prd-controller] failed to load active PRDs for product ${product.id}:`, err.message);
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
for (const prd of prds) {
|
|
292
|
+
try {
|
|
293
|
+
const result = await runPrdControllerTick(prd, merged);
|
|
294
|
+
totals.obstaclesEvaluated += result.obstaclesEvaluated;
|
|
295
|
+
totals.obstaclesCleared += result.obstaclesCleared;
|
|
296
|
+
totals.materialized += result.materialized;
|
|
297
|
+
totals.armed += result.armed;
|
|
298
|
+
totals.skippedNoRole += result.skippedNoRole;
|
|
299
|
+
if (result.prdDone) {
|
|
300
|
+
totals.prdsDone += 1;
|
|
301
|
+
}
|
|
302
|
+
if (result.diverged) {
|
|
303
|
+
totals.prdsDiverged += 1;
|
|
304
|
+
}
|
|
305
|
+
if (result.pathSwitched) {
|
|
306
|
+
totals.prdsPathSwitched += 1;
|
|
307
|
+
}
|
|
308
|
+
if (result.escalated) {
|
|
309
|
+
totals.prdsEscalated += 1;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
console.warn(`[prd-controller] tick failed for PRD ${prd.id}:`, err.message);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return totals;
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=prd-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prd-controller.js","sourceRoot":"","sources":["../src/prd-controller.ts"],"names":[],"mappings":"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"}
|