@cat-factory/orchestration 0.220.0 → 0.222.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 (65) hide show
  1. package/dist/container/dependencies.d.ts +22 -1
  2. package/dist/container/dependencies.d.ts.map +1 -1
  3. package/dist/container/foundation.d.ts +2 -0
  4. package/dist/container/foundation.d.ts.map +1 -1
  5. package/dist/container/foundation.js +4 -1
  6. package/dist/container/foundation.js.map +1 -1
  7. package/dist/container/platform-modules.d.ts +2 -0
  8. package/dist/container/platform-modules.d.ts.map +1 -1
  9. package/dist/container/platform-modules.js +2 -2
  10. package/dist/container/platform-modules.js.map +1 -1
  11. package/dist/container/runtime.d.ts +2 -0
  12. package/dist/container/runtime.d.ts.map +1 -1
  13. package/dist/container/runtime.js +12 -1
  14. package/dist/container/runtime.js.map +1 -1
  15. package/dist/container-content-libraries.d.ts +8 -2
  16. package/dist/container-content-libraries.d.ts.map +1 -1
  17. package/dist/container-content-libraries.js +12 -1
  18. package/dist/container-content-libraries.js.map +1 -1
  19. package/dist/container.d.ts +15 -1
  20. package/dist/container.d.ts.map +1 -1
  21. package/dist/container.js +5 -1
  22. package/dist/container.js.map +1 -1
  23. package/dist/modules/board/BoardService.d.ts +32 -33
  24. package/dist/modules/board/BoardService.d.ts.map +1 -1
  25. package/dist/modules/board/BoardService.js +121 -94
  26. package/dist/modules/board/BoardService.js.map +1 -1
  27. package/dist/modules/board/internalAnchors.d.ts +17 -0
  28. package/dist/modules/board/internalAnchors.d.ts.map +1 -0
  29. package/dist/modules/board/internalAnchors.js +55 -0
  30. package/dist/modules/board/internalAnchors.js.map +1 -0
  31. package/dist/modules/board/layoutWrites.d.ts +4 -2
  32. package/dist/modules/board/layoutWrites.d.ts.map +1 -1
  33. package/dist/modules/board/layoutWrites.js +24 -9
  34. package/dist/modules/board/layoutWrites.js.map +1 -1
  35. package/dist/modules/board/taskTypeCreationDefaults.d.ts +26 -7
  36. package/dist/modules/board/taskTypeCreationDefaults.d.ts.map +1 -1
  37. package/dist/modules/board/taskTypeCreationDefaults.js +45 -8
  38. package/dist/modules/board/taskTypeCreationDefaults.js.map +1 -1
  39. package/dist/modules/bootstrap/BootstrapService.d.ts +13 -1
  40. package/dist/modules/bootstrap/BootstrapService.d.ts.map +1 -1
  41. package/dist/modules/bootstrap/BootstrapService.js +21 -3
  42. package/dist/modules/bootstrap/BootstrapService.js.map +1 -1
  43. package/dist/modules/execution/PostMergeBoardController.js +4 -4
  44. package/dist/modules/execution/PostMergeBoardController.js.map +1 -1
  45. package/dist/modules/execution/RunAdmission.d.ts.map +1 -1
  46. package/dist/modules/execution/RunAdmission.js +3 -2
  47. package/dist/modules/execution/RunAdmission.js.map +1 -1
  48. package/dist/modules/execution/RunDispatcher.d.ts.map +1 -1
  49. package/dist/modules/execution/RunDispatcher.js +8 -6
  50. package/dist/modules/execution/RunDispatcher.js.map +1 -1
  51. package/dist/modules/execution/RunLifecycleController.d.ts.map +1 -1
  52. package/dist/modules/execution/RunLifecycleController.js +9 -5
  53. package/dist/modules/execution/RunLifecycleController.js.map +1 -1
  54. package/dist/modules/initiative/InitiativeLoopService.d.ts.map +1 -1
  55. package/dist/modules/initiative/InitiativeLoopService.js +16 -2
  56. package/dist/modules/initiative/InitiativeLoopService.js.map +1 -1
  57. package/dist/modules/initiative/InitiativeService.js +1 -1
  58. package/dist/modules/initiative/InitiativeService.js.map +1 -1
  59. package/dist/modules/recurring/RecurringPipelineService.js +1 -1
  60. package/dist/modules/recurring/RecurringPipelineService.js.map +1 -1
  61. package/dist/validation/validateRegistrations.d.ts +40 -5
  62. package/dist/validation/validateRegistrations.d.ts.map +1 -1
  63. package/dist/validation/validateRegistrations.js +177 -28
  64. package/dist/validation/validateRegistrations.js.map +1 -1
  65. package/package.json +11 -11
@@ -1,6 +1,6 @@
1
1
  import type { AddEpicInput, AddFrameInput, AddModuleInput, AddServiceFromRepoInput, AddTaskInput, BlockEditActor, ReparentInput, ResizeBlockInput, UpdateBlockInput } from '@cat-factory/contracts';
2
2
  import type { Block, BlockStatus, Position, PreloadedBlocks } from '@cat-factory/kernel';
3
- import type { BlockRepository, Clock, ExecutionEventPublisher, ExecutionRepository, GitHubRepo, GroupCacheHandle, InitiativeRepository, DocumentRepository, Logger, RepoProjectionRepository, ResolveRunRepoContext, RiskPolicyRepository, ServiceFragmentDefaultsRepository, ServiceRepository, TaskRepository, TaskTypeRegistry, TaskTypeSuppressionRepository, WorkspaceMountRepository, WorkspaceRepository } from '@cat-factory/kernel';
3
+ import type { BlockRepository, Clock, ExecutionEventPublisher, ExecutionRepository, GitHubRepo, GroupCacheHandle, InitiativeRepository, DocumentRepository, Logger, RepoProjectionRepository, ResolveRunRepoContext, RiskPolicyRepository, ServiceFragmentDefaultsRepository, ServiceRepository, TaskRepository, TaskTypeRegistry, TaskTypeSuppressionRepository, PromptFragmentSource, WorkspaceMountRepository, WorkspaceRepository } from '@cat-factory/kernel';
4
4
  import type { IdGenerator } from '@cat-factory/kernel';
5
5
  import type { ReviewFrictionNotificationReader } from './reviewFrictionGuard.js';
6
6
  import type { WorkspaceSettingsReader } from './workspaceSettingsReader.js';
@@ -90,6 +90,12 @@ export interface BoardServiceDependencies {
90
90
  * Absent (tests / an unwired facade) ⇒ nothing is suppressed, today's behaviour.
91
91
  */
92
92
  taskTypeSuppressionRepository?: TaskTypeSuppressionRepository;
93
+ /**
94
+ * Where a new task's per-TASK-TYPE default fragment ids are read from: the app-owned source (this
95
+ * deployment's registry, or the mothership's on a mothership-mode node). Absent ⇒ a new task
96
+ * carries only its explicit/service picks and a registered type's own standing context.
97
+ */
98
+ promptFragmentSource?: PromptFragmentSource;
93
99
  /**
94
100
  * The acting workspace's runtime settings, read by two collaborators:
95
101
  * - the opt-in review-debt friction guard on task creation
@@ -159,6 +165,11 @@ export declare class BoardService {
159
165
  private readonly reviewFrictionGuard;
160
166
  /** The external `/api/v1` board surface (see publicBoardReads.ts). */
161
167
  private readonly publicReads;
168
+ /**
169
+ * The headless `internal` anchor blocks a public-API run hangs off (see internalAnchors.ts).
170
+ * Never board state: no event announces one, and every projection filters it out.
171
+ */
172
+ private readonly internalAnchors;
162
173
  /**
163
174
  * The board's LAYOUT writes — drag a container to a new spot, drag its border to new bounds
164
175
  * (see layoutWrites.ts). Both split their write between a frame's per-board mount override and
@@ -183,25 +194,33 @@ export declare class BoardService {
183
194
  * those a caller reaches for.
184
195
  */
185
196
  private readonly riskPolicySelection;
186
- constructor({ workspaceRepository, blockRepository, executionRepository, idGenerator, clock, repoProjectionRepository, repoProjectionCache, serviceRepository, workspaceMountRepository, serviceFragmentDefaultsRepository, initiativeRepository, documentRepository, taskRepository, executionEventPublisher, taskTypeRegistry, taskTypeSuppressionRepository, workspaceSettings, reviewFrictionNotifications, resolveRunRepoContext, riskPolicyRepository, logger, }: BoardServiceDependencies);
197
+ constructor({ workspaceRepository, blockRepository, executionRepository, idGenerator, clock, repoProjectionRepository, repoProjectionCache, serviceRepository, workspaceMountRepository, serviceFragmentDefaultsRepository, initiativeRepository, documentRepository, taskRepository, executionEventPublisher, taskTypeRegistry, taskTypeSuppressionRepository, promptFragmentSource, workspaceSettings, reviewFrictionNotifications, resolveRunRepoContext, riskPolicyRepository, logger, }: BoardServiceDependencies);
187
198
  /**
188
- * Push a coarse board-changed signal for a successful mutation. `originWorkspaceId` MUST be
199
+ * Push a board-changed signal for a successful mutation. `originWorkspaceId` MUST be
189
200
  * the workspace that physically HOMES the affected block (its `homeWorkspaceId`), not
190
201
  * necessarily the acting workspace: {@link FanOutEventPublisher} resolves the block's service
191
- * and thus every workspace that mounts it by looking the block up under this origin, so
202
+ * (and thus every workspace that mounts it) by looking the block up under this origin, so
192
203
  * passing a mounter's id for a block homed elsewhere would find nothing and collapse the
193
- * fan-out to that one board. Naming a block lets the change reach every mount; pass `null` for
204
+ * fan-out to that one board. Naming a block lets the change reach every mount; name none for
194
205
  * a signal that should reach the origin workspace only (e.g. a per-workspace frame-layout
195
206
  * move). Best-effort: swallow any failure so a missed push never fails the already-persisted
196
- * mutation the client reconciles by re-fetching its snapshot.
207
+ * mutation, since the client reconciles by re-fetching its snapshot.
197
208
  *
198
- * When `originConnectionId` is given (a user-driven mutation move / reparent / field edit
209
+ * Pass `block` (rather than only `blockId`) when the change is FULLY described by that one
210
+ * block, so subscribers patch it in place instead of re-reading the whole board. That is the
211
+ * difference between a spawned task costing one small payload and costing a snapshot on every
212
+ * open board. Withhold it for a structural change whose new shape a single block cannot state:
213
+ * a removal or a reparent moves a block BETWEEN parents, and a cascade touches rows the event
214
+ * never names. A frame payload is dropped at the wire by `deliverableBoardBlock`, so naming one
215
+ * here is safe but pointless.
216
+ *
217
+ * When `originConnectionId` is given (a user-driven mutation: move / reparent / field edit,
199
218
  * carrying the acting tab's connection id), the realtime transport SKIPS delivering this
200
219
  * echo back to that connection: its REST response already carried the authoritative result,
201
220
  * so refreshing off its own event would only race an in-flight drag (snapping a block back to
202
221
  * a stale position) or trigger a redundant board-wide re-hydrate on every inspector edit. Every
203
- * OTHER subscriber still receives the coarse signal and refreshes. Engine-driven board changes
204
- * pass no origin id, so they fan out to everyone as before.
222
+ * OTHER subscriber still receives the signal. Engine-driven board changes pass no origin id, so
223
+ * they fan out to everyone as before.
205
224
  */
206
225
  private emitBoardChanged;
207
226
  /**
@@ -291,36 +310,16 @@ export declare class BoardService {
291
310
  * Pass `UNATTRIBUTED_BLOCK_EDITOR` for a caller with no workspace tier (see its doc).
292
311
  */
293
312
  addTask(workspaceId: string, containerId: string, input: AddTaskInput, editor: BlockEditActor, createdBy?: string | null): Promise<Block>;
294
- /**
295
- * Create a HEADLESS internal task — a top-level, `internal: true` block used purely to anchor
296
- * a public-API run (an external "initiative breakdown"). It is EXCLUDED from every board
297
- * projection (see the snapshot/board reads), so it never renders in the UI; deliberately does
298
- * NOT emit a `block-added` event (nothing should flash onto a live board). Returns the block so
299
- * the caller can start an execution on it. The engine writes status onto it like any block.
300
- */
313
+ /** Public-API: create the anchor block a public-API run hangs off. */
301
314
  createInternalTask(workspaceId: string, input: {
302
315
  title: string;
303
316
  description: string;
304
317
  }): Promise<Block>;
305
- /**
306
- * Fetch a HEADLESS internal anchor block by id, or null when no block with that id exists in
307
- * the workspace OR it is not `internal`. The public-API job reads use this to confine an
308
- * external key to the runs IT created (an `internal` block) — never an arbitrary board
309
- * execution that merely shares the key's workspace. See PublicApiController.
310
- */
318
+ /** Public-API: an anchor by id, or null when the block is absent or not `internal`. */
311
319
  getInternalTask(workspaceId: string, blockId: string): Promise<Block | null>;
312
- /**
313
- * Delete a HEADLESS internal anchor block. Used by the public API to roll back the anchor when
314
- * the run it was created for fails to start, so a failed dispatch never leaves an orphan
315
- * `internal` block behind (it renders nowhere and is invisible to the cap, so it would just
316
- * accumulate). A headless anchor has no children/service subtree, so a direct delete is enough.
317
- */
320
+ /** Public-API: roll an anchor back when the run it was created for fails to start. */
318
321
  deleteInternalTask(workspaceId: string, blockId: string): Promise<void>;
319
- /**
320
- * How many of the workspace's headless internal "initiative" runs are still in flight — the
321
- * concurrency backstop the public API checks before starting another, so a single (possibly
322
- * leaked) key can't spin up unbounded LLM runs. A SQL `COUNT`, not a load-and-count.
323
- */
322
+ /** Public-API: how many anchored runs are in flight — the concurrency backstop. */
324
323
  countActiveInternalTasks(workspaceId: string): Promise<number>;
325
324
  /** Public-API: the workspace's board services (visible service frames). */
326
325
  listServices(workspaceId: string): Promise<Block[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"BoardService.d.ts","sourceRoot":"","sources":["../../../src/modules/board/BoardService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BoardService.d.ts","sourceRoot":"","sources":["../../../src/modules/board/BoardService.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ import { pruneDanglingEdges, reclaimDoomedEntities } from './removal-cascade.js'
7
7
  import { canReparent, descendantIds, gridSlot, serviceOf, tasksOf, unfinishedTasksUnder, wouldCreateCycle, } from './board.logic.js';
8
8
  import { ReviewFrictionGuard } from './reviewFrictionGuard.js';
9
9
  import { resolveNewServiceFrameDefaults } from './newServiceFrameDefaults.js';
10
+ import { createInternalAnchors } from './internalAnchors.js';
10
11
  import { PublicBoardReads } from './publicBoardReads.js';
11
12
  import { buildReviewDescription, resolveReviewTaskTarget } from './reviewTaskTarget.js';
12
13
  import { createBlockPatchNarrowing } from './blockPatchNarrowing.js';
@@ -40,6 +41,11 @@ export class BoardService {
40
41
  reviewFrictionGuard;
41
42
  /** The external `/api/v1` board surface (see publicBoardReads.ts). */
42
43
  publicReads;
44
+ /**
45
+ * The headless `internal` anchor blocks a public-API run hangs off (see internalAnchors.ts).
46
+ * Never board state: no event announces one, and every projection filters it out.
47
+ */
48
+ internalAnchors;
43
49
  /**
44
50
  * The board's LAYOUT writes — drag a container to a new spot, drag its border to new bounds
45
51
  * (see layoutWrites.ts). Both split their write between a frame's per-board mount override and
@@ -64,7 +70,7 @@ export class BoardService {
64
70
  * those a caller reaches for.
65
71
  */
66
72
  riskPolicySelection;
67
- constructor({ workspaceRepository, blockRepository, executionRepository, idGenerator, clock, repoProjectionRepository, repoProjectionCache, serviceRepository, workspaceMountRepository, serviceFragmentDefaultsRepository, initiativeRepository, documentRepository, taskRepository, executionEventPublisher, taskTypeRegistry, taskTypeSuppressionRepository, workspaceSettings, reviewFrictionNotifications, resolveRunRepoContext, riskPolicyRepository, logger, }) {
73
+ constructor({ workspaceRepository, blockRepository, executionRepository, idGenerator, clock, repoProjectionRepository, repoProjectionCache, serviceRepository, workspaceMountRepository, serviceFragmentDefaultsRepository, initiativeRepository, documentRepository, taskRepository, executionEventPublisher, taskTypeRegistry, taskTypeSuppressionRepository, promptFragmentSource, workspaceSettings, reviewFrictionNotifications, resolveRunRepoContext, riskPolicyRepository, logger, }) {
68
74
  this.workspaceRepository = workspaceRepository;
69
75
  this.blockRepository = blockRepository;
70
76
  this.executionRepository = executionRepository;
@@ -94,6 +100,7 @@ export class BoardService {
94
100
  });
95
101
  this.taskTypeDefaults = createTaskTypeCreationDefaults({
96
102
  taskTypeRegistry,
103
+ promptFragmentSource,
97
104
  taskTypeSuppressionRepository,
98
105
  logger: this.log,
99
106
  });
@@ -115,36 +122,49 @@ export class BoardService {
115
122
  resolveBlock: (workspaceId, id) => this.resolveBlock(workspaceId, id),
116
123
  frameMount: (workspaceId, block) => this.frameMount(workspaceId, block),
117
124
  projectForWorkspace: (workspaceId, block) => this.projectForWorkspace(workspaceId, block),
118
- emitBoardChanged: (originWorkspaceId, reason, blockId, originConnectionId) => this.emitBoardChanged(originWorkspaceId, reason, blockId, originConnectionId),
125
+ emitBoardChanged: (originWorkspaceId, change) => this.emitBoardChanged(originWorkspaceId, change),
119
126
  });
120
127
  this.publicReads = new PublicBoardReads({
121
128
  blockRepository,
122
129
  requireWorkspace: (workspaceId) => this.requireWorkspace(workspaceId),
123
130
  addTask: (workspaceId, containerId, input, editor, createdBy) => this.addTask(workspaceId, containerId, input, editor, createdBy),
124
131
  });
132
+ this.internalAnchors = createInternalAnchors({
133
+ blockRepository,
134
+ idGenerator,
135
+ requireWorkspace: (workspaceId) => this.requireWorkspace(workspaceId),
136
+ });
125
137
  }
126
138
  /**
127
- * Push a coarse board-changed signal for a successful mutation. `originWorkspaceId` MUST be
139
+ * Push a board-changed signal for a successful mutation. `originWorkspaceId` MUST be
128
140
  * the workspace that physically HOMES the affected block (its `homeWorkspaceId`), not
129
141
  * necessarily the acting workspace: {@link FanOutEventPublisher} resolves the block's service
130
- * and thus every workspace that mounts it by looking the block up under this origin, so
142
+ * (and thus every workspace that mounts it) by looking the block up under this origin, so
131
143
  * passing a mounter's id for a block homed elsewhere would find nothing and collapse the
132
- * fan-out to that one board. Naming a block lets the change reach every mount; pass `null` for
144
+ * fan-out to that one board. Naming a block lets the change reach every mount; name none for
133
145
  * a signal that should reach the origin workspace only (e.g. a per-workspace frame-layout
134
146
  * move). Best-effort: swallow any failure so a missed push never fails the already-persisted
135
- * mutation the client reconciles by re-fetching its snapshot.
147
+ * mutation, since the client reconciles by re-fetching its snapshot.
136
148
  *
137
- * When `originConnectionId` is given (a user-driven mutation move / reparent / field edit
149
+ * Pass `block` (rather than only `blockId`) when the change is FULLY described by that one
150
+ * block, so subscribers patch it in place instead of re-reading the whole board. That is the
151
+ * difference between a spawned task costing one small payload and costing a snapshot on every
152
+ * open board. Withhold it for a structural change whose new shape a single block cannot state:
153
+ * a removal or a reparent moves a block BETWEEN parents, and a cascade touches rows the event
154
+ * never names. A frame payload is dropped at the wire by `deliverableBoardBlock`, so naming one
155
+ * here is safe but pointless.
156
+ *
157
+ * When `originConnectionId` is given (a user-driven mutation: move / reparent / field edit,
138
158
  * carrying the acting tab's connection id), the realtime transport SKIPS delivering this
139
159
  * echo back to that connection: its REST response already carried the authoritative result,
140
160
  * so refreshing off its own event would only race an in-flight drag (snapping a block back to
141
161
  * a stale position) or trigger a redundant board-wide re-hydrate on every inspector edit. Every
142
- * OTHER subscriber still receives the coarse signal and refreshes. Engine-driven board changes
143
- * pass no origin id, so they fan out to everyone as before.
162
+ * OTHER subscriber still receives the signal. Engine-driven board changes pass no origin id, so
163
+ * they fan out to everyone as before.
144
164
  */
145
- async emitBoardChanged(originWorkspaceId, reason, blockId, originConnectionId) {
165
+ async emitBoardChanged(originWorkspaceId, change) {
146
166
  try {
147
- await this.events?.boardChanged(originWorkspaceId, reason, blockId, originConnectionId);
167
+ await this.events?.boardChanged(originWorkspaceId, change);
148
168
  }
149
169
  catch {
150
170
  // best-effort; the REST response already carried the mutation
@@ -272,7 +292,8 @@ export class BoardService {
272
292
  };
273
293
  const serviceId = await this.registerService(workspaceId, block);
274
294
  await this.blockRepository.insert(workspaceId, block, serviceId);
275
- await this.emitBoardChanged(workspaceId, 'block-added', block.id);
295
+ // A service FRAME, so no payload: its position is the per-board mount, not this row.
296
+ await this.emitBoardChanged(workspaceId, { reason: 'block-added', blockId: block.id });
276
297
  return block;
277
298
  }
278
299
  /**
@@ -363,7 +384,8 @@ export class BoardService {
363
384
  directory: directory ?? null,
364
385
  });
365
386
  await this.blockRepository.insert(workspaceId, block, serviceId);
366
- await this.emitBoardChanged(workspaceId, 'block-added', block.id);
387
+ // A service FRAME, so no payload (see `addBlock`).
388
+ await this.emitBoardChanged(workspaceId, { reason: 'block-added', blockId: block.id });
367
389
  return block;
368
390
  }
369
391
  /**
@@ -413,8 +435,12 @@ export class BoardService {
413
435
  createdAt: this.clock.now(),
414
436
  };
415
437
  await this.workspaceMountRepository.upsert(mount);
416
- // Fan out from the frame's HOME so every board mounting the shared service refreshes.
417
- await this.emitBoardChanged(home.workspaceId, 'block-added', home.block.id);
438
+ // Fan out from the frame's HOME so every board mounting the shared service refreshes. A
439
+ // FRAME, and each target board reads its own mount, so there is no payload to carry.
440
+ await this.emitBoardChanged(home.workspaceId, {
441
+ reason: 'block-added',
442
+ blockId: home.block.id,
443
+ });
418
444
  }
419
445
  // The frame block is the one homed on ANOTHER board, carrying that board's coordinates —
420
446
  // return it placed where THIS board just mounted it, or the SPA drops the imported service
@@ -512,13 +538,21 @@ export class BoardService {
512
538
  // `pr-reviewer` knows WHICH PR to review from its prompt.
513
539
  block.description = buildReviewDescription(taskType, block.taskTypeFields, block.description);
514
540
  // The best-practice fragments the task OWNS from creation: the create form's picks or the
515
- // service's standing standards, unioned with the type's defaults and a registered operation's
516
- // standing context. Derived by `taskTypeCreationDefaults.ts`, which owns the precedence rules
517
- // and STATES a custom type this process does not register.
518
- const fragmentIds = this.taskTypeDefaults.fragmentIdsFor({
541
+ // service's standing standards, unioned with the type's defaults, a registered operation's
542
+ // standing context, and whichever of its CONDITIONAL entries hold against the values collected
543
+ // above. Derived by `taskTypeCreationDefaults.ts`, which owns the precedence rules and STATES a
544
+ // custom type this process does not register.
545
+ //
546
+ // `block.taskTypeFields` and not `input.taskTypeFields`: the fields have been validated and
547
+ // SANITIZED by now, so a value for a field hidden by its own `showWhen` is already gone, and a
548
+ // conditional rule keyed on one must reduce to false to match what the row actually freezes.
549
+ const fragmentIds = await this.taskTypeDefaults.fragmentIdsFor({
519
550
  taskType,
520
551
  explicit: input.fragmentIds,
521
552
  serviceFragmentIds: service?.serviceFragmentIds,
553
+ // `?? undefined` because the row spells "no per-case values" as null while the reduction
554
+ // takes an absent bag. Both mean the same thing to it: no conditional entry holds.
555
+ fields: block.taskTypeFields ?? undefined,
522
556
  });
523
557
  if (fragmentIds.length) {
524
558
  block.fragmentIds = fragmentIds;
@@ -558,66 +592,30 @@ export class BoardService {
558
592
  block.technical = input.technical;
559
593
  await this.blockRepository.insert(homeWorkspaceId, block, await this.serviceForContainer(blocks, container));
560
594
  // Origin = the block's HOME (the mounted service's home when added to a shared board), so
561
- // the fan-out reaches every workspace mounting the service, not just the acting one.
562
- await this.emitBoardChanged(homeWorkspaceId, 'block-added', block.id);
595
+ // the fan-out reaches every workspace mounting the service, not just the acting one. A new
596
+ // task is fully described by itself, so it rides along and every board patches it in place
597
+ // rather than re-reading a snapshot: this is the event an initiative loop fires per spawn.
598
+ await this.emitBoardChanged(homeWorkspaceId, { reason: 'block-added', block });
563
599
  return block;
564
600
  }
565
- /**
566
- * Create a HEADLESS internal task — a top-level, `internal: true` block used purely to anchor
567
- * a public-API run (an external "initiative breakdown"). It is EXCLUDED from every board
568
- * projection (see the snapshot/board reads), so it never renders in the UI; deliberately does
569
- * NOT emit a `block-added` event (nothing should flash onto a live board). Returns the block so
570
- * the caller can start an execution on it. The engine writes status onto it like any block.
571
- */
572
- async createInternalTask(workspaceId, input) {
573
- await this.requireWorkspace(workspaceId);
574
- const block = {
575
- id: this.idGenerator.next('task'),
576
- title: input.title.trim() || 'Initiative',
577
- // `type` is the service/repo CLASSIFICATION (frontend/service/library/…), orthogonal to the
578
- // `level` hierarchy; there is no task-specific BlockType. This anchor is a standalone,
579
- // never-rendered, repo-less `level:'task'` block, so `type` is irrelevant to it — 'service'
580
- // is just the neutral default (a normal task inherits its parent service's type instead).
581
- type: 'service',
582
- description: input.description ?? '',
583
- position: { x: 0, y: 0 },
584
- status: 'planned',
585
- progress: 0,
586
- dependsOn: [],
587
- executionId: null,
588
- level: 'task',
589
- parentId: null,
590
- internal: true,
591
- };
592
- await this.blockRepository.insert(workspaceId, block);
593
- return block;
601
+ // --- Headless internal anchors ---------------------------------------------
602
+ // Delegated to {@link createInternalAnchors}: the top-level `internal: true` blocks that anchor
603
+ // a public-API run and render on no board, ever. See that file for why the four belong together.
604
+ /** Public-API: create the anchor block a public-API run hangs off. */
605
+ createInternalTask(workspaceId, input) {
606
+ return this.internalAnchors.createInternalTask(workspaceId, input);
594
607
  }
595
- /**
596
- * Fetch a HEADLESS internal anchor block by id, or null when no block with that id exists in
597
- * the workspace OR it is not `internal`. The public-API job reads use this to confine an
598
- * external key to the runs IT created (an `internal` block) — never an arbitrary board
599
- * execution that merely shares the key's workspace. See PublicApiController.
600
- */
601
- async getInternalTask(workspaceId, blockId) {
602
- const block = await this.blockRepository.get(workspaceId, blockId);
603
- return block?.internal ? block : null;
608
+ /** Public-API: an anchor by id, or null when the block is absent or not `internal`. */
609
+ getInternalTask(workspaceId, blockId) {
610
+ return this.internalAnchors.getInternalTask(workspaceId, blockId);
604
611
  }
605
- /**
606
- * Delete a HEADLESS internal anchor block. Used by the public API to roll back the anchor when
607
- * the run it was created for fails to start, so a failed dispatch never leaves an orphan
608
- * `internal` block behind (it renders nowhere and is invisible to the cap, so it would just
609
- * accumulate). A headless anchor has no children/service subtree, so a direct delete is enough.
610
- */
611
- async deleteInternalTask(workspaceId, blockId) {
612
- await this.blockRepository.deleteMany(workspaceId, [blockId]);
612
+ /** Public-API: roll an anchor back when the run it was created for fails to start. */
613
+ deleteInternalTask(workspaceId, blockId) {
614
+ return this.internalAnchors.deleteInternalTask(workspaceId, blockId);
613
615
  }
614
- /**
615
- * How many of the workspace's headless internal "initiative" runs are still in flight — the
616
- * concurrency backstop the public API checks before starting another, so a single (possibly
617
- * leaked) key can't spin up unbounded LLM runs. A SQL `COUNT`, not a load-and-count.
618
- */
616
+ /** Public-API: how many anchored runs are in flight — the concurrency backstop. */
619
617
  countActiveInternalTasks(workspaceId) {
620
- return this.blockRepository.countActiveInternal(workspaceId);
618
+ return this.internalAnchors.countActiveInternalTasks(workspaceId);
621
619
  }
622
620
  // --- Public-API board reads/writes -----------------------------------------
623
621
  // Delegated to {@link PublicBoardReads}: the external `/api/v1` surface is its own cohesive
@@ -685,7 +683,8 @@ export class BoardService {
685
683
  };
686
684
  await this.blockRepository.insert(homeWorkspaceId, block, containerServiceId);
687
685
  // Origin = the block's HOME so a module added to a mounted service fans out to all mounts.
688
- await this.emitBoardChanged(homeWorkspaceId, 'block-added', block.id);
686
+ // A module is a sub-frame with no mount of its own, so its payload is correct everywhere.
687
+ await this.emitBoardChanged(homeWorkspaceId, { reason: 'block-added', block });
689
688
  created.push(block);
690
689
  n += 1;
691
690
  }
@@ -723,7 +722,7 @@ export class BoardService {
723
722
  parentId,
724
723
  };
725
724
  await this.blockRepository.insert(workspaceId, block);
726
- await this.emitBoardChanged(workspaceId, 'block-added', block.id);
725
+ await this.emitBoardChanged(workspaceId, { reason: 'block-added', block });
727
726
  return block;
728
727
  }
729
728
  /**
@@ -745,9 +744,12 @@ export class BoardService {
745
744
  }
746
745
  }
747
746
  await this.blockRepository.update(homeWorkspaceId, taskId, { epicId });
747
+ // Re-read BEFORE emitting so the event carries the task it just changed: membership is a
748
+ // field ON the task, so the one block states the whole change and subscribers patch it.
748
749
  // Origin = the task's HOME so the fan-out resolves the (possibly mounted) service's boards.
749
- await this.emitBoardChanged(homeWorkspaceId, 'epic-assigned', taskId);
750
- return assertFound(await this.blockRepository.get(homeWorkspaceId, taskId), 'Block', taskId);
750
+ const updated = assertFound(await this.blockRepository.get(homeWorkspaceId, taskId), 'Block', taskId);
751
+ await this.emitBoardChanged(homeWorkspaceId, { reason: 'epic-assigned', block: updated });
752
+ return updated;
751
753
  }
752
754
  /** Move a block to a new spot on the board (a frame's position is its per-board override). */
753
755
  async moveBlock(workspaceId, id, position, originConnectionId) {
@@ -796,17 +798,24 @@ export class BoardService {
796
798
  // `customTaskTypeFields` (the half that may be patched) and the row stores the whole
797
799
  // `taskTypeFields`, so this is where the request type becomes the repository's.
798
800
  await this.blockRepository.update(homeWorkspaceId, id, narrow.customTaskTypeFields(effective, block));
801
+ const updated = assertFound(await this.blockRepository.get(homeWorkspaceId, id), 'Block', id);
799
802
  // Origin = the block's HOME so editing a shared block fans out to every board mounting it.
800
- // Forward the acting tab's connection id so the realtime transport SKIPS echoing this coarse
801
- // signal back to it: the REST response already carried the authoritative block (the SPA
802
- // upserts it), so a self-echo would only trigger a redundant board-wide re-hydrate the same
803
- // "don't refresh off your own mutation" contract move/reparent already follow. Every OTHER
804
- // subscriber still receives the signal and refreshes.
805
- await this.emitBoardChanged(homeWorkspaceId, 'block-updated', id, originConnectionId);
806
- // A frame's position/size come from THIS board's mount, not the row we just re-read — so a
803
+ // Forward the acting tab's connection id so the realtime transport SKIPS echoing this back to
804
+ // it: the REST response already carried the authoritative block (the SPA upserts it), so a
805
+ // self-echo would only trigger a redundant board-wide re-hydrate, the same "don't refresh off
806
+ // your own mutation" contract move/reparent already follow. Every OTHER subscriber receives
807
+ // the change, carrying the edited block. The UNPROJECTED row is what rides: the projection
808
+ // below is for THIS board, and a fan-out reaches boards with different mounts. That only ever
809
+ // matters for a frame, whose payload `deliverableBoardBlock` drops at the wire anyway.
810
+ await this.emitBoardChanged(homeWorkspaceId, {
811
+ reason: 'block-updated',
812
+ block: updated,
813
+ originConnectionId,
814
+ });
815
+ // A frame's position/size come from THIS board's mount, not the row we just re-read, so a
807
816
  // frame edit (rename, threshold, and above all a RESIZE) must not hand the SPA the block's
808
817
  // own, never-updated coordinates to upsert.
809
- return this.projectForWorkspace(workspaceId, assertFound(await this.blockRepository.get(homeWorkspaceId, id), 'Block', id));
818
+ return this.projectForWorkspace(workspaceId, updated);
810
819
  }
811
820
  /** Move a block into a new container at a new local position. */
812
821
  async reparent(workspaceId, id, input, originConnectionId) {
@@ -844,8 +853,14 @@ export class BoardService {
844
853
  const destService = await this.serviceForContainer(destBlocks, parent);
845
854
  await this.blockRepository.setService(blockHome, [...descendantIds(destBlocks, id)], destService ?? null);
846
855
  }
847
- // Origin = the block's HOME so the re-stamped subtree fans out to every mounting board.
848
- await this.emitBoardChanged(blockHome, 'block-reparented', id, originConnectionId);
856
+ // Origin = the block's HOME so the re-stamped subtree fans out to every mounting board. No
857
+ // payload: a reparent moves the whole SUBTREE between parents, and the moved block alone
858
+ // cannot state what its descendants' service stamps became.
859
+ await this.emitBoardChanged(blockHome, {
860
+ reason: 'block-reparented',
861
+ blockId: id,
862
+ originConnectionId,
863
+ });
849
864
  return assertFound(await this.blockRepository.get(blockHome, id), 'Block', id);
850
865
  }
851
866
  // Cross-home: the block and its new parent belong to two services homed in different
@@ -886,10 +901,14 @@ export class BoardService {
886
901
  // service's mounts (and that board). Source side: the block is gone from its old service, so
887
902
  // the block→service join can't resolve it anymore — notify the captured source boards
888
903
  // directly (origin-only) so they refresh the subtree away.
889
- await this.emitBoardChanged(parentHome, 'block-reparented', id, originConnectionId);
904
+ await this.emitBoardChanged(parentHome, {
905
+ reason: 'block-reparented',
906
+ blockId: id,
907
+ originConnectionId,
908
+ });
890
909
  for (const ws of sourceFanout) {
891
910
  if (ws !== parentHome) {
892
- await this.emitBoardChanged(ws, 'block-reparented', null, originConnectionId);
911
+ await this.emitBoardChanged(ws, { reason: 'block-reparented', originConnectionId });
893
912
  }
894
913
  }
895
914
  return assertFound(await this.blockRepository.get(parentHome, id), 'Block', id);
@@ -956,9 +975,10 @@ export class BoardService {
956
975
  await this.blockRepository.deleteMany(homeWorkspaceId, [...doomed]);
957
976
  await pruneDanglingEdges(this.blockRepository, homeWorkspaceId, blocks, doomed);
958
977
  // The block + any shared service are now gone, so fan out per captured target (blockId is
959
- // unresolvable post-delete) every board that showed the block refreshes it away.
978
+ // unresolvable post-delete): every board that showed the block refreshes it away. There is
979
+ // nothing to carry, and a delete CASCADES, so the refresh is the point.
960
980
  for (const ws of fanoutTargets) {
961
- await this.emitBoardChanged(ws, 'block-removed', null);
981
+ await this.emitBoardChanged(ws, { reason: 'block-removed' });
962
982
  }
963
983
  }
964
984
  /**
@@ -983,7 +1003,11 @@ export class BoardService {
983
1003
  }
984
1004
  await this.blockRepository.update(homeWorkspaceId, id, { archived });
985
1005
  // Origin = the block's HOME so archiving a shared service fans out to every board mounting it.
986
- await this.emitBoardChanged(homeWorkspaceId, archived ? 'block-archived' : 'block-restored', id);
1006
+ // Always a FRAME (asserted above) and archiving hides its whole subtree, so no payload.
1007
+ await this.emitBoardChanged(homeWorkspaceId, {
1008
+ reason: archived ? 'block-archived' : 'block-restored',
1009
+ blockId: id,
1010
+ });
987
1011
  // Always a frame (asserted above), so it owes the caller this board's layout override.
988
1012
  return this.projectForWorkspace(workspaceId, assertFound(await this.blockRepository.get(homeWorkspaceId, id), 'Block', id));
989
1013
  }
@@ -1028,8 +1052,11 @@ export class BoardService {
1028
1052
  }
1029
1053
  }
1030
1054
  // Origin = the target's HOME so toggling an edge on a shared task fans out to all mounts.
1031
- await this.emitBoardChanged(homeWorkspaceId, 'dependency-toggled', targetId);
1032
- return assertFound(await this.blockRepository.get(homeWorkspaceId, targetId), 'Block', targetId);
1055
+ // Re-read first so the event carries the target: `dependsOn` lives on it, so one block
1056
+ // states the whole change (the SOURCE block is untouched).
1057
+ const updated = assertFound(await this.blockRepository.get(homeWorkspaceId, targetId), 'Block', targetId);
1058
+ await this.emitBoardChanged(homeWorkspaceId, { reason: 'dependency-toggled', block: updated });
1059
+ return updated;
1033
1060
  }
1034
1061
  }
1035
1062
  /**