@cat-factory/orchestration 0.63.0 → 0.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/container.d.ts +4 -1
  2. package/dist/container.d.ts.map +1 -1
  3. package/dist/container.js +45 -12
  4. package/dist/container.js.map +1 -1
  5. package/dist/modules/execution/AgentContextBuilder.d.ts +11 -0
  6. package/dist/modules/execution/AgentContextBuilder.d.ts.map +1 -1
  7. package/dist/modules/execution/AgentContextBuilder.js +49 -3
  8. package/dist/modules/execution/AgentContextBuilder.js.map +1 -1
  9. package/dist/modules/execution/ExecutionService.d.ts +9 -1
  10. package/dist/modules/execution/ExecutionService.d.ts.map +1 -1
  11. package/dist/modules/execution/ExecutionService.js +9 -1
  12. package/dist/modules/execution/ExecutionService.js.map +1 -1
  13. package/dist/modules/execution/RunDispatcher.d.ts +62 -1
  14. package/dist/modules/execution/RunDispatcher.d.ts.map +1 -1
  15. package/dist/modules/execution/RunDispatcher.js +327 -90
  16. package/dist/modules/execution/RunDispatcher.js.map +1 -1
  17. package/dist/modules/execution/RunStateMachine.d.ts +7 -0
  18. package/dist/modules/execution/RunStateMachine.d.ts.map +1 -1
  19. package/dist/modules/execution/RunStateMachine.js +8 -0
  20. package/dist/modules/execution/RunStateMachine.js.map +1 -1
  21. package/dist/modules/execution/deployer.logic.d.ts +15 -1
  22. package/dist/modules/execution/deployer.logic.d.ts.map +1 -1
  23. package/dist/modules/execution/deployer.logic.js +41 -2
  24. package/dist/modules/execution/deployer.logic.js.map +1 -1
  25. package/dist/modules/execution/frame.logic.d.ts +20 -0
  26. package/dist/modules/execution/frame.logic.d.ts.map +1 -0
  27. package/dist/modules/execution/frame.logic.js +40 -0
  28. package/dist/modules/execution/frame.logic.js.map +1 -0
  29. package/dist/modules/initiative/InitiativeLoopService.d.ts +88 -0
  30. package/dist/modules/initiative/InitiativeLoopService.d.ts.map +1 -0
  31. package/dist/modules/initiative/InitiativeLoopService.js +356 -0
  32. package/dist/modules/initiative/InitiativeLoopService.js.map +1 -0
  33. package/dist/modules/initiative/InitiativeService.d.ts +31 -1
  34. package/dist/modules/initiative/InitiativeService.d.ts.map +1 -1
  35. package/dist/modules/initiative/InitiativeService.js +53 -0
  36. package/dist/modules/initiative/InitiativeService.js.map +1 -1
  37. package/dist/modules/initiative/initiative.logic.d.ts +58 -1
  38. package/dist/modules/initiative/initiative.logic.d.ts.map +1 -1
  39. package/dist/modules/initiative/initiative.logic.js +157 -0
  40. package/dist/modules/initiative/initiative.logic.js.map +1 -1
  41. package/package.json +10 -10
@@ -0,0 +1,20 @@
1
+ import type { Block } from '@cat-factory/kernel';
2
+ /**
3
+ * The service-frame block enclosing a block, resolved from an already-loaded block map — a
4
+ * bounded (the tree is at most frame → module → task), cycle-guarded walk up the `parentId`
5
+ * chain. Returns the first ancestor that is a `frame` (or the topmost parent-less block, or the
6
+ * last block reached if the map is missing a link). Pure: the caller owns the load, so this does
7
+ * NO repository access — the point-read variant is `AgentContextBuilder.resolveServiceFrame`.
8
+ */
9
+ export declare function frameOf(byId: ReadonlyMap<string, Block>, blockId: string): Block | null;
10
+ /**
11
+ * The connected service frames "directly involved" in a task beyond its own — the shared read-time
12
+ * STALE FILTER over `block.involvedServiceIds` used by BOTH the deployer fan-out
13
+ * (`RunDispatcher.resolveDeployTargets`) and the agent-context resolution
14
+ * (`AgentContextBuilder.resolveInvolvedServices`), so the two can't drift on which peers are valid.
15
+ * Keeps only ids that (a) are not the own frame, (b) are STILL a connection neighbour of the own
16
+ * frame, (c) are unique, and (d) resolve to a `service` `frame` block. A stale/removed connection
17
+ * makes an id inert (dropped), never a run failure. Pure — the caller owns the block-list load.
18
+ */
19
+ export declare function validInvolvedServiceFrames(blocks: readonly Block[], block: Block, ownFrameId: string): Block[];
20
+ //# sourceMappingURL=frame.logic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/frame.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAGhD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAOvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,KAAK,EAAE,EACxB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,GACjB,KAAK,EAAE,CAUT"}
@@ -0,0 +1,40 @@
1
+ import { connectionNeighborIds } from '@cat-factory/contracts';
2
+ /**
3
+ * The service-frame block enclosing a block, resolved from an already-loaded block map — a
4
+ * bounded (the tree is at most frame → module → task), cycle-guarded walk up the `parentId`
5
+ * chain. Returns the first ancestor that is a `frame` (or the topmost parent-less block, or the
6
+ * last block reached if the map is missing a link). Pure: the caller owns the load, so this does
7
+ * NO repository access — the point-read variant is `AgentContextBuilder.resolveServiceFrame`.
8
+ */
9
+ export function frameOf(byId, blockId) {
10
+ let cursor = byId.get(blockId) ?? null;
11
+ for (let i = 0; cursor && i < 8; i++) {
12
+ if (cursor.level === 'frame' || !cursor.parentId)
13
+ return cursor;
14
+ cursor = byId.get(cursor.parentId) ?? null;
15
+ }
16
+ return cursor;
17
+ }
18
+ /**
19
+ * The connected service frames "directly involved" in a task beyond its own — the shared read-time
20
+ * STALE FILTER over `block.involvedServiceIds` used by BOTH the deployer fan-out
21
+ * (`RunDispatcher.resolveDeployTargets`) and the agent-context resolution
22
+ * (`AgentContextBuilder.resolveInvolvedServices`), so the two can't drift on which peers are valid.
23
+ * Keeps only ids that (a) are not the own frame, (b) are STILL a connection neighbour of the own
24
+ * frame, (c) are unique, and (d) resolve to a `service` `frame` block. A stale/removed connection
25
+ * makes an id inert (dropped), never a run failure. Pure — the caller owns the block-list load.
26
+ */
27
+ export function validInvolvedServiceFrames(blocks, block, ownFrameId) {
28
+ if (block.level !== 'task')
29
+ return [];
30
+ const ids = block.involvedServiceIds ?? [];
31
+ if (ids.length === 0)
32
+ return [];
33
+ const byId = new Map(blocks.map((b) => [b.id, b]));
34
+ const neighbors = connectionNeighborIds(blocks, ownFrameId);
35
+ return ids
36
+ .filter((id, i) => id !== ownFrameId && neighbors.has(id) && ids.indexOf(id) === i)
37
+ .map((id) => byId.get(id))
38
+ .filter((b) => !!b && b.level === 'frame' && b.type === 'service');
39
+ }
40
+ //# sourceMappingURL=frame.logic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame.logic.js","sourceRoot":"","sources":["../../../src/modules/execution/frame.logic.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAE9D;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CAAC,IAAgC,EAAE,OAAe;IACvE,IAAI,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,CAAA;IACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,MAAM,CAAC,KAAK,KAAK,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ;YAAE,OAAO,MAAM,CAAA;QAC/D,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAA;IAC5C,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAwB,EACxB,KAAY,EACZ,UAAkB;IAElB,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM;QAAE,OAAO,EAAE,CAAA;IACrC,MAAM,GAAG,GAAG,KAAK,CAAC,kBAAkB,IAAI,EAAE,CAAA;IAC1C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAClD,MAAM,SAAS,GAAG,qBAAqB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IAC3D,OAAO,GAAG;SACP,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,KAAK,UAAU,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;SAClF,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;SACzB,MAAM,CAAC,CAAC,CAAC,EAAc,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAA;AAClF,CAAC"}
@@ -0,0 +1,88 @@
1
+ import type { BlockRepository, Clock, ExecutionEventPublisher, IdGenerator, InitiativeItem, InitiativeRepository, PipelineRepository, ResolveRunRepoContext, ServiceRepository, TaskEstimate } from '@cat-factory/kernel';
2
+ import type { ExecutionService } from '../execution/ExecutionService.js';
3
+ import type { NotificationService } from '../notifications/NotificationService.js';
4
+ import type { InitiativeService } from './InitiativeService.js';
5
+ export interface InitiativeLoopServiceDependencies {
6
+ initiativeRepository: InitiativeRepository;
7
+ initiativeService: InitiativeService;
8
+ blockRepository: BlockRepository;
9
+ pipelineRepository: PipelineRepository;
10
+ executionService: ExecutionService;
11
+ events: ExecutionEventPublisher;
12
+ clock: Clock;
13
+ idGenerator: IdGenerator;
14
+ /** Raises the `initiative` notification (blocked item / completion). Absent ⇒ no cards. */
15
+ notificationService?: NotificationService;
16
+ /** Resolves the initiative's repo for the best-effort tracker re-commit. Absent ⇒ mirror skipped. */
17
+ resolveRunRepoContext?: ResolveRunRepoContext;
18
+ /** Stamps a spawned task with the frame's service (in-org sharing). Absent ⇒ no service link. */
19
+ serviceRepository?: ServiceRepository;
20
+ }
21
+ /**
22
+ * The initiative EXECUTION LOOP (slice 3): the driver that turns an approved plan into a
23
+ * running body of work. The cron/interval sweepers call {@link runDue}; a settling child run
24
+ * pokes {@link pokeForInitiativeBlock} so the loop advances immediately instead of waiting for
25
+ * the next sweep. Each per-initiative {@link tick}:
26
+ *
27
+ * 1. RECONCILE — batch-reads ONLY the spawned task blocks (one chunked `findByIds`, indexed —
28
+ * no N+1, no full-workspace scan) and folds each block's status back onto its item (done +
29
+ * PR link / pr_open / blocked + deviation).
30
+ * 2. COMPLETE — when every item is settled, flip the initiative + its anchor block `done`,
31
+ * re-commit the tracker, and notify.
32
+ * 3. SPAWN — creates task blocks for the eligible `pending` items (current phase, deps met,
33
+ * phase not halted by a blocked sibling) up to the concurrency cap, picking each task's
34
+ * pipeline from the policy rules. Spawning is CLAIM-FIRST: a CAS write records the
35
+ * pre-generated block id BEFORE any side effect, so a concurrent ticker that lost the CAS
36
+ * created nothing (single-writer by construction, exactly like the rest of the entity).
37
+ *
38
+ * Every entity write goes through {@link InitiativeService}'s rev-guarded CAS, so a lost tick is
39
+ * simply abandoned; the next sweep retries. A per-service task-limit `ConflictError` leaves the
40
+ * item `pending` for the next sweep (never `blocked`); a missing pipeline (deleted after ingest)
41
+ * records a deviation + notification and blocks the item — the sweep NEVER throws.
42
+ */
43
+ export declare class InitiativeLoopService {
44
+ private readonly deps;
45
+ /** In-process re-entrancy guard so a cron sweep + a terminal poke don't double-tick one initiative. */
46
+ private readonly ticking;
47
+ constructor(deps: InitiativeLoopServiceDependencies);
48
+ /**
49
+ * Tick every `executing` initiative across all workspaces. The cron (Worker) / interval
50
+ * (Node) sweepers call this. Never throws — a per-initiative failure is isolated so one bad
51
+ * initiative can't stall the others. Returns aggregate counts for logging.
52
+ */
53
+ runDue(_now: number): Promise<{
54
+ ticked: number;
55
+ spawned: number;
56
+ completed: number;
57
+ }>;
58
+ /**
59
+ * Best-effort single tick for one initiative, triggered when a spawned child run settles (a
60
+ * terminal run / a merge). Fire-and-forget from the caller; swallow errors (the sweep is the
61
+ * backstop). `initiativeBlockId` is the block the settled child carries in its `initiativeId`.
62
+ */
63
+ pokeForInitiativeBlock(workspaceId: string, initiativeBlockId: string): Promise<void>;
64
+ private tick;
65
+ /**
66
+ * Batch-read ONLY the blocks the initiative's items were spawned as (a single chunked `IN`
67
+ * via {@link BlockRepository.findByIds}), indexed by id for the reconcile lookup — never a
68
+ * full-workspace block scan. Empty when no item carries a block link yet.
69
+ */
70
+ private readSpawnedBlocks;
71
+ private reconcile;
72
+ private complete;
73
+ private spawn;
74
+ private spawnItem;
75
+ /** Build the task block a spawned item runs as (item estimate stamped, `initiativeId` linked). */
76
+ private buildTaskBlock;
77
+ /**
78
+ * Block an item that could not be spawned (a missing pipeline / a start failure): mark it
79
+ * `blocked`, drop its dangling block link, record a deviation, and raise the notification.
80
+ * The blocked item halts its phase (see `phaseIsHalted`) until a human intervenes.
81
+ */
82
+ private blockItem;
83
+ private recommitTracker;
84
+ private notify;
85
+ }
86
+ /** Build a {@link TaskEstimate} from an item's planner estimate, stamped for the spawned block. */
87
+ export declare function estimateForItem(item: InitiativeItem, now: number): TaskEstimate | undefined;
88
+ //# sourceMappingURL=InitiativeLoopService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InitiativeLoopService.d.ts","sourceRoot":"","sources":["../../../src/modules/initiative/InitiativeLoopService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,eAAe,EACf,KAAK,EACL,uBAAuB,EACvB,WAAW,EAEX,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,YAAY,EACb,MAAM,qBAAqB,CAAA;AAG5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAA;AACxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAA;AAClF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAa/D,MAAM,WAAW,iCAAiC;IAChD,oBAAoB,EAAE,oBAAoB,CAAA;IAC1C,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,eAAe,EAAE,eAAe,CAAA;IAChC,kBAAkB,EAAE,kBAAkB,CAAA;IACtC,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,MAAM,EAAE,uBAAuB,CAAA;IAC/B,KAAK,EAAE,KAAK,CAAA;IACZ,WAAW,EAAE,WAAW,CAAA;IACxB,2FAA2F;IAC3F,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;IACzC,qGAAqG;IACrG,qBAAqB,CAAC,EAAE,qBAAqB,CAAA;IAC7C,iGAAiG;IACjG,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;CACtC;AAcD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,qBAAqB;IAIpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,uGAAuG;IACvG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAE5C,YAA6B,IAAI,EAAE,iCAAiC,EAAI;IAExE;;;;OAIG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAe1F;IAED;;;;OAIG;IACG,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU1F;YAEa,IAAI;IAqClB;;;;OAIG;YACW,iBAAiB;YAcjB,SAAS;YA0CT,QAAQ;YAqBR,KAAK;YAsCL,SAAS;IAwEvB,kGAAkG;IAClG,OAAO,CAAC,cAAc;IA2BtB;;;;OAIG;YACW,SAAS;YA+BT,eAAe;YA2Bf,MAAM;CAgCrB;AAED,mGAAmG;AACnG,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAU3F"}
@@ -0,0 +1,356 @@
1
+ import { ConflictError, DomainError } from '@cat-factory/kernel';
2
+ import { commitInitiativeTracker } from '@cat-factory/agents';
3
+ import { activeItemCount, allItemsSettled, applyRevertClaim, applySpawnClaim, deriveCurrentPhase, effectiveMaxConcurrent, eligibleItemsToSpawn, reconcileItem, selectInitiativePipeline, } from './initiative.logic.js';
4
+ /**
5
+ * The initiative EXECUTION LOOP (slice 3): the driver that turns an approved plan into a
6
+ * running body of work. The cron/interval sweepers call {@link runDue}; a settling child run
7
+ * pokes {@link pokeForInitiativeBlock} so the loop advances immediately instead of waiting for
8
+ * the next sweep. Each per-initiative {@link tick}:
9
+ *
10
+ * 1. RECONCILE — batch-reads ONLY the spawned task blocks (one chunked `findByIds`, indexed —
11
+ * no N+1, no full-workspace scan) and folds each block's status back onto its item (done +
12
+ * PR link / pr_open / blocked + deviation).
13
+ * 2. COMPLETE — when every item is settled, flip the initiative + its anchor block `done`,
14
+ * re-commit the tracker, and notify.
15
+ * 3. SPAWN — creates task blocks for the eligible `pending` items (current phase, deps met,
16
+ * phase not halted by a blocked sibling) up to the concurrency cap, picking each task's
17
+ * pipeline from the policy rules. Spawning is CLAIM-FIRST: a CAS write records the
18
+ * pre-generated block id BEFORE any side effect, so a concurrent ticker that lost the CAS
19
+ * created nothing (single-writer by construction, exactly like the rest of the entity).
20
+ *
21
+ * Every entity write goes through {@link InitiativeService}'s rev-guarded CAS, so a lost tick is
22
+ * simply abandoned; the next sweep retries. A per-service task-limit `ConflictError` leaves the
23
+ * item `pending` for the next sweep (never `blocked`); a missing pipeline (deleted after ingest)
24
+ * records a deviation + notification and blocks the item — the sweep NEVER throws.
25
+ */
26
+ export class InitiativeLoopService {
27
+ deps;
28
+ /** In-process re-entrancy guard so a cron sweep + a terminal poke don't double-tick one initiative. */
29
+ ticking = new Set();
30
+ constructor(deps) {
31
+ this.deps = deps;
32
+ }
33
+ /**
34
+ * Tick every `executing` initiative across all workspaces. The cron (Worker) / interval
35
+ * (Node) sweepers call this. Never throws — a per-initiative failure is isolated so one bad
36
+ * initiative can't stall the others. Returns aggregate counts for logging.
37
+ */
38
+ async runDue(_now) {
39
+ const executing = await this.deps.initiativeRepository.listExecuting();
40
+ let spawned = 0;
41
+ let completed = 0;
42
+ for (const { workspaceId, initiative } of executing) {
43
+ try {
44
+ const result = await this.tick(workspaceId, initiative);
45
+ spawned += result.spawned;
46
+ if (result.completed)
47
+ completed++;
48
+ }
49
+ catch {
50
+ // Isolate a bad initiative; the next sweep retries it. (Each entity write is already
51
+ // CAS-guarded, so a partial tick left the entity consistent.)
52
+ }
53
+ }
54
+ return { ticked: executing.length, spawned, completed };
55
+ }
56
+ /**
57
+ * Best-effort single tick for one initiative, triggered when a spawned child run settles (a
58
+ * terminal run / a merge). Fire-and-forget from the caller; swallow errors (the sweep is the
59
+ * backstop). `initiativeBlockId` is the block the settled child carries in its `initiativeId`.
60
+ */
61
+ async pokeForInitiativeBlock(workspaceId, initiativeBlockId) {
62
+ try {
63
+ const initiative = await this.deps.initiativeRepository.getByBlock(workspaceId, initiativeBlockId);
64
+ if (initiative && initiative.status === 'executing')
65
+ await this.tick(workspaceId, initiative);
66
+ }
67
+ catch {
68
+ // Swallow — the periodic sweep will pick the initiative up.
69
+ }
70
+ }
71
+ async tick(workspaceId, seed) {
72
+ const key = seed.id;
73
+ if (this.ticking.has(key))
74
+ return { spawned: 0, completed: false };
75
+ this.ticking.add(key);
76
+ try {
77
+ // Re-read the freshest entity (the seed may be stale — from listExecuting or a poke).
78
+ let initiative = await this.deps.initiativeRepository.getByBlock(workspaceId, seed.blockId);
79
+ if (!initiative || initiative.status !== 'executing')
80
+ return { spawned: 0, completed: false };
81
+ const startRev = initiative.rev;
82
+ // 1. Reconcile spawned tasks from their blocks — a single batched point-read of ONLY the
83
+ // spawned task blocks (chunked `IN` via `findByIds`, not a full-workspace scan), indexed.
84
+ const blocksById = await this.readSpawnedBlocks(workspaceId, initiative);
85
+ initiative = (await this.reconcile(workspaceId, initiative, blocksById)) ?? initiative;
86
+ // 2. Complete when every item is settled.
87
+ if (allItemsSettled(initiative)) {
88
+ await this.complete(workspaceId, initiative);
89
+ return { spawned: 0, completed: true };
90
+ }
91
+ // 3. Spawn eligible items up to the effective concurrency cap.
92
+ const spawned = await this.spawn(workspaceId, initiative);
93
+ // 4. Best-effort mirror the tracker — ONLY when this tick actually mutated the entity (a
94
+ // reconcile folded a status, or a spawn/claim/block landed → the persisted `rev` moved).
95
+ // An idle tick (spawned tasks still running, nothing to fold) skips it entirely, so an
96
+ // executing initiative waiting on in-flight PRs doesn't hit GitHub every sweep. Never
97
+ // before a DB CAS wins; hash-short-circuited even when it does run.
98
+ await this.recommitTracker(workspaceId, initiative.blockId, startRev).catch(() => { });
99
+ return { spawned, completed: false };
100
+ }
101
+ finally {
102
+ this.ticking.delete(key);
103
+ }
104
+ }
105
+ /**
106
+ * Batch-read ONLY the blocks the initiative's items were spawned as (a single chunked `IN`
107
+ * via {@link BlockRepository.findByIds}), indexed by id for the reconcile lookup — never a
108
+ * full-workspace block scan. Empty when no item carries a block link yet.
109
+ */
110
+ async readSpawnedBlocks(workspaceId, initiative) {
111
+ const ids = (initiative.items ?? []).map((i) => i.blockId).filter((id) => !!id);
112
+ if (ids.length === 0)
113
+ return new Map();
114
+ const found = await this.deps.blockRepository.findByIds(ids);
115
+ return new Map(found.filter((r) => r.workspaceId === workspaceId).map((r) => [r.block.id, r.block]));
116
+ }
117
+ // ---- Reconcile ----------------------------------------------------------
118
+ async reconcile(workspaceId, initiative, blocksById) {
119
+ // Nothing to reconcile unless an actively-spawned item exists.
120
+ const hasActive = (initiative.items ?? []).some((i) => i.blockId && (i.status === 'in_progress' || i.status === 'pr_open'));
121
+ if (!hasActive)
122
+ return null;
123
+ let newlyBlocked = false;
124
+ const updated = await this.deps.initiativeService.update(workspaceId, initiative.blockId, (current) => {
125
+ const items = (current.items ?? []).map((it) => it.blockId ? reconcileItem(it, blocksById.get(it.blockId)) : it);
126
+ const deviations = [...(current.deviations ?? [])];
127
+ for (let i = 0; i < items.length; i++) {
128
+ const before = current.items[i];
129
+ const after = items[i];
130
+ if (after.status === 'blocked' && before.status !== 'blocked') {
131
+ newlyBlocked = true;
132
+ deviations.push({
133
+ id: this.deps.idGenerator.next('idev'),
134
+ at: this.deps.clock.now(),
135
+ itemId: after.id,
136
+ description: `Task for "${after.title}" was blocked; the phase is halted until it is retried or skipped.`,
137
+ });
138
+ }
139
+ }
140
+ return { ...current, items, deviations };
141
+ });
142
+ if (newlyBlocked && updated)
143
+ await this.notify(workspaceId, updated, 'item_blocked');
144
+ return updated;
145
+ }
146
+ // ---- Complete -----------------------------------------------------------
147
+ async complete(workspaceId, initiative) {
148
+ const done = await this.deps.initiativeService.update(workspaceId, initiative.blockId, (current) => allItemsSettled(current) && current.status === 'executing'
149
+ ? { ...current, status: 'done' }
150
+ : current);
151
+ if (!done || done.status !== 'done')
152
+ return;
153
+ await this.deps.blockRepository.update(workspaceId, done.blockId, {
154
+ status: 'done',
155
+ progress: 1,
156
+ });
157
+ await this.deps.events.boardChanged(workspaceId, 'initiative-complete', done.blockId);
158
+ await this.recommitTracker(workspaceId, done.blockId).catch(() => { });
159
+ await this.notify(workspaceId, done, 'complete');
160
+ }
161
+ // ---- Spawn --------------------------------------------------------------
162
+ async spawn(workspaceId, initiative) {
163
+ const phase = deriveCurrentPhase(initiative);
164
+ if (!phase)
165
+ return 0;
166
+ let slots = effectiveMaxConcurrent(initiative, phase) - activeItemCount(initiative);
167
+ if (slots <= 0)
168
+ return 0;
169
+ const eligible = eligibleItemsToSpawn(initiative);
170
+ if (eligible.length === 0)
171
+ return 0;
172
+ // Resolve the host frame ONCE (invariant across items): spawned tasks live under the
173
+ // initiative's parent service frame (structural containment), linked to the initiative via
174
+ // `initiativeId` (epic-style membership). No frame ⇒ nothing to host the work.
175
+ const anchor = await this.deps.blockRepository.get(workspaceId, initiative.blockId);
176
+ const frame = anchor?.parentId
177
+ ? await this.deps.blockRepository.get(workspaceId, anchor.parentId)
178
+ : null;
179
+ if (!frame)
180
+ return 0;
181
+ const serviceId = this.deps.serviceRepository
182
+ ? ((await this.deps.serviceRepository.getByFrameBlock(frame.id))?.id ?? null)
183
+ : null;
184
+ let spawned = 0;
185
+ let entity = initiative;
186
+ for (const item of eligible) {
187
+ if (slots <= 0)
188
+ break;
189
+ const result = await this.spawnItem(workspaceId, entity, item, frame, serviceId);
190
+ entity = result.entity;
191
+ if (result.outcome === 'spawned') {
192
+ spawned++;
193
+ slots--;
194
+ }
195
+ else if (result.outcome === 'conflict') {
196
+ // Lost a CAS, or the per-service task limit was hit — abandon the rest of this tick.
197
+ break;
198
+ }
199
+ // 'skipped' (item no longer pending, or blocked on a config problem) — try the next item.
200
+ }
201
+ return spawned;
202
+ }
203
+ async spawnItem(workspaceId, entity, item, frame, serviceId) {
204
+ const policy = entity.policy;
205
+ if (!policy)
206
+ return { outcome: 'skipped', entity };
207
+ // Pick the pipeline first; a missing one is a config problem (a pipeline deleted after
208
+ // ingest) → block the item + deviation + notify, NEVER throw inside the sweep.
209
+ const pipelineId = selectInitiativePipeline(item, policy);
210
+ if (!(await this.deps.pipelineRepository.get(workspaceId, pipelineId))) {
211
+ const blocked = await this.blockItem(workspaceId, entity.blockId, item.id, `Pipeline "${pipelineId}" no longer exists — pick another in the initiative policy.`);
212
+ return { outcome: 'skipped', entity: blocked ?? entity };
213
+ }
214
+ // Claim the item BEFORE any side effect: a CAS write records the pre-generated block id, so
215
+ // a concurrent ticker whose CAS lost created nothing (the winner's claim short-circuits the
216
+ // loser's transform to a no-op).
217
+ const spawnedBlockId = this.deps.idGenerator.next('blk');
218
+ const claimed = await this.deps.initiativeService.update(workspaceId, entity.blockId, (current) => applySpawnClaim(current, item.id, spawnedBlockId));
219
+ if (!claimed)
220
+ return { outcome: 'skipped', entity };
221
+ const claimedItem = (claimed.items ?? []).find((i) => i.id === item.id);
222
+ if (!claimedItem || claimedItem.blockId !== spawnedBlockId) {
223
+ // Another ticker already claimed it (a different block id), or it moved on — skip.
224
+ return { outcome: 'skipped', entity: claimed };
225
+ }
226
+ // The claim won: insert the task block, then start its run.
227
+ const block = this.buildTaskBlock(spawnedBlockId, item, frame, entity.blockId);
228
+ try {
229
+ await this.deps.blockRepository.insert(workspaceId, block, serviceId);
230
+ await this.deps.events.boardChanged(workspaceId, 'block-added', block.id);
231
+ await this.deps.executionService.start(workspaceId, block.id, pipelineId);
232
+ return { outcome: 'spawned', entity: claimed };
233
+ }
234
+ catch (error) {
235
+ // Roll back the block, then decide on the item. A per-service task-limit ConflictError is
236
+ // transient → revert the item to `pending` for the next sweep and stop spawning this tick.
237
+ // Any OTHER failure is (likely) a persistent config problem → block + notify so it isn't
238
+ // retried forever.
239
+ await this.deps.blockRepository.deleteMany(workspaceId, [block.id]).catch(() => { });
240
+ const reason = error instanceof DomainError ? error.details?.reason : undefined;
241
+ if (error instanceof ConflictError && reason === 'task_limit_reached') {
242
+ const reverted = await this.deps.initiativeService.update(workspaceId, entity.blockId, (current) => applyRevertClaim(current, item.id, spawnedBlockId));
243
+ return { outcome: 'conflict', entity: reverted ?? claimed };
244
+ }
245
+ const message = error instanceof Error ? error.message : 'Failed to start the task.';
246
+ const blocked = await this.blockItem(workspaceId, entity.blockId, item.id, `Could not start the task: ${message}`);
247
+ return { outcome: 'skipped', entity: blocked ?? claimed };
248
+ }
249
+ }
250
+ /** Build the task block a spawned item runs as (item estimate stamped, `initiativeId` linked). */
251
+ buildTaskBlock(blockId, item, frame, initiativeBlockId) {
252
+ const estimate = estimateForItem(item, this.deps.clock.now());
253
+ return {
254
+ id: blockId,
255
+ title: item.title,
256
+ // Inherit the host frame's (behavioural) repo type, like BoardService.addTask.
257
+ type: frame.type,
258
+ description: item.description,
259
+ position: { x: 24, y: 96 },
260
+ status: 'planned',
261
+ progress: 0,
262
+ dependsOn: [],
263
+ executionId: null,
264
+ level: 'task',
265
+ parentId: frame.id,
266
+ // Epic-style membership so the loop reconciles from the block and the board badges it. The
267
+ // loop OWNS sequencing, so NEVER opt into `autoStartDependents` on a spawned block.
268
+ initiativeId: initiativeBlockId,
269
+ ...(estimate ? { estimate } : {}),
270
+ };
271
+ }
272
+ /**
273
+ * Block an item that could not be spawned (a missing pipeline / a start failure): mark it
274
+ * `blocked`, drop its dangling block link, record a deviation, and raise the notification.
275
+ * The blocked item halts its phase (see `phaseIsHalted`) until a human intervenes.
276
+ */
277
+ async blockItem(workspaceId, initiativeBlockId, itemId, note) {
278
+ const updated = await this.deps.initiativeService.update(workspaceId, initiativeBlockId, (current) => {
279
+ const items = (current.items ?? []).map((i) => i.id === itemId ? { ...i, status: 'blocked', note, blockId: null } : i);
280
+ const deviations = [
281
+ ...(current.deviations ?? []),
282
+ {
283
+ id: this.deps.idGenerator.next('idev'),
284
+ at: this.deps.clock.now(),
285
+ itemId,
286
+ description: note,
287
+ },
288
+ ];
289
+ return { ...current, items, deviations };
290
+ });
291
+ if (updated)
292
+ await this.notify(workspaceId, updated, 'item_blocked');
293
+ return updated;
294
+ }
295
+ // ---- Tracker mirror + notifications -------------------------------------
296
+ async recommitTracker(workspaceId, initiativeBlockId, sinceRev) {
297
+ if (!this.deps.resolveRunRepoContext)
298
+ return;
299
+ const initiative = await this.deps.initiativeRepository.getByBlock(workspaceId, initiativeBlockId);
300
+ if (!initiative)
301
+ return;
302
+ // Nothing changed this tick (the persisted rev never moved) ⇒ skip the repo round-trip.
303
+ if (sinceRev !== undefined && initiative.rev === sinceRev)
304
+ return;
305
+ const runRepo = await this.deps.resolveRunRepoContext(workspaceId, initiativeBlockId);
306
+ if (!runRepo)
307
+ return;
308
+ const doc = await commitInitiativeTracker(runRepo.repo, runRepo.baseBranch, initiative, new Date(this.deps.clock.now()));
309
+ // Stamp the committed version/hash back (a content-unchanged tick commits nothing, so the
310
+ // no-change short-circuit means a replay skips this write too). `markExecuting` leaves an
311
+ // already-`executing` status untouched and only writes the `doc` bookkeeping.
312
+ if (doc)
313
+ await this.deps.initiativeService.markExecuting(workspaceId, initiativeBlockId, doc);
314
+ }
315
+ async notify(workspaceId, initiative, reason) {
316
+ if (!this.deps.notificationService)
317
+ return;
318
+ const items = initiative.items ?? [];
319
+ const blocked = items.filter((i) => i.status === 'blocked');
320
+ const input = reason === 'complete'
321
+ ? {
322
+ title: `Initiative "${initiative.title}" complete`,
323
+ body: `Every planned task is resolved (${items.length} item${items.length === 1 ? '' : 's'}).`,
324
+ }
325
+ : {
326
+ title: `Initiative "${initiative.title}" needs attention`,
327
+ body: blocked.length === 1
328
+ ? `A task was blocked (${blocked[0].title}). Retry or skip it to unblock the phase.`
329
+ : `${blocked.length} tasks are blocked. Retry or skip them to unblock the phase.`,
330
+ };
331
+ await this.deps.notificationService
332
+ .raise(workspaceId, {
333
+ type: 'initiative',
334
+ blockId: initiative.blockId,
335
+ executionId: null,
336
+ title: input.title,
337
+ body: input.body,
338
+ payload: { initiativeReason: reason },
339
+ })
340
+ .catch(() => { });
341
+ }
342
+ }
343
+ /** Build a {@link TaskEstimate} from an item's planner estimate, stamped for the spawned block. */
344
+ export function estimateForItem(item, now) {
345
+ if (!item.estimate)
346
+ return undefined;
347
+ return {
348
+ complexity: item.estimate.complexity,
349
+ risk: item.estimate.risk,
350
+ impact: item.estimate.impact,
351
+ rationale: item.estimate.rationale ?? '',
352
+ model: 'initiative-planner',
353
+ createdAt: now,
354
+ };
355
+ }
356
+ //# sourceMappingURL=InitiativeLoopService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InitiativeLoopService.js","sourceRoot":"","sources":["../../../src/modules/initiative/InitiativeLoopService.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { Block, BlockRepository, Clock, CreateInitiativeInput, ExecutionEventPublisher, IdGenerator, Initiative, InitiativeRepository, WorkspaceRepository } from '@cat-factory/kernel';
1
+ import type { Block, BlockRepository, Clock, CreateInitiativeInput, ExecutionEventPublisher, IdGenerator, Initiative, InitiativeRepository, PipelineRepository, WorkspaceRepository } from '@cat-factory/kernel';
2
2
  export interface InitiativeServiceDependencies {
3
3
  workspaceRepository: WorkspaceRepository;
4
4
  blockRepository: BlockRepository;
@@ -6,6 +6,13 @@ export interface InitiativeServiceDependencies {
6
6
  events: ExecutionEventPublisher;
7
7
  clock: Clock;
8
8
  idGenerator: IdGenerator;
9
+ /**
10
+ * Pipelines, used ONLY to validate the plan's `defaultPipelineId` at ingest (fail the
11
+ * planning run loudly on a plan that names a non-existent pipeline, rather than surfacing
12
+ * it later as a per-item spawn deviation). Optional so a deployment/test without pipelines
13
+ * wired still ingests. A pipeline deleted AFTER ingest is handled by the loop at spawn.
14
+ */
15
+ pipelineRepository?: PipelineRepository;
9
16
  }
10
17
  /**
11
18
  * The initiative entity's owner: creation (the board block + the entity in one
@@ -40,6 +47,13 @@ export declare class InitiativeService {
40
47
  * initiative (nothing to ingest into).
41
48
  */
42
49
  ingestPlan(workspaceId: string, blockId: string, rawDraft: unknown): Promise<Initiative | null>;
50
+ /**
51
+ * Fail a plan ingest whose policy names a pipeline that doesn't exist (the default, or a
52
+ * rule/item override) — a plan the loop could never execute. No-op when no pipeline
53
+ * repository is wired (tests/conformance). The loop still guards a pipeline deleted AFTER
54
+ * ingest at spawn time (a deviation + notification, never a throw inside the sweep).
55
+ */
56
+ private assertPipelinesExist;
43
57
  /**
44
58
  * Flip an initiative to `executing` (the committer step ran: the plan is
45
59
  * approved and the tracker mirror committed), stamping the repo-doc
@@ -50,6 +64,22 @@ export declare class InitiativeService {
50
64
  version: number;
51
65
  hash: string;
52
66
  } | null): Promise<Initiative | null>;
67
+ /**
68
+ * Apply a CAS-guarded transform to the block's initiative — the execution loop's write
69
+ * path. A content-identical transform short-circuits to no write (replay/idempotency);
70
+ * a lost CAS reloads and retries a bounded number of times. Returns the persisted entity,
71
+ * or null when the block has no initiative.
72
+ */
73
+ update(workspaceId: string, blockId: string, transform: (current: Initiative) => Initiative): Promise<Initiative | null>;
74
+ /** Pause an executing initiative (the sweep skips it; in-flight tasks finish naturally). */
75
+ pause(workspaceId: string, blockId: string): Promise<Initiative | null>;
76
+ /** Resume a paused initiative back to `executing` (the next sweep picks it up). */
77
+ resume(workspaceId: string, blockId: string): Promise<Initiative | null>;
78
+ /**
79
+ * Cancel an initiative: stop spawning further work. Terminal from the loop's view. In-flight
80
+ * spawned tasks are left to finish on their own (cascading their teardown is slice 4).
81
+ */
82
+ cancel(workspaceId: string, blockId: string): Promise<Initiative | null>;
53
83
  /** Append a fresh round of pending interview questions (parks the interview `awaiting`). */
54
84
  recordInterviewQuestions(workspaceId: string, blockId: string, questions: string[]): Promise<Initiative | null>;
55
85
  /** Record the human's answer to one pending question (no run resume; the controller does that). */
@@ -1 +1 @@
1
- {"version":3,"file":"InitiativeService.d.ts","sourceRoot":"","sources":["../../../src/modules/initiative/InitiativeService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,eAAe,EACf,KAAK,EACL,qBAAqB,EACrB,uBAAuB,EACvB,WAAW,EACX,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,qBAAqB,CAAA;AAe5B,MAAM,WAAW,6BAA6B;IAC5C,mBAAmB,EAAE,mBAAmB,CAAA;IACxC,eAAe,EAAE,eAAe,CAAA;IAChC,oBAAoB,EAAE,oBAAoB,CAAA;IAC1C,MAAM,EAAE,uBAAuB,CAAA;IAC/B,KAAK,EAAE,KAAK,CAAA;IACZ,WAAW,EAAE,WAAW,CAAA;CACzB;AAKD;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAChB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,6BAA6B,EAAI;IAEpE;;;;;OAKG;IACG,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC;QAAE,UAAU,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAmEnD;IAED,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAE/C;IAEK,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAE9D;IAED,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAE3E;IAED;;;;;;;;OAQG;IACG,UAAU,CACd,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,OAAO,GAChB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAM5B;IAED;;;;;OAKG;IACG,aAAa,CACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,GAC5C,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAS5B;IAQD,4FAA4F;IACtF,wBAAwB,CAC5B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAI5B;IAED,mGAAmG;IAC7F,qBAAqB,CACzB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAI5B;IAED,qGAAqG;IAC/F,sBAAsB,CAC1B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,GACnE,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAE5B;IAED,uEAAuE;IACjE,cAAc,CAClB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAE5B;IAED;;;;OAIG;YACW,MAAM;CAwBrB"}
1
+ {"version":3,"file":"InitiativeService.d.ts","sourceRoot":"","sources":["../../../src/modules/initiative/InitiativeService.ts"],"names":[],"mappings":"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"}