@telora/daemon 0.16.42 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/build-info.json +6 -3
  2. package/dist/completion/event.d.ts +17 -0
  3. package/dist/completion/event.d.ts.map +1 -1
  4. package/dist/completion/event.js +46 -12
  5. package/dist/completion/event.js.map +1 -1
  6. package/dist/directive/directive-queue.d.ts +117 -0
  7. package/dist/directive/directive-queue.d.ts.map +1 -0
  8. package/dist/directive/directive-queue.js +114 -0
  9. package/dist/directive/directive-queue.js.map +1 -0
  10. package/dist/directive/stage-tracker.d.ts +23 -0
  11. package/dist/directive/stage-tracker.d.ts.map +1 -0
  12. package/dist/directive/stage-tracker.js +27 -0
  13. package/dist/directive/stage-tracker.js.map +1 -0
  14. package/dist/directive-executor.d.ts +3 -102
  15. package/dist/directive-executor.d.ts.map +1 -1
  16. package/dist/directive-executor.js +14 -112
  17. package/dist/directive-executor.js.map +1 -1
  18. package/dist/escalations.d.ts +38 -0
  19. package/dist/escalations.d.ts.map +1 -0
  20. package/dist/escalations.js +38 -0
  21. package/dist/escalations.js.map +1 -0
  22. package/dist/focus-engine.d.ts.map +1 -1
  23. package/dist/focus-engine.js +28 -0
  24. package/dist/focus-engine.js.map +1 -1
  25. package/dist/focus-executor.d.ts.map +1 -1
  26. package/dist/focus-executor.js +1 -0
  27. package/dist/focus-executor.js.map +1 -1
  28. package/dist/prd-clearance-engine.d.ts +121 -0
  29. package/dist/prd-clearance-engine.d.ts.map +1 -0
  30. package/dist/prd-clearance-engine.js +164 -0
  31. package/dist/prd-clearance-engine.js.map +1 -0
  32. package/dist/prd-controller.d.ts +87 -0
  33. package/dist/prd-controller.d.ts.map +1 -0
  34. package/dist/prd-controller.js +319 -0
  35. package/dist/prd-controller.js.map +1 -0
  36. package/dist/prd-divergence.d.ts +76 -0
  37. package/dist/prd-divergence.d.ts.map +1 -0
  38. package/dist/prd-divergence.js +148 -0
  39. package/dist/prd-divergence.js.map +1 -0
  40. package/dist/prompt-sections/context-sections.d.ts +32 -0
  41. package/dist/prompt-sections/context-sections.d.ts.map +1 -0
  42. package/dist/prompt-sections/context-sections.js +86 -0
  43. package/dist/prompt-sections/context-sections.js.map +1 -0
  44. package/dist/prompt-sections/execution-sections.d.ts +82 -0
  45. package/dist/prompt-sections/execution-sections.d.ts.map +1 -0
  46. package/dist/prompt-sections/execution-sections.js +601 -0
  47. package/dist/prompt-sections/execution-sections.js.map +1 -0
  48. package/dist/prompt-sections/persona-sections.d.ts +133 -0
  49. package/dist/prompt-sections/persona-sections.d.ts.map +1 -0
  50. package/dist/prompt-sections/persona-sections.js +317 -0
  51. package/dist/prompt-sections/persona-sections.js.map +1 -0
  52. package/dist/prompt-sections/role-sections.d.ts +24 -0
  53. package/dist/prompt-sections/role-sections.d.ts.map +1 -0
  54. package/dist/prompt-sections/role-sections.js +78 -0
  55. package/dist/prompt-sections/role-sections.js.map +1 -0
  56. package/dist/prompt-sections/shared.d.ts +66 -0
  57. package/dist/prompt-sections/shared.d.ts.map +1 -0
  58. package/dist/prompt-sections/shared.js +33 -0
  59. package/dist/prompt-sections/shared.js.map +1 -0
  60. package/dist/queries/prd.d.ts +79 -0
  61. package/dist/queries/prd.d.ts.map +1 -0
  62. package/dist/queries/prd.js +116 -0
  63. package/dist/queries/prd.js.map +1 -0
  64. package/dist/team-prompt-base.d.ts +16 -287
  65. package/dist/team-prompt-base.d.ts.map +1 -1
  66. package/dist/team-prompt-base.js +20 -1089
  67. package/dist/team-prompt-base.js.map +1 -1
  68. package/dist/templates/claude-md.d.ts.map +1 -1
  69. package/dist/templates/claude-md.js +0 -1
  70. package/dist/templates/claude-md.js.map +1 -1
  71. package/package.json +1 -1
@@ -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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"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * PRD divergence detection + path selection -- Staged Assembly: PRD Layer
3
+ * (Delivery E, task E1). PURE: no DB, no shell, no module-level mutable state.
4
+ *
5
+ * PLL framing. The committed pathway is the locked phase. Divergence is loss of
6
+ * lock -- the chosen approach stopped tracking intent. Path-switch is re-capture
7
+ * onto the best surviving path computed from ACTUAL current tree state. When no
8
+ * survivor exists the controller escalates to the human, who owns intent.
9
+ *
10
+ * NO-REVERT INVARIANT (read before editing). Dead-path residue -- code already
11
+ * merged on a now-abandoned pathway -- is NEW REALITY, not garbage to undo.
12
+ * Nothing in this module (or the realign step that consumes it) reverts, deletes,
13
+ * or rolls back focuses, commits, or merged work. Detection reads the tree;
14
+ * selection re-points which pathway is committed. The goal is never lowered to
15
+ * fit a path; we only re-acquire a path that still reaches the goal, or escalate.
16
+ *
17
+ * @module prd-divergence
18
+ */
19
+ import type { PrtNode, PrtEdge } from './queries/prd.js';
20
+ /** The shapes divergence can take on a Prerequisite Tree. */
21
+ export type DivergenceForm = 'clearance_fail' | 'negative_branch' | 'falsified_prerequisite';
22
+ /** A single detected divergence, anchored to the offending node. */
23
+ export interface DivergenceSignal {
24
+ form: DivergenceForm;
25
+ nodeId: string;
26
+ detail: string;
27
+ }
28
+ /** A held alternative pathway and its commitment status. */
29
+ export interface PathwayState {
30
+ id: string;
31
+ status: 'option' | 'committed' | 'abandoned';
32
+ }
33
+ /**
34
+ * Detect all divergence signals on a PRT snapshot. PURE. A healthy path
35
+ * returns []. Implements all three forms:
36
+ *
37
+ * - clearance_fail: an overcome O marked cleared (shipped) whose 'overcomes'
38
+ * edge O->B points at an obstacle B that did NOT clear this tick
39
+ * (B in clearanceFailedObstacleIds). The remedy ran but the obstacle stands.
40
+ *
41
+ * - negative_branch: an OPEN obstacle B (status !== 'cleared') with NO inbound
42
+ * 'overcomes' edge (no planned remedy) that is a prerequisite (edge B->Q) of
43
+ * some overcome Q which is not cleared. An unanticipated blocker on the path.
44
+ *
45
+ * - falsified_prerequisite: a 'prerequisite' edge P->Q where Q is cleared but
46
+ * P is not. Downstream proceeded though its prerequisite is unsatisfied.
47
+ */
48
+ export declare function detectDivergence(input: {
49
+ nodes: PrtNode[];
50
+ edges: PrtEdge[];
51
+ clearedNodeIds: Set<string>;
52
+ clearanceFailedObstacleIds: Set<string>;
53
+ committedPathwayId: string | null;
54
+ }): DivergenceSignal[];
55
+ /**
56
+ * Select the surviving committed pathway. PURE.
57
+ *
58
+ * Among pathways that are NOT abandoned:
59
+ * - If a committed pathway is set and still viable, keep it
60
+ * (survivor = committed, switched = false). Lock held.
61
+ * - Otherwise pick the first viable non-abandoned pathway; switched = true when
62
+ * that survivor differs from the previously committed pathway. Re-capture.
63
+ * - If none are viable, survivor = null, switched = false. The controller
64
+ * escalates -- the human owns intent; the goal is never lowered.
65
+ *
66
+ * NO-REVERT: choosing a different survivor only changes which pathway is
67
+ * committed. It never undoes work done on the abandoned/old pathway.
68
+ */
69
+ export declare function selectSurvivingPath(pathways: PathwayState[], opts: {
70
+ committedPathwayId: string | null;
71
+ isPathwayViable: (pathwayId: string) => boolean;
72
+ }): {
73
+ survivor: string | null;
74
+ switched: boolean;
75
+ };
76
+ //# sourceMappingURL=prd-divergence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prd-divergence.d.ts","sourceRoot":"","sources":["../src/prd-divergence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAMzD,6DAA6D;AAC7D,MAAM,MAAM,cAAc,GACtB,gBAAgB,GAChB,iBAAiB,GACjB,wBAAwB,CAAC;AAE7B,oEAAoE;AACpE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,4DAA4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAC;CAC9C;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,0BAA0B,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC,GAAG,gBAAgB,EAAE,CAsFrB;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,EAAE,EACxB,IAAI,EAAE;IACJ,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CACjD,GACA;IAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAyBhD"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * PRD divergence detection + path selection -- Staged Assembly: PRD Layer
3
+ * (Delivery E, task E1). PURE: no DB, no shell, no module-level mutable state.
4
+ *
5
+ * PLL framing. The committed pathway is the locked phase. Divergence is loss of
6
+ * lock -- the chosen approach stopped tracking intent. Path-switch is re-capture
7
+ * onto the best surviving path computed from ACTUAL current tree state. When no
8
+ * survivor exists the controller escalates to the human, who owns intent.
9
+ *
10
+ * NO-REVERT INVARIANT (read before editing). Dead-path residue -- code already
11
+ * merged on a now-abandoned pathway -- is NEW REALITY, not garbage to undo.
12
+ * Nothing in this module (or the realign step that consumes it) reverts, deletes,
13
+ * or rolls back focuses, commits, or merged work. Detection reads the tree;
14
+ * selection re-points which pathway is committed. The goal is never lowered to
15
+ * fit a path; we only re-acquire a path that still reaches the goal, or escalate.
16
+ *
17
+ * @module prd-divergence
18
+ */
19
+ // ---------------------------------------------------------------------------
20
+ // Divergence detection
21
+ // ---------------------------------------------------------------------------
22
+ /**
23
+ * Detect all divergence signals on a PRT snapshot. PURE. A healthy path
24
+ * returns []. Implements all three forms:
25
+ *
26
+ * - clearance_fail: an overcome O marked cleared (shipped) whose 'overcomes'
27
+ * edge O->B points at an obstacle B that did NOT clear this tick
28
+ * (B in clearanceFailedObstacleIds). The remedy ran but the obstacle stands.
29
+ *
30
+ * - negative_branch: an OPEN obstacle B (status !== 'cleared') with NO inbound
31
+ * 'overcomes' edge (no planned remedy) that is a prerequisite (edge B->Q) of
32
+ * some overcome Q which is not cleared. An unanticipated blocker on the path.
33
+ *
34
+ * - falsified_prerequisite: a 'prerequisite' edge P->Q where Q is cleared but
35
+ * P is not. Downstream proceeded though its prerequisite is unsatisfied.
36
+ */
37
+ export function detectDivergence(input) {
38
+ const { nodes, edges, clearedNodeIds, clearanceFailedObstacleIds } = input;
39
+ const signals = [];
40
+ const nodeById = new Map(nodes.map((n) => [n.id, n]));
41
+ const overcomesEdges = edges.filter((e) => e.edgeType === 'overcomes');
42
+ const prereqEdges = edges.filter((e) => e.edgeType === 'prerequisite');
43
+ // --- clearance_fail ---
44
+ // An overcome that is cleared but the obstacle it overcomes did not clear.
45
+ for (const edge of overcomesEdges) {
46
+ const overcome = nodeById.get(edge.fromNodeId);
47
+ const obstacle = nodeById.get(edge.toNodeId);
48
+ if (!overcome || !obstacle) {
49
+ continue;
50
+ }
51
+ if (overcome.nodeType !== 'overcome' || overcome.status !== 'cleared') {
52
+ continue;
53
+ }
54
+ if (clearanceFailedObstacleIds.has(obstacle.id)) {
55
+ signals.push({
56
+ form: 'clearance_fail',
57
+ nodeId: obstacle.id,
58
+ detail: `overcome ${overcome.id} is cleared (shipped) but obstacle ${obstacle.id} ` +
59
+ `failed its clearance predicate this tick`,
60
+ });
61
+ }
62
+ }
63
+ // --- negative_branch ---
64
+ // An open obstacle with no planned remedy that gates an uncleared overcome.
65
+ const obstaclesWithRemedy = new Set(overcomesEdges.map((e) => e.toNodeId));
66
+ for (const node of nodes) {
67
+ if (node.nodeType !== 'obstacle') {
68
+ continue;
69
+ }
70
+ if (node.status === 'cleared') {
71
+ continue;
72
+ }
73
+ if (obstaclesWithRemedy.has(node.id)) {
74
+ continue; // a remedy is planned -> anticipated, not a negative branch
75
+ }
76
+ // Is this obstacle a prerequisite of an uncleared overcome?
77
+ const gatesUnclearedOvercome = prereqEdges.some((edge) => {
78
+ if (edge.fromNodeId !== node.id) {
79
+ return false;
80
+ }
81
+ const target = nodeById.get(edge.toNodeId);
82
+ return (!!target &&
83
+ target.nodeType === 'overcome' &&
84
+ !clearedNodeIds.has(target.id));
85
+ });
86
+ if (gatesUnclearedOvercome) {
87
+ signals.push({
88
+ form: 'negative_branch',
89
+ nodeId: node.id,
90
+ detail: `obstacle ${node.id} is open with no planned overcome and gates an ` +
91
+ `uncleared overcome -- unanticipated blocker`,
92
+ });
93
+ }
94
+ }
95
+ // --- falsified_prerequisite ---
96
+ // A prerequisite edge whose downstream cleared while its upstream did not.
97
+ for (const edge of prereqEdges) {
98
+ if (clearedNodeIds.has(edge.toNodeId) &&
99
+ !clearedNodeIds.has(edge.fromNodeId)) {
100
+ signals.push({
101
+ form: 'falsified_prerequisite',
102
+ nodeId: edge.fromNodeId,
103
+ detail: `node ${edge.toNodeId} is cleared but its prerequisite ${edge.fromNodeId} ` +
104
+ `is not -- downstream proceeded on an unsatisfied prerequisite`,
105
+ });
106
+ }
107
+ }
108
+ return signals;
109
+ }
110
+ // ---------------------------------------------------------------------------
111
+ // Surviving-path selection (re-capture)
112
+ // ---------------------------------------------------------------------------
113
+ /**
114
+ * Select the surviving committed pathway. PURE.
115
+ *
116
+ * Among pathways that are NOT abandoned:
117
+ * - If a committed pathway is set and still viable, keep it
118
+ * (survivor = committed, switched = false). Lock held.
119
+ * - Otherwise pick the first viable non-abandoned pathway; switched = true when
120
+ * that survivor differs from the previously committed pathway. Re-capture.
121
+ * - If none are viable, survivor = null, switched = false. The controller
122
+ * escalates -- the human owns intent; the goal is never lowered.
123
+ *
124
+ * NO-REVERT: choosing a different survivor only changes which pathway is
125
+ * committed. It never undoes work done on the abandoned/old pathway.
126
+ */
127
+ export function selectSurvivingPath(pathways, opts) {
128
+ const candidates = pathways.filter((p) => p.status !== 'abandoned');
129
+ // Keep the committed path if it is still in play and viable.
130
+ if (opts.committedPathwayId !== null) {
131
+ const committedStillCandidate = candidates.some((p) => p.id === opts.committedPathwayId);
132
+ if (committedStillCandidate && opts.isPathwayViable(opts.committedPathwayId)) {
133
+ return { survivor: opts.committedPathwayId, switched: false };
134
+ }
135
+ }
136
+ // Otherwise re-acquire the first viable surviving option.
137
+ for (const pathway of candidates) {
138
+ if (opts.isPathwayViable(pathway.id)) {
139
+ return {
140
+ survivor: pathway.id,
141
+ switched: pathway.id !== opts.committedPathwayId,
142
+ };
143
+ }
144
+ }
145
+ // No survivor: hand control to the human.
146
+ return { survivor: null, switched: false };
147
+ }
148
+ //# sourceMappingURL=prd-divergence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prd-divergence.js","sourceRoot":"","sources":["../src/prd-divergence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Context section builders: focus context, product context docs, deployment
3
+ * profile, loop context, and execution config. Extracted from
4
+ * team-prompt-base.ts.
5
+ */
6
+ import type { FocusExecutionConfig } from '../types.js';
7
+ import type { ProductContextDoc } from '../queries/focuses.js';
8
+ import type { DeploymentProfileSnapshotContext, FocusTeamPromptContext } from './shared.js';
9
+ /**
10
+ * Build the focus context section (focus ID, name, product ID).
11
+ */
12
+ export declare function buildFocusContextSection(context: FocusTeamPromptContext): string[];
13
+ /**
14
+ * Build the product context documents section.
15
+ * Deduplicates documents by title. Returns empty array if no docs.
16
+ */
17
+ export declare function buildProductContextSection(docs?: ProductContextDoc[]): string[];
18
+ /**
19
+ * Build the deployment profile section (inception prompt + guidelines).
20
+ * Returns empty array if no snapshot provided.
21
+ */
22
+ export declare function buildDeploymentProfileSection(snapshot?: DeploymentProfileSnapshotContext | null): string[];
23
+ /**
24
+ * Build the loop context section (persona + documents + Q&A).
25
+ * Returns pre-formatted markdown from the loop.context resolver, or empty array if none.
26
+ */
27
+ export declare function buildLoopContextSection(loopContext?: string): string[];
28
+ /**
29
+ * Build the execution config section (max workers, poll interval).
30
+ */
31
+ export declare function buildExecutionConfigSection(config: FocusExecutionConfig): string[];
32
+ //# sourceMappingURL=context-sections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-sections.d.ts","sourceRoot":"","sources":["../../src/prompt-sections/context-sections.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EACV,gCAAgC,EAChC,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,EAAE,CAQlF;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,CAAC,EAAE,iBAAiB,EAAE,GAAG,MAAM,EAAE,CAqB/E;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,CAAC,EAAE,gCAAgC,GAAG,IAAI,GACjD,MAAM,EAAE,CAmBV;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAGtE;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAOlF"}