@outbuild-company/schedule-core 1.0.0 → 1.1.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.
package/dist/index.d.cts CHANGED
@@ -5,10 +5,8 @@
5
5
  * This file is the single seam between all components. All scheduler code
6
6
  * depends ONLY on these types — never on the DHTMLX gantt object directly.
7
7
  */
8
- type ActivityId$2 = string;
8
+ type ActivityId$1 = string;
9
9
  type LinkId$1 = string;
10
- type CalendarId$2 = string;
11
-
12
10
  /** Value constants for link types. Matches `gantt.config.links`. */
13
11
  declare const LINK_TYPE: {
14
12
  readonly FINISH_TO_START: "0";
@@ -16,172 +14,10 @@ declare const LINK_TYPE: {
16
14
  readonly FINISH_TO_FINISH: "2";
17
15
  readonly START_TO_FINISH: "3";
18
16
  };
19
- /**
20
- * RAW DHTMLX row as the scheduler engine and `ScheduleState` see it:
21
- * snake_case fields, `parent` with the numeric-0 root sentinel,
22
- * `$source`/`$target` link id arrays, `duration` in HOURS, ids
23
- * `string | number`. Dates are real Date objects (not ISO strings);
24
- * serialization for JSON fixtures happens in the recording layer.
25
- * Sibling shapes: persisted `Activity` (`src/types.ts`) and the
26
- * pipelines' camelCase `ActivitySnapshot` (`src/columns/types.ts`) —
27
- * see the `Activity` docblock for the full map.
28
- */
29
- interface EngineActivitySnapshot {
30
- id: ActivityId$2;
31
- start_date: Date;
32
- end_date: Date;
33
- duration: number;
34
- type: ActivityType;
35
- parent: ActivityId$2 | 0;
36
- constraint_type: ConstraintType | null;
37
- constraint_date: Date | null;
38
- progress: number;
39
- auto_scheduling: boolean;
40
- calendar_id: CalendarId$2 | null;
41
- /** Outgoing link ids (this activity is the link source) */
42
- $source: LinkId$1[];
43
- /** Incoming link ids (this activity is the link target) */
44
- $target: LinkId$1[];
45
- /** Mirrors `Activity.is_critical` (`CriticalFlag`): boolean fresh from the
46
- * backend, `'Si'`/`'No'` after the critical-path pass. */
47
- is_critical?: boolean | 'Si' | 'No';
48
- dragged?: boolean;
49
- /**
50
- * Display/domain fields carried at runtime via the activityToSnapshot `...a`
51
- * spread; declared so state-ports reads them typed instead of casting.
52
- */
53
- text?: string;
54
- description?: string;
55
- cost?: number;
56
- used_cost?: number;
57
- real_cost?: number;
58
- hhWorkTime?: number;
59
- real_work?: number;
60
- ponderator?: number;
61
- tasks?: unknown[];
62
- real_constraint_type?: ConstraintType | null;
63
- last_constraint?: ConstraintType | null;
64
- last_constraint_date?: Date | null;
65
- last_start_date?: Date | null;
66
- date_origin?: Date | null;
67
- /**
68
- * Backend DB row id (distinct from `id` which is `unique_id`). Optional
69
- * because activities created in-session have no backend row yet.
70
- */
71
- proplannerId?: number;
72
- /** Sequential display index used as a short human-readable activity label.
73
- * `| undefined` is explicit: rollback before-images assign the prior value,
74
- * which is `undefined` for an activity that had no correlative_id yet. */
75
- correlative_id?: number | undefined;
76
- /**
77
- * Project-scoped unique identifier string, user-visible (e.g. "A-0001").
78
- * Null for activities that have not been assigned one yet.
79
- */
80
- custom_id?: string | null;
81
- /**
82
- * UUID-like correlative assigned by Outbuild. May be string or number
83
- * depending on the backend version; absent on in-session-created activities.
84
- */
85
- unique_correlative_id?: string | number | null;
86
- /**
87
- * Working-hours mirror of `duration` used by the Duration column renderer to
88
- * avoid re-computing hours from days on every render. Stamped by
89
- * `parseFromBackend`, `activityCreationPipeline`, and parent-bounds.
90
- */
91
- for_disable_milestone_duration?: number;
92
- /**
93
- * View-model visibility bit (UI filters); ex `should_be_showed` of the
94
- * DHTMLX task. `visible !== false` = visible; default true.
95
- */
96
- visible?: boolean;
97
- /** Checkbox-selection bit owned by the selection pipeline. */
98
- checked?: boolean;
99
- /** Visible (UI-layer) checkbox state, kept in sync with `checked`. */
100
- visibleChecked?: boolean;
101
- /** Signal to the bridge that `visibleChecked` was set this dispatch. */
102
- mustApplyVisibleChecked?: boolean;
103
- /**
104
- * Pending Schedule Impact Requests freezing this activity (id-only
105
- * reduction; non-empty ⇒ frozen). Carried verbatim from the backend payload.
106
- * Only for dynamic setActivityField writes + arbitrary backend passthrough;
107
- * all known fields are declared above.
108
- */
109
- pendingRequests?: PendingRequest[];
110
- earlyStart?: Date | null;
111
- earlyFinish?: Date | null;
112
- lateStart?: Date | null;
113
- lateFinish?: Date | null;
114
- totalSlack?: number | null;
115
- freeSlack?: number | null;
116
- /** Expected-progress baseline output, written by the expected-progress pass. */
117
- expected_progress?: number;
118
- /** Lookahead membership; the core derives it in promote/demote (R4). */
119
- is_lookahead?: boolean;
120
- /** Client-side "new, unsaved" marker (not persisted as such). */
121
- isNewActivity?: true | null;
122
- /** Descendant new-activity id bookkeeping (R15, temporal). */
123
- newActivitiesArray?: ActivityId$2[];
124
- /** `newActivitiesArray.length > 0` mirror (R15, temporal). */
125
- hasNewActivities?: boolean;
126
- /** Activity modification log carried from the backend. */
127
- activityModifications?: unknown[];
128
- /** Load-derived: the activity fell back to the default calendar. */
129
- assignedDefaultCalendar?: boolean;
130
- /** Backend flag: has persisted children. */
131
- has_childs?: boolean;
132
- /** Backend flag: ponderator set manually (not auto-distributed). */
133
- hasCustomPonderator?: boolean;
134
- /** Backend aggregate: recursive duration sum. */
135
- sumOfDurationRecursively?: number;
136
- /** Backend row ids (distinct from the domain `id`). */
137
- ganttId?: number;
138
- sectorId?: number;
139
- companyId?: number;
140
- /** Subcontract column id + its raw backend object. */
141
- subcontractId?: number | null;
142
- subcontract?: unknown;
143
- /** Responsibility / tag columns (arrays of backend rows). */
144
- responsables?: unknown[];
145
- tags?: unknown[];
146
- /** Active baseline points overlaid at load. */
147
- baseline_points?: BaselinePoint[];
148
- /** Backend timestamps. */
149
- createdAt?: string;
150
- updatedAt?: string;
151
- old_progress_registered?: number;
152
- old_duration_registered?: number;
153
- old_cost_registered?: number;
154
- old_used_cost_registered?: number;
155
- old_real_cost_registered?: number;
156
- old_hhWorkTime_registered?: number;
157
- /** Mirror of the constraint before the last change (constraint cluster). */
158
- constraint_type_old?: ConstraintType | null;
159
- /** `type === 'milestone'` cache flipped by the duration pipeline. */
160
- is_milestone?: boolean;
161
- /** DHTMLX markers consumed by the bridge / render layer. */
162
- $keep_constraints?: boolean;
163
- $rendered_type?: ActivityType;
164
- $no_start?: boolean;
165
- $no_end?: boolean;
166
- status?: 'Waiting' | 'Doing' | 'Done';
167
- progressSolidColor?: string;
168
- color?: string;
169
- /** Flags a recursive complete/uncomplete from the action-button flow. */
170
- progressChangedByActionButton?: boolean;
171
- custom_predecessors?: string;
172
- /** Backend typo preserved (single 'c'). */
173
- custom_sucessors?: string;
174
- start_base?: Date;
175
- end_base?: Date;
176
- duration_base?: number;
177
- cost_base?: number;
178
- work_base?: number;
179
- expected_progress_base?: number;
180
- }
181
17
  interface LinkSnapshot {
182
18
  id: LinkId$1;
183
- source: ActivityId$2;
184
- target: ActivityId$2;
19
+ source: ActivityId$1;
20
+ target: ActivityId$1;
185
21
  type: LinkType;
186
22
  lag: number;
187
23
  /**
@@ -208,6 +44,11 @@ interface LinkSnapshot {
208
44
  /** BE row id (distinct from the schedule-level `id`). */
209
45
  proplannerId?: number;
210
46
  }
47
+ /**
48
+ * Gantt-wide flags that influence scheduling decisions. Captured at the
49
+ * boundary of every scheduling run.
50
+ */
51
+ type MutableLinkField = 'lag' | 'type';
211
52
 
212
53
  /**
213
54
  * Constraint Rules — single source of truth.
@@ -259,21 +100,13 @@ declare const CONSTRAINT_TYPE: {
259
100
  * DHTMLX convention) and camelCase for everything else, per Q14 in
260
101
  * SCHEDULE_CORE_API.md.
261
102
  */
262
- type ActivityId$1 = string;
103
+ type ActivityId = string;
263
104
  type LinkId = string;
264
- type CalendarId$1 = string;
105
+ type CalendarId = string;
265
106
  type ActivityType = 'project' | 'task' | 'milestone';
266
107
 
267
108
  /** DHTMLX link kinds: 0 = FS, 1 = SS, 2 = FF, 3 = SF. */
268
109
  type LinkType = '0' | '1' | '2' | '3';
269
- /**
270
- * Critical-path output flag. Carries two historical shapes: `parseFromBackend`
271
- * stores a boolean, and the critical-path pass (`initial-passes.ts`) overwrites
272
- * it with the DHTMLX string `'Si'`/`'No'`. Both are observed at runtime (the
273
- * CP / paste tests assert against `'Si'`/`'No'`; `parseFromBackend` against
274
- * boolean), so the type unions all three rather than lying with a bare boolean.
275
- */
276
- type CriticalFlag = boolean | 'Si' | 'No';
277
110
  /** Direction for closest-work-time snapping. */
278
111
  type WorkTimeDirection = 'future' | 'past';
279
112
  declare const WORK_TIME_DIRECTION: {
@@ -349,11 +182,8 @@ interface BaselinePoint {
349
182
  /**
350
183
  * Pure-domain activity model produced by `parseFromBackend`. Snake_case
351
184
  * matches the backend convention. No index signature — every field is
352
- * explicit. New backend fields must be added here (or to
353
- * `ACTIVITY_PASSTHROUGH_FIELDS` in `parseFromBackend.ts` and here).
354
- *
355
- * Companion type for runtime mutations: see `ActivityRuntime` below,
356
- * which extends this with `DhtmlxHeritageFields`.
185
+ * explicit. New backend fields must be added here and preserved by
186
+ * `normalize-activity.ts`.
357
187
  */
358
188
  /**
359
189
  * A pending SIR freezing an activity, reduced to the only field the core
@@ -363,120 +193,101 @@ interface BaselinePoint {
363
193
  interface PendingRequest {
364
194
  id: string;
365
195
  }
366
- /**
367
- * PUBLIC persisted domain model — what `core.getActivityView()` returns and
368
- * what the backend payload parses into. Fields are snake_case (backend +
369
- * DHTMLX convention); `duration` is in DAYS at this boundary.
370
- *
371
- * The package has three activity shapes — one per layer:
372
- * - `Activity` (this): public, persisted, snake_case.
373
- * - `ActivitySnapshot` (`src/columns/types.ts`): camelCase + derived
374
- * fields (hasChildren, isMilestone…); what column pipelines read.
375
- * Built per-read by `state-ports.ts`; never persisted.
376
- * - `EngineActivitySnapshot` (`src/autoscheduler/types.ts`): raw DHTMLX
377
- * row (snake_case + `parent`/`$source`/`$target`, hours-based
378
- * duration); what `ScheduleState` stores and the scheduler engine
379
- * consumes. Translation Activity ↔ engine: `src/dispatch/conversion.ts`.
380
- */
381
- interface Activity {
382
- id: ActivityId$1;
383
- /** Parent's `id`, or `'0'` when the activity is a root. */
384
- parent: ActivityId$1 | '0';
385
- text: string;
196
+ declare const STATUS: {
197
+ readonly DONE: "Done";
198
+ readonly OVERDUE: "Overdue";
199
+ readonly ADVANCEMENT: "Advancement";
200
+ readonly WAITING: "Waiting";
201
+ readonly DOING: "Doing";
202
+ };
203
+ type ActivityStatus = (typeof STATUS)[keyof typeof STATUS];
204
+ interface CriticalPathResult {
205
+ earlyStart: Date | null;
206
+ earlyFinish: Date | null;
207
+ lateStart: Date | null;
208
+ lateFinish: Date | null;
209
+ totalSlackHours: number | null;
210
+ }
211
+ interface ActivityBaselineSnapshot {
212
+ startDate: Date | null;
213
+ endDate: Date | null;
214
+ durationDays: number;
215
+ cost: number;
216
+ workHours: number;
217
+ }
218
+ interface CoreBaselinePoint {
219
+ startDate: Date | null;
220
+ endDate: Date | null;
221
+ durationDays: number;
222
+ cost: number;
223
+ workHours: number;
224
+ versionId: number | null;
225
+ isActiveVersion: boolean;
226
+ baseCalendarId: CalendarId | null;
227
+ hoursPerDay: number | null;
228
+ hoursPerWeek: number | null;
229
+ }
230
+ interface CoreActivity {
231
+ id: ActivityId;
232
+ proplannerId: number | null;
233
+ parentId: ActivityId | null;
234
+ name: string;
386
235
  description: string;
387
236
  type: ActivityType;
388
- start_date: Date;
389
- end_date: Date;
390
- duration: number;
391
- constraint_type: ConstraintType | null;
392
- constraint_date: Date | null;
393
- auto_scheduling: boolean;
394
- calendar_id: CalendarId$1 | null;
395
- /**
396
- * True when the activity had no valid calendar of its own and inherited the
397
- * project default at load (its backend `calendarId` was null/undefined or a
398
- * dangling reference). Set by `parseFromBackend` when `resolveCalendarId`
399
- * falls back. The legacy DHTMLX worker computed this; the core owns calendar
400
- * assignment now, so it owns the flag. The UI uses it to surface
401
- * default-assigned activities. See `CALENDARS.md`.
402
- */
403
- assignedDefaultCalendar?: boolean;
237
+ startDate: Date;
238
+ endDate: Date;
239
+ durationHours: number;
240
+ constraintType: ConstraintType | null;
241
+ constraintDate: Date | null;
242
+ autoScheduling: boolean;
243
+ calendarId: CalendarId | null;
244
+ assignedDefaultCalendar: boolean;
245
+ dateOrigin: Date | null;
404
246
  progress: number;
405
247
  cost: number;
406
- used_cost: number;
407
- real_cost: number;
408
- hhWorkTime: number;
409
- real_work: number;
248
+ usedCost: number;
249
+ realCost: number;
250
+ workHours: number;
251
+ realWorkHours: number;
410
252
  ponderator: number;
411
- correlative_id: number;
412
- is_lookahead: boolean;
413
- /**
414
- * Bit de visibilidad del view-model (filtros de UI); ex `should_be_showed`
415
- * del task DHTMLX. `visible !== false` = visible; default true. Escrito por
416
- * el intent `visibility-set` (prop-only) y por `parseFromBackend` al load.
417
- */
418
- visible?: boolean;
419
- newActivitiesArray: ActivityId$1[];
420
- activityModifications: unknown[];
421
- /**
422
- * Backend DB row id (distinct from the core `id`, which is `unique_id`).
423
- * Captured from `a.id` in `parseActivity`; `undefined` for activities
424
- * created in-session (no backend id yet). Used by save dirty-detection to
425
- * tell persisted activities from new ones. Mirrors `Link.proplannerId`.
426
- */
427
- proplannerId?: number;
428
- unique_correlative_id: string;
429
- ganttId: number;
430
- sectorId: number;
431
- companyId: number;
432
- subcontractId: number | null;
433
- subcontract: unknown;
434
- custom_id: string | null;
435
253
  hasCustomPonderator: boolean;
436
- has_childs: boolean;
437
- sumOfDurationRecursively: number;
438
- /**
439
- * Critical-path outputs (poblados cuando corre el CP: en background tras la
440
- * carga vía `criticalPathReady`, o tras cada dispatch). `undefined` si el CP
441
- * aún no corrió. `is_critical` es string DHTMLX (`'Si'`/`'No'`) post-CP,
442
- * boolean recién parseado del backend — ver `CriticalFlag`.
443
- */
444
- earlyStart?: Date | null;
445
- earlyFinish?: Date | null;
446
- lateStart?: Date | null;
447
- lateFinish?: Date | null;
448
- totalSlack?: number | null;
449
- freeSlack: number | null;
450
- is_critical: CriticalFlag;
254
+ correlativeId: number;
255
+ uniqueCorrelativeId: string;
256
+ customId: string | null;
257
+ subcontractId: number | null;
258
+ isLookahead: boolean;
259
+ hasLookaheadTasks: boolean;
260
+ newActivityIds: ActivityId[];
451
261
  hasNewActivities: boolean;
452
- isNewActivity: true | null;
453
- /**
454
- * Active-baseline snapshots for this activity (backend
455
- * `sectorbaselinepoint[]`). Passthrough — carried verbatim so the
456
- * frontend baseline columns and the ponderator computation can read the
457
- * ACTIVE point via `getActiveBaseline`. `undefined` when the activity has
458
- * no baseline (e.g. created in-session after the snapshot).
459
- */
460
- baseline_points?: BaselinePoint[];
461
- tasks: unknown[];
462
- responsables: unknown[];
463
- tags: unknown[];
464
- /**
465
- * Pending Schedule Impact Requests (SIRs) freezing this activity. The
466
- * schedule load path (`sector.controller.js`) already filters to
467
- * `state==='pending'` and sends `{ id }` only, so the core stores just the
468
- * id — enough to name the SIR when emitting a `sir-auto-reject` effect.
469
- * Non-empty ⇒ the activity is frozen (`isFrozen`). The full SIR record lives
470
- * in the front's Redux, not here. See `SIR_MAP.md`.
471
- */
472
- pendingRequests: PendingRequest[];
473
- createdAt: string;
474
- updatedAt: string;
262
+ isNewActivity?: true | null;
263
+ pendingRequestIds: string[];
264
+ responsableIds: string[];
265
+ tagIds: string[];
266
+ baselinePoints: CoreBaselinePoint[];
267
+ baselineSnapshot: ActivityBaselineSnapshot | null;
268
+ recursiveDurationHours: number;
269
+ isCritical: boolean;
270
+ freeSlackHours: number | null;
271
+ expectedProgress: number | null;
272
+ expectedProgressBaseline: number | null;
273
+ status: ActivityStatus | null;
274
+ criticalPath: CriticalPathResult | null;
275
+ /** Internal reversible leaf→project promotion state; never serialized. */
276
+ promotionRestore: {
277
+ type: 'task' | 'milestone';
278
+ startDate: Date;
279
+ endDate: Date;
280
+ durationHours: number;
281
+ expectedProgressBaseline: number | null;
282
+ constraintType: ConstraintType;
283
+ constraintDate: Date | null;
284
+ progress: number;
285
+ } | null;
475
286
  }
476
287
  interface Link {
477
288
  id: LinkId;
478
- source: ActivityId$1;
479
- target: ActivityId$1;
289
+ source: ActivityId;
290
+ target: ActivityId;
480
291
  type: LinkType;
481
292
  lag: number;
482
293
  ganttId?: number;
@@ -493,10 +304,12 @@ interface CalendarWorktime {
493
304
  * (supports per-day variation, e.g. a short Friday,
494
305
  * and multi-shift split days like `["8-12","13-17"]`)
495
306
  *
496
- * Single source of truth: this is exactly what `parseFromBackend` emits —
497
- * a working day ALWAYS carries its resolved windows (the parser resolves
498
- * the default-hours fallback at parse time). The vendored work-calendar
499
- * engine natively also accepts a boolean `true` per day (DHTMLX
307
+ * Single source of truth: this is exactly what `parseFromBackend` emits. A
308
+ * usable working day carries its resolved windows; `[]` is reserved for a
309
+ * catalog calendar that declares the day as working but provides no usable
310
+ * shift anywhere. Those catalog-only calendars remain selectable/persistable
311
+ * but are deliberately not registered as arithmetic calendars. The vendored
312
+ * work-calendar engine natively also accepts a boolean `true` per day (DHTMLX
500
313
  * contract), but that form never appears in the domain `Calendar`; it is
501
314
  * reserved for the engine-facing internals (`SnapshotWorktime`,
502
315
  * synthetic replay fixtures).
@@ -507,8 +320,8 @@ interface CalendarWorktime {
507
320
  days: Array<false | string[]>;
508
321
  /**
509
322
  * Default working-hour windows (`"HH:MM-HH:MM"`). Used as the engine's
510
- * global fallback. `parseFromBackend` sets it to the first working day's
511
- * windows.
323
+ * global fallback. `parseFromBackend` sets it to the first usable working
324
+ * day's windows, or `[]` when the calendar has no usable shift.
512
325
  */
513
326
  hours: string[];
514
327
  /**
@@ -522,7 +335,7 @@ interface CalendarWorktime {
522
335
  * - `string[]` → use these `"HH:MM-HH:MM"` windows instead
523
336
  * of the default `hours`
524
337
  *
525
- * Source: `BackendCalendar.exceptiondays[]` after the adapter expands
338
+ * Source: `BackendCalendarInput.exceptiondays[]` after the adapter expands
526
339
  * `from_date`/`to_date` ranges into individual UTC days.
527
340
  */
528
341
  dates?: Record<string, false | string[]>;
@@ -530,7 +343,7 @@ interface CalendarWorktime {
530
343
  customWeeks?: Record<string, unknown>;
531
344
  }
532
345
  interface Calendar {
533
- id: CalendarId$1;
346
+ id: CalendarId;
534
347
  /** Display name. Used by the DHTMLX calendar-selector column. */
535
348
  name: string;
536
349
  worktime: CalendarWorktime;
@@ -612,6 +425,68 @@ interface EntityChange<T> {
612
425
  after: Readonly<T> | null;
613
426
  }
614
427
 
428
+ declare const COLUMN: {
429
+ readonly REAL_WORK: "real_work";
430
+ readonly REAL_COST: "real_cost";
431
+ readonly EXPECTED_PROGRESS: "expected_progress";
432
+ readonly EXPECTED_PROGRESS_BASE: "expected_progress_base";
433
+ readonly START_BASE: "start_base";
434
+ readonly END_BASE: "end_base";
435
+ readonly DURATION_BASE: "duration_base";
436
+ readonly COST_BASE: "cost_base";
437
+ readonly WORK_BASE: "work_base";
438
+ readonly CALENDAR_DURATION: "calendarDuration";
439
+ readonly IS_CRITICAL: "is_critical";
440
+ readonly EARLY_START: "earlyStart";
441
+ readonly EARLY_FINISH: "earlyFinish";
442
+ readonly LATE_START: "lateStart";
443
+ readonly LATE_FINISH: "lateFinish";
444
+ readonly FREE_SLACK: "freeSlack";
445
+ readonly TOTAL_SLACK: "totalSlack";
446
+ readonly CORRELATIVE_ID: "correlative_id";
447
+ readonly UNIQUE_CORRELATIVE_ID: "unique_correlative_id";
448
+ readonly PONDERATOR: "ponderator";
449
+ readonly STATUS: "status";
450
+ readonly TEXT: "text";
451
+ readonly DESCRIPTION: "description";
452
+ readonly DURATION: "duration";
453
+ readonly PROGRESS: "progress";
454
+ readonly COST: "cost";
455
+ readonly USED_COST: "used_cost";
456
+ readonly HH_WORK_TIME: "hhWorkTime";
457
+ readonly START_DATE: "start_date";
458
+ readonly END_DATE: "end_date";
459
+ readonly CONSTRAINT_TYPE: "constraint_type";
460
+ readonly CONSTRAINT_DATE: "constraint_date";
461
+ readonly CALENDAR_ID: "calendar_id";
462
+ readonly CUSTOM_ID: "custom_id";
463
+ readonly SUBCONTRACT_ID: "subcontractId";
464
+ readonly RESPONSABLES: "responsables";
465
+ readonly TAGS: "tags";
466
+ readonly CUSTOM_PREDECESSORS: "custom_predecessors";
467
+ readonly CUSTOM_SUCESSORS: "custom_sucessors";
468
+ };
469
+ type ColumnName = (typeof COLUMN)[keyof typeof COLUMN];
470
+
471
+ /**
472
+ * Task creation pipeline — types.
473
+ *
474
+ * Ports the pure parts of `src/assets/js/custom_actions/createTask/` into a
475
+ * functional pipeline that replay tests (and eventually prod) can invoke
476
+ * against an adapter instead of the live gantt.
477
+ */
478
+
479
+ /**
480
+ * Closed, canonical contract for create/paste overrides: camelCase, working
481
+ * hours, limited to the fields a caller may seed on a new activity. Identity
482
+ * and structure (`id`/`parentId`/`correlativeId`/`uniqueCorrelativeId`),
483
+ * derived/CP/baseline outputs and view-state are NOT overridable. PP2 adapts
484
+ * its own vocabulary to this contract in step 9.
485
+ */
486
+ declare const CREATION_OVERRIDE_FIELD_LIST: readonly ["name", "description", "type", "startDate", "durationHours", "constraintType", "constraintDate", "calendarId", "assignedDefaultCalendar", "autoScheduling", "progress", "cost", "usedCost", "realCost", "workHours", "realWorkHours", "ponderator", "hasCustomPonderator", "customId", "subcontractId", "responsableIds", "tagIds", "isLookahead"];
487
+ type CreationOverrideField = (typeof CREATION_OVERRIDE_FIELD_LIST)[number];
488
+ type CreationOverrides = Partial<Pick<CoreActivity, CreationOverrideField>>;
489
+
615
490
  /**
616
491
  * Public dispatch types — see Q8/Q9/Q10 in SCHEDULE_CORE_API.md.
617
492
  *
@@ -634,8 +509,8 @@ interface EntityChange<T> {
634
509
  */
635
510
  type LinksBatchOperation = {
636
511
  kind: 'create';
637
- source: ActivityId$1;
638
- target: ActivityId$1;
512
+ source: ActivityId;
513
+ target: ActivityId;
639
514
  type: LinkType;
640
515
  lag?: number;
641
516
  linkId?: LinkId;
@@ -651,7 +526,7 @@ type LinksBatchOperation = {
651
526
 
652
527
  type DispatchAction = {
653
528
  kind: 'inline-edit';
654
- activityId: ActivityId$1;
529
+ activityId: ActivityId;
655
530
  column: string;
656
531
  newValue: unknown;
657
532
  } | {
@@ -664,7 +539,7 @@ type DispatchAction = {
664
539
  */
665
540
  kind: 'dates-batch';
666
541
  edits: ReadonlyArray<{
667
- activityId: ActivityId$1;
542
+ activityId: ActivityId;
668
543
  column: 'start_date' | 'end_date';
669
544
  newValue: unknown;
670
545
  }>;
@@ -686,15 +561,15 @@ type DispatchAction = {
686
561
  */
687
562
  kind: 'bulk-edit';
688
563
  edits: ReadonlyArray<{
689
- activityId: ActivityId$1;
564
+ activityId: ActivityId;
690
565
  column: string;
691
566
  newValue: unknown;
692
567
  }>;
693
568
  eventSource?: string;
694
569
  } | {
695
570
  kind: 'link-create';
696
- source: ActivityId$1;
697
- target: ActivityId$1;
571
+ source: ActivityId;
572
+ target: ActivityId;
698
573
  type: LinkType;
699
574
  /** Lag in DAYS (public boundary unit; converted to working hours inside). */
700
575
  lag: number;
@@ -716,7 +591,7 @@ type DispatchAction = {
716
591
  } | {
717
592
  kind: 'activity-create';
718
593
  /** Where to put the new activity. Use `'0'` for root. */
719
- parentId: ActivityId$1 | '0';
594
+ parentId: ActivityId | '0';
720
595
  /**
721
596
  * Optional — insert the new activity immediately AFTER this sibling.
722
597
  * If omitted (and `beforeSiblingId` also omitted), the new activity
@@ -724,7 +599,7 @@ type DispatchAction = {
724
599
  * currently be a child of `parentId`, otherwise the dispatch is
725
600
  * rejected. Mutually exclusive with `beforeSiblingId`.
726
601
  */
727
- afterSiblingId?: ActivityId$1 | undefined;
602
+ afterSiblingId?: ActivityId | undefined;
728
603
  /**
729
604
  * Optional — insert the new activity immediately BEFORE this sibling.
730
605
  * Use case: "insert as first child" (`beforeSiblingId = currentFirstChild`)
@@ -732,25 +607,20 @@ type DispatchAction = {
732
607
  * The sibling must currently be a child of `parentId`, otherwise the
733
608
  * dispatch is rejected. Mutually exclusive with `afterSiblingId`.
734
609
  */
735
- beforeSiblingId?: ActivityId$1 | undefined;
610
+ beforeSiblingId?: ActivityId | undefined;
736
611
  /**
737
- * Optional field overrides applied on top of the defaults built by
738
- * the creation pipeline. Common cases: `text`, `duration`,
739
- * `start_date`, `constraint_type`, `constraint_date`, `calendar_id`.
740
- *
741
- * Only keys that name a real model field are honored — the pipeline
742
- * drops any incidental non-model key (dhtmlx runtime junk, lightbox UI
743
- * state) so it can never phantom onto the created activity. `name` is
744
- * accepted as an alias for `text` (mapped, then dropped as a raw key).
745
- * See `isDroppableOverrideKey` in `creation/defaults.ts`.
612
+ * Canonical field overrides applied on top of the creation defaults —
613
+ * camelCase, working hours, limited to creation-writable fields
614
+ * (`CreationOverrides`). Identity/structure and derived outputs are not
615
+ * overridable.
746
616
  */
747
- overrides?: Partial<Activity>;
617
+ overrides?: CreationOverrides;
748
618
  /**
749
619
  * Deterministic activity id — used by tests and by replay flows
750
620
  * (paste, undo) that need to assign a specific id. If omitted, the
751
621
  * core's internal id generator allocates one.
752
622
  */
753
- activityId?: ActivityId$1;
623
+ activityId?: ActivityId;
754
624
  /**
755
625
  * Where this create originated from — passed through to the
756
626
  * `schedule_activity_creation` Amplitude event. Free-form string
@@ -765,7 +635,7 @@ type DispatchAction = {
765
635
  * Operation is atomic — if any id is missing, the whole dispatch is
766
636
  * rejected before mutating anything.
767
637
  */
768
- activityIds: ReadonlyArray<ActivityId$1>;
638
+ activityIds: ReadonlyArray<ActivityId>;
769
639
  eventSource?: string;
770
640
  } | {
771
641
  kind: 'activity-move';
@@ -773,16 +643,17 @@ type DispatchAction = {
773
643
  * The activity to move. Single-id only — for batch reorder use
774
644
  * multiple dispatches (each one observes the post-previous state).
775
645
  */
776
- activityId: ActivityId$1;
646
+ activityId: ActivityId;
777
647
  /** Destination parent. Same as current parent = reorder within. */
778
- parentId: ActivityId$1 | '0';
648
+ parentId: ActivityId | '0';
779
649
  /**
780
650
  * Optional — position the moved activity immediately below this
781
651
  * sibling. If omitted, appended as the last child of `parentId`.
782
652
  * The sibling must currently be a child of `parentId`; otherwise
783
- * the dispatch is rejected.
653
+ * the dispatch is rejected. Mutually exclusive with `beforeSiblingId`.
784
654
  */
785
- afterSiblingId?: ActivityId$1;
655
+ afterSiblingId?: ActivityId;
656
+ beforeSiblingId?: ActivityId;
786
657
  eventSource?: string;
787
658
  } | {
788
659
  kind: 'activity-indent';
@@ -792,7 +663,7 @@ type DispatchAction = {
792
663
  * selected set, so consecutive selected siblings all land under the
793
664
  * same anchor (matches legacy `findPreviousNonSelectedSibling`).
794
665
  */
795
- activityIds: ReadonlyArray<ActivityId$1>;
666
+ activityIds: ReadonlyArray<ActivityId>;
796
667
  eventSource?: string;
797
668
  } | {
798
669
  kind: 'activity-outdent';
@@ -801,7 +672,7 @@ type DispatchAction = {
801
672
  * selected siblings via initial-index capture (matches legacy
802
673
  * `initialFirstSiblings` + `initialTaskIndexes` pre-loop setup).
803
674
  */
804
- activityIds: ReadonlyArray<ActivityId$1>;
675
+ activityIds: ReadonlyArray<ActivityId>;
805
676
  eventSource?: string;
806
677
  } | {
807
678
  /**
@@ -824,7 +695,7 @@ type DispatchAction = {
824
695
  * with newValue=0 or newValue=100.
825
696
  */
826
697
  kind: 'activity-set-progress';
827
- activityId: ActivityId$1;
698
+ activityId: ActivityId;
828
699
  /** Strictly 0 (uncomplete) or 100 (complete). */
829
700
  newValue: 0 | 100;
830
701
  eventSource?: string;
@@ -841,7 +712,7 @@ type DispatchAction = {
841
712
  * critical path.
842
713
  */
843
714
  kind: 'selection-toggle';
844
- activityId: ActivityId$1;
715
+ activityId: ActivityId;
845
716
  /** Checkbox state AFTER the user click. */
846
717
  isChecked: boolean;
847
718
  /**
@@ -850,7 +721,7 @@ type DispatchAction = {
850
721
  * is load-time-stale until TODO #10). When omitted, the core
851
722
  * falls back to its own snapshots.
852
723
  */
853
- frozenIds?: ReadonlyArray<ActivityId$1>;
724
+ frozenIds?: ReadonlyArray<ActivityId>;
854
725
  /**
855
726
  * Enable the upward auto-check of ancestors when all their
856
727
  * checkable children become selected. Mirrors the (inverted)
@@ -866,7 +737,7 @@ type DispatchAction = {
866
737
  * `selection-toggle`.
867
738
  */
868
739
  kind: 'selection-replace';
869
- activityIds: ReadonlyArray<ActivityId$1>;
740
+ activityIds: ReadonlyArray<ActivityId>;
870
741
  eventSource?: string;
871
742
  } | {
872
743
  /**
@@ -880,7 +751,7 @@ type DispatchAction = {
880
751
  * path, no undo step. Idempotent.
881
752
  */
882
753
  kind: 'visibility-set';
883
- visibleIds: ReadonlyArray<ActivityId$1>;
754
+ visibleIds: ReadonlyArray<ActivityId>;
884
755
  eventSource?: string;
885
756
  } | {
886
757
  /**
@@ -892,9 +763,21 @@ type DispatchAction = {
892
763
  * ChangeSet; no autoscheduler, no CP. Idempotent.
893
764
  */
894
765
  kind: 'sir-sync';
895
- activityId: ActivityId$1;
766
+ activityId: ActivityId;
896
767
  pendingRequests: ReadonlyArray<PendingRequest>;
897
768
  eventSource?: string;
769
+ } | {
770
+ /**
771
+ * Synchronize the schedule-side flags owned by Lookahead task
772
+ * creation/deletion. The Lookahead records remain at the application
773
+ * boundary; the core owns these flags because they affect schedule
774
+ * editing rules and the public activity view.
775
+ */
776
+ kind: 'activity-lookahead-sync';
777
+ activityIds: ReadonlyArray<ActivityId>;
778
+ isLookahead: boolean;
779
+ hasLookaheadTasks: boolean;
780
+ eventSource?: string;
898
781
  } | {
899
782
  /**
900
783
  * Bulk paste (2026-06-08). Creates N activities (preserving the
@@ -919,22 +802,24 @@ type DispatchAction = {
919
802
  * is derived from the sibling.
920
803
  */
921
804
  destination: {
922
- parentId: ActivityId$1 | '0';
805
+ parentId: ActivityId | '0';
923
806
  index: number;
924
807
  } | {
925
- afterSiblingId: ActivityId$1;
808
+ afterSiblingId: ActivityId;
926
809
  };
927
810
  /**
928
811
  * The activity the paste is anchored to (the single selected row).
929
812
  * Used as the custom_id reference for pasted children. Replaces
930
813
  * the legacy `gantt.pasteReferenceActivity` instance flag.
931
814
  */
932
- referenceActivityId: ActivityId$1;
815
+ referenceActivityId: ActivityId;
933
816
  /**
934
817
  * Activities to create, in tree order (parents before children).
935
818
  * `originalId` / `originalParentId` are the ids from the copied
936
819
  * payload; the core remaps them to freshly allocated ids and uses
937
- * the remap to re-hang the hierarchy and the links.
820
+ * the remap to re-hang the hierarchy and the links. A pasted activity
821
+ * may carry its visible baseline snapshot, but it is not enrolled in an
822
+ * already-created historical baseline.
938
823
  */
939
824
  activities: ReadonlyArray<PastedActivityInput>;
940
825
  /**
@@ -946,26 +831,30 @@ type DispatchAction = {
946
831
  eventSource?: string;
947
832
  };
948
833
  interface PastedActivityInput {
949
- readonly originalId: ActivityId$1;
950
- readonly originalParentId: ActivityId$1 | '0';
951
- readonly overrides: Partial<Activity>;
834
+ readonly originalId: ActivityId;
835
+ readonly originalParentId: ActivityId | '0';
836
+ /**
837
+ * Optional explicit destination id. Production normally omits it and lets
838
+ * the adapter allocate; recorder replay supplies MAIN's observed id so the
839
+ * whole-tree oracle can compare identity without an invented id remap.
840
+ */
841
+ readonly activityId?: ActivityId;
842
+ readonly overrides: CreationOverrides;
843
+ readonly baselineSnapshot?: ActivityBaselineSnapshot | null;
952
844
  }
953
845
  interface PastedLinkInput {
954
- readonly source: ActivityId$1;
955
- readonly target: ActivityId$1;
846
+ readonly source: ActivityId;
847
+ readonly target: ActivityId;
956
848
  readonly type: LinkType;
957
849
  /** Lag in DAYS (public boundary unit; converted to working hours inside). */
958
850
  readonly lag: number;
851
+ readonly linkId?: LinkId;
959
852
  }
960
- /** Unit of duration/lag at the public boundary. Default 'days'. */
961
- type OutputUnit = 'days' | 'hours';
962
853
  interface DispatchOptions {
963
854
  /** Skip the autoscheduler pass after the mutation. Default: false. */
964
855
  skipAutoSchedule?: boolean;
965
856
  /** Skip the CP recompute after the mutation. Default: false. */
966
857
  skipCriticalPath?: boolean;
967
- /** 'days' default; the DHTMLX bridge passes 'hours' to skip conversion. */
968
- outputUnit?: OutputUnit;
969
858
  /**
970
859
  * Unit of the INPUT `newValue` for unit-bearing inline-edit columns (today:
971
860
  * duration). Default 'days' (public contract; card + tests send days). The
@@ -973,7 +862,7 @@ interface DispatchOptions {
973
862
  * the bridge passes 'hours' for those edits → the pipeline skips the days→hours
974
863
  * conversion instead of double-converting.
975
864
  */
976
- inputUnit?: OutputUnit;
865
+ inputUnit?: 'days' | 'hours';
977
866
  }
978
867
  type DispatchResult = {
979
868
  ok: true;
@@ -993,7 +882,7 @@ type DispatchResult = {
993
882
  * handlers (delete/move/paste); stripped before the result reaches the
994
883
  * bridge in the Wave-3 integration.
995
884
  */
996
- __beforeSnap?: ReadonlyMap<string, EngineActivitySnapshot>;
885
+ __beforeSnap?: ReadonlyMap<string, CoreActivity>;
997
886
  /**
998
887
  * INTERNAL (undo / B4). Incident links of deleted activities, keyed by
999
888
  * STRING id (EntityChange link ids are String()-normalized). Carries the
@@ -1029,7 +918,7 @@ interface TrackingEvent {
1029
918
  */
1030
919
  type ScheduleEffect = {
1031
920
  kind: 'sir-auto-reject';
1032
- activityId: ActivityId$1;
921
+ activityId: ActivityId;
1033
922
  /** Backend SIR id == the front Redux item id (see parseFromBackend A1). */
1034
923
  sirId: string;
1035
924
  reason: 'date_changed' | 'activity_deleted';
@@ -1043,13 +932,22 @@ type ScheduleEffect = {
1043
932
  */
1044
933
  interface ConstraintWarning {
1045
934
  kind: 'constraint_violation';
1046
- activityId: ActivityId$1;
935
+ activityId: ActivityId;
1047
936
  constraintType: ConstraintType;
1048
937
  constraintDate: Date;
1049
938
  /** The projected date that violated (start or end, per constraint type). */
1050
939
  projectedDate: Date;
1051
940
  messageKey: string;
1052
941
  }
942
+ interface ViewStatePropChange {
943
+ readonly before: boolean;
944
+ readonly after: boolean;
945
+ }
946
+ interface ViewStateChange {
947
+ readonly activityId: ActivityId;
948
+ readonly checked?: ViewStatePropChange;
949
+ readonly visible?: ViewStatePropChange;
950
+ }
1053
951
  interface ChangeSet {
1054
952
  source: DispatchAction | {
1055
953
  kind: 'init';
@@ -1058,10 +956,11 @@ interface ChangeSet {
1058
956
  } | {
1059
957
  kind: 'redo';
1060
958
  };
1061
- activities: ReadonlyArray<EntityChange<Activity>>;
959
+ activities: ReadonlyArray<EntityChange<CoreActivity>>;
1062
960
  links: ReadonlyArray<EntityChange<Link>>;
1063
961
  calendars: ReadonlyArray<EntityChange<Calendar>>;
1064
962
  trackingEvents: ReadonlyArray<TrackingEvent>;
963
+ viewState?: ReadonlyArray<ViewStateChange>;
1065
964
  /**
1066
965
  * Optional — present only when the dispatch produced side effects. Builders
1067
966
  * that emit none omit it; consumers read `changeSet.effects ?? []`. Kept
@@ -1082,256 +981,111 @@ interface ProjectWorkHours {
1082
981
  endHour: string;
1083
982
  }
1084
983
 
1085
- /**
1086
- * Backend payload shapes — exactly as the Outbuild server returns.
1087
- *
1088
- * The core accepts these directly in the constructor and parses them into
1089
- * normalized internal types. Keeping these as the public input type means
1090
- * any consumer of the schedule API (frontend, node_server, future) speaks
1091
- * the same contract.
1092
- *
1093
- * Validated against the real mocks in
1094
- * `packages/schedule-core/src/testing/projects/startDate/`.
1095
- */
1096
- /** Calendar shift definition — one shift per day, CSV-encoded strings. */
1097
- interface BackendShift {
1098
- id: number;
1099
- /**
1100
- * Encoded shift string for the week:
1101
- * `false,8:00,8:00,8:00,8:00,8:00,false-false,16:00,...,false`
1102
- * left side = starts, right side = ends, each CSV is Sun..Sat.
1103
- * `false` means non-working day.
1104
- */
984
+ interface BackendShiftInput {
1105
985
  shift_string: string;
1106
- correlative_id: number;
1107
- createdAt: string;
1108
- updatedAt: string;
1109
- calendarId: number;
1110
- calendarexceptiondayId: number | null;
1111
986
  }
1112
- /** Backend calendar exception (per-date override). */
1113
- interface BackendCalendarException {
1114
- id: number;
1115
- date: string;
1116
- /** Optional shifts for this specific exception. */
1117
- shifts?: BackendShift[];
1118
- [key: string]: unknown;
987
+ interface BackendCalendarExceptionInput {
988
+ from_date: string;
989
+ to_date: string;
990
+ workable: boolean;
991
+ shifts?: BackendShiftInput[];
1119
992
  }
1120
- /** Calendar as returned by the server. */
1121
- interface BackendCalendar {
993
+ interface BackendCalendarInput {
1122
994
  id: number;
1123
995
  name: string;
1124
- unique_id: number;
1125
996
  is_default: boolean;
1126
- /** CSV of Sun..Sat: `"0,1,1,1,1,1,0"` (0 = non-working, 1 = working). */
997
+ baseDefault?: boolean;
1127
998
  working_days: string;
1128
- /** CSV of shift starts per day: `"false,8:00,8:00,8:00,8:00,8:00,false"`. */
1129
- shift_start: string;
1130
- /** CSV of shift ends per day: `"false,16:00,...,false"`. */
1131
- shift_end: string;
1132
- exceptiondays: BackendCalendarException[];
1133
- shifts: BackendShift[];
1134
- status: boolean;
1135
- companyId: number;
1136
- ganttId: number | null;
1137
- userId: number;
1138
- sectorId: number;
1139
- createdAt: string;
1140
- updatedAt: string;
1141
- [key: string]: unknown;
999
+ shift_start: string | null;
1000
+ shift_end: string | null;
1001
+ shifts: BackendShiftInput[];
1002
+ exceptiondays: BackendCalendarExceptionInput[];
1003
+ baseexceptiondays?: BackendCalendarExceptionInput[];
1142
1004
  }
1143
- /**
1144
- * Activity exactly as the Outbuild server returns it — the raw, untrusted
1145
- * input boundary. Dates are strings, `duration` is in backend DAYS, and field
1146
- * names are the backend's (snake_case, `unique_id`, `parent_id`, `name`).
1147
- *
1148
- * `parseFromBackend` is the only place that consumes it: it validates and
1149
- * normalizes each row into the internal model. Nothing else in the core should
1150
- * read a `BackendActivityInput` after parse.
1151
- */
1152
1005
  interface BackendActivityInput {
1153
- /** Database row id. Distinct from `unique_id`. */
1154
1006
  id: number;
1155
- /** Canonical schedule id (used by links and DHTMLX). String-encoded number. */
1156
1007
  unique_id: string;
1157
- /** Parent's `unique_id`, or `"0"` for root. */
1158
1008
  parent_id: string;
1159
1009
  unique_correlative_id: string;
1160
1010
  correlative_id: number;
1161
1011
  name: string;
1162
- description: string;
1012
+ description: string | null;
1163
1013
  type: 'project' | 'task' | 'milestone';
1164
- /** Format: `"YYYY/MM/DD H:MM"` (server local, see dateFormat in sector). */
1165
1014
  start_date: string;
1166
1015
  end_date: string;
1167
1016
  duration: number;
1168
- /**
1169
- * Constraint label in plain English: `"As soon As Possible"`,
1170
- * `"Start no earlier than"`, etc. Mapped to internal `ConstraintType`.
1171
- */
1172
- constraint: string;
1173
- /** Optional constraint date — server uses ISO 8601 or null. */
1017
+ constraint: string | null;
1174
1018
  constraint_date?: string | null;
1175
1019
  progress: number;
1176
1020
  cost: number;
1177
- used_cost: number;
1178
- real_cost: number;
1021
+ used_cost: number | null;
1022
+ real_cost: number | null;
1179
1023
  hhWorkTime: number;
1180
- real_work: number;
1181
- ponderator: number;
1024
+ real_work: number | null;
1025
+ ponderator: number | null;
1182
1026
  hasCustomPonderator: boolean;
1183
1027
  has_childs: boolean;
1184
1028
  isOnLookahead: boolean;
1185
- sumOfDurationRecursively: number;
1029
+ sumOfDurationRecursively: number | null;
1186
1030
  freeSlack: number | null;
1187
1031
  is_critical: boolean;
1188
- newActivitiesArray: string;
1189
- hasNewActivities: boolean;
1032
+ newActivitiesArray: string | (string | number)[] | null;
1033
+ hasNewActivities: boolean | null;
1190
1034
  isNewActivity: true | null;
1191
1035
  custom_id: string | null;
1192
1036
  ganttId: number;
1193
1037
  sectorId: number;
1194
1038
  companyId: number;
1195
- calendarId: number;
1039
+ calendarId: number | null;
1196
1040
  subcontractId: number | null;
1197
- /**
1198
- * Visibility bit of the legacy view-model. Historically NEVER sent by the
1199
- * backend (0 of ~105k activities across the captured seeds carry it) — the
1200
- * legacy client hardcoded `should_be_showed: true` at parse. Declared so
1201
- * `parseActivity` can map it to `visible` if it ever arrives; absent/null
1202
- * defaults to visible.
1203
- */
1204
- should_be_showed?: boolean;
1041
+ should_be_showed?: boolean | null;
1205
1042
  tasks: unknown[];
1206
1043
  responsables: unknown[];
1207
1044
  tags: unknown[];
1208
1045
  activitymodifications: unknown[];
1209
- /** Pending SIRs for this activity — schedule load sends `{ id }` only. */
1210
- pendingRequests: ReadonlyArray<{
1211
- id: number | string;
1212
- }>;
1046
+ pendingRequests?: readonly {
1047
+ id?: unknown;
1048
+ }[];
1213
1049
  subcontract: unknown;
1050
+ date_origin?: string | null;
1051
+ baseline_points?: BaselinePoint[];
1214
1052
  createdAt: string;
1215
1053
  updatedAt: string;
1216
- /** Custom fields the backend may include — passed through opaquely. */
1217
- [key: string]: unknown;
1218
1054
  }
1219
- /** Link as returned by the server. */
1220
- interface BackendLink {
1055
+ interface BackendLinkInput {
1221
1056
  id: number | string;
1222
- source: number | string;
1223
- target: number | string;
1224
- /** DHTMLX kind: `"0"` FS, `"1"` SS, `"2"` FF, `"3"` SF. */
1225
- type: '0' | '1' | '2' | '3';
1226
- lag: number;
1227
- [key: string]: unknown;
1057
+ unique_id?: string | null;
1058
+ source_id?: string;
1059
+ target_id?: string;
1060
+ source?: number | string;
1061
+ target?: number | string;
1062
+ type?: unknown;
1063
+ lag: number | null;
1064
+ ganttId?: number;
1065
+ sectorId?: number;
1228
1066
  }
1229
- /** Sector metadata — project-level config from the server. */
1230
- interface BackendSector {
1067
+ interface BackendSectorInput {
1231
1068
  id: number;
1232
1069
  name: string;
1233
- description: string | null;
1234
- status: boolean;
1235
- set_current: boolean;
1236
- visible: boolean;
1237
- order: number;
1238
- productive: boolean;
1239
1070
  hoursPerDay: number;
1240
1071
  hoursPerWeek: number;
1241
- accumulatedDuration: number;
1242
- /** Date format string used by the backend, e.g. `"DD/MM/YY hh:mm"`. */
1243
1072
  dateFormat: string;
1244
- didCloseWeek: string | null;
1245
- currentClosedWeek: string | null;
1246
- expectedProgress: number;
1247
- /**
1248
- * Legacy Primavera-import flag. When true, the stored `duration` of each
1249
- * activity may not match the calendar (Primavera stores end-driven
1250
- * durations); the core recomputes duration from start/end at load. ~218
1251
- * production sectors carry it (active). See `Obsidian:newPlanSchedule/CALENDARS.md`.
1252
- */
1253
- update_duration_for_primavera_for_end_date?: boolean | null;
1254
- companyId: number;
1255
1073
  projectId: number;
1256
- version: string;
1257
- createdAt: string;
1258
- updatedAt: string;
1259
- /** Calendars nested inside sector when the sector-fetch endpoint is used. */
1260
- calendars?: BackendCalendar[];
1261
- [key: string]: unknown;
1262
- }
1263
- /** Optional sibling payloads the API often returns alongside the sector. */
1264
- interface BackendScheduleImpactRequests {
1265
- pending: unknown[];
1266
- approved: unknown[];
1267
- rejected: unknown[];
1074
+ companyId: number;
1075
+ update_duration_for_primavera_for_end_date?: boolean | null;
1076
+ activity_creter?: string | null;
1077
+ custom_id_prefix?: string | null;
1078
+ custom_id_increment?: string | number | null;
1079
+ calendars?: BackendCalendarInput[];
1268
1080
  }
1269
- /** Complete server payload accepted by `ScheduleCore`. */
1270
- interface BackendInput {
1271
- sector: BackendSector;
1081
+ interface BackendScheduleInput {
1082
+ sector: BackendSectorInput;
1272
1083
  activities: BackendActivityInput[];
1273
- links: BackendLink[];
1274
- /**
1275
- * Calendars come either inside `sector.calendars` or as a sibling array.
1276
- * If both are present, the sibling array wins.
1277
- */
1278
- calendars?: BackendCalendar[] | undefined;
1279
- /**
1280
- * Baseline calendars, RAW from the backend's `showBaseCalendar` endpoint
1281
- * (exceptions under `baseexceptiondays`, `is_default`, no `-base` suffix).
1282
- * Parsed into a separate `ParsedInput.baseCalendars` collection — never
1283
- * mixed into the scheduling calendars. The core owns their reshape /
1284
- * differentiation (previously done by the frontend `refreshCalendarsRewrite`).
1285
- */
1286
- baseCalendars?: BackendCalendar[] | undefined;
1084
+ links: BackendLinkInput[];
1085
+ calendars?: BackendCalendarInput[] | undefined;
1086
+ baseCalendars?: BackendCalendarInput[] | undefined;
1287
1087
  }
1288
1088
 
1289
- declare const COLUMN: {
1290
- readonly REAL_WORK: "real_work";
1291
- readonly REAL_COST: "real_cost";
1292
- readonly EXPECTED_PROGRESS: "expected_progress";
1293
- readonly EXPECTED_PROGRESS_BASE: "expected_progress_base";
1294
- readonly START_BASE: "start_base";
1295
- readonly END_BASE: "end_base";
1296
- readonly DURATION_BASE: "duration_base";
1297
- readonly COST_BASE: "cost_base";
1298
- readonly WORK_BASE: "work_base";
1299
- readonly CALENDAR_DURATION: "calendarDuration";
1300
- readonly IS_CRITICAL: "is_critical";
1301
- readonly EARLY_START: "earlyStart";
1302
- readonly EARLY_FINISH: "earlyFinish";
1303
- readonly LATE_START: "lateStart";
1304
- readonly LATE_FINISH: "lateFinish";
1305
- readonly FREE_SLACK: "freeSlack";
1306
- readonly TOTAL_SLACK: "totalSlack";
1307
- readonly CORRELATIVE_ID: "correlative_id";
1308
- readonly UNIQUE_CORRELATIVE_ID: "unique_correlative_id";
1309
- readonly PONDERATOR: "ponderator";
1310
- readonly STATUS: "status";
1311
- readonly TEXT: "text";
1312
- readonly DESCRIPTION: "description";
1313
- readonly DURATION: "duration";
1314
- readonly PROGRESS: "progress";
1315
- readonly COST: "cost";
1316
- readonly USED_COST: "used_cost";
1317
- readonly HH_WORK_TIME: "hhWorkTime";
1318
- readonly START_DATE: "start_date";
1319
- readonly END_DATE: "end_date";
1320
- readonly CONSTRAINT_TYPE: "constraint_type";
1321
- readonly CONSTRAINT_DATE: "constraint_date";
1322
- readonly CALENDAR_ID: "calendar_id";
1323
- readonly CUSTOM_ID: "custom_id";
1324
- readonly SUBCONTRACT_ID: "subcontractId";
1325
- readonly RESPONSABLES: "responsables";
1326
- readonly TAGS: "tags";
1327
- readonly CUSTOM_PREDECESSORS: "custom_predecessors";
1328
- readonly CUSTOM_SUCESSORS: "custom_sucessors";
1329
- };
1330
- type ColumnName = (typeof COLUMN)[keyof typeof COLUMN];
1331
-
1332
- type ActivityId = string;
1333
- type CalendarId = string;
1334
-
1335
1089
  /**
1336
1090
  * Role interfaces (Interface Segregation).
1337
1091
  *
@@ -1349,30 +1103,37 @@ type CalendarId = string;
1349
1103
 
1350
1104
  /** READ surface over the activity/link store and the hierarchy index. */
1351
1105
  interface ActivityReader {
1352
- getActivity(activityId: ActivityId$2): EngineActivitySnapshot | null;
1353
- getAllActivities(): ReadonlyArray<EngineActivitySnapshot>;
1106
+ getActivity(activityId: ActivityId$1): CoreActivity | null;
1107
+ getLastStartDate(activityId: ActivityId$1): Date | null;
1108
+ getAllActivities(): ReadonlyArray<CoreActivity>;
1354
1109
  getAllLinks(): LinkSnapshot[];
1355
1110
  getLink(linkId: LinkId$1): LinkSnapshot | null;
1356
- activityExists(activityId: ActivityId$2): boolean;
1357
- getChildren(parentId: ActivityId$2): ActivityId$2[];
1358
- getParent(activityId: ActivityId$2): EngineActivitySnapshot | null;
1359
- getParentId(activityId: ActivityId$2): ActivityId$2 | 0;
1360
- isChildOf(childId: ActivityId$2, parentId: ActivityId$2): boolean;
1361
- getAllIds(): readonly ActivityId$2[];
1111
+ activityExists(activityId: ActivityId$1): boolean;
1112
+ getChildren(parentId: ActivityId$1): ActivityId$1[];
1113
+ hasChildren(parentId: ActivityId$1): boolean;
1114
+ getParent(activityId: ActivityId$1): CoreActivity | null;
1115
+ getParentId(activityId: ActivityId$1): ActivityId$1 | null;
1116
+ getRootIds(): ReadonlyArray<ActivityId$1>;
1117
+ isChildOf(childId: ActivityId$1, parentId: ActivityId$1): boolean;
1118
+ getOutgoingLinkIds(activityId: ActivityId$1): ReadonlyArray<LinkId$1>;
1119
+ getIncomingLinkIds(activityId: ActivityId$1): ReadonlyArray<LinkId$1>;
1120
+ getAllIds(): readonly ActivityId$1[];
1362
1121
  activityCount(): number;
1363
- forEachActivity(visit: (activity: EngineActivitySnapshot, id: ActivityId$2) => void): void;
1122
+ forEachActivity(visit: (activity: CoreActivity, id: ActivityId$1) => void): void;
1364
1123
  }
1365
1124
  /** READ + WRITE surface over the store. */
1366
1125
  interface ActivityWriter extends ActivityReader {
1367
- setActivityField<Field extends keyof EngineActivitySnapshot>(activityId: ActivityId$2, field: Field, value: EngineActivitySnapshot[Field]): void;
1126
+ setActivityField<Field extends keyof CoreActivity>(activityId: ActivityId$1, field: Field, value: CoreActivity[Field]): void;
1127
+ setActivityFieldDynamic(activityId: ActivityId$1, field: string, value: unknown): void;
1368
1128
  /** Bulk write of several fields of one activity in a single getActivity +
1369
1129
  * write-capture note (vs N setActivityField calls). */
1370
- setActivityFields(activityId: ActivityId$2, fields: Partial<EngineActivitySnapshot>): void;
1130
+ setActivityFields(activityId: ActivityId$1, fields: Partial<CoreActivity>): void;
1371
1131
  addLink(link: LinkSnapshot): void;
1372
1132
  removeLink(linkId: LinkId$1): void;
1373
- setLinkField<Field extends keyof LinkSnapshot>(linkId: LinkId$1, field: Field, value: LinkSnapshot[Field]): void;
1374
- addActivity(activity: EngineActivitySnapshot): void;
1375
- removeActivity(activityId: ActivityId$2): void;
1133
+ setLinkField<Field extends MutableLinkField>(linkId: LinkId$1, field: Field, value: LinkSnapshot[Field]): void;
1134
+ setLinkFieldDynamic(linkId: LinkId$1, field: string, value: unknown): void;
1135
+ addActivity(activity: CoreActivity): void;
1136
+ removeActivity(activityId: ActivityId$1): void;
1376
1137
  }
1377
1138
 
1378
1139
  /**
@@ -1410,7 +1171,7 @@ interface ScheduleCoreReporter {
1410
1171
  */
1411
1172
 
1412
1173
  type ScheduleCoreStatus = 'ready' | 'destroyed' | 'poisoned';
1413
- interface ScheduleCoreInput extends BackendInput {
1174
+ interface ScheduleCoreInput extends BackendScheduleInput {
1414
1175
  /**
1415
1176
  * Skip the full autoscheduler pass that normally runs from the
1416
1177
  * constructor (`runInitialPasses`).
@@ -1474,6 +1235,14 @@ interface ScheduleCoreInput extends BackendInput {
1474
1235
  reporter?: ScheduleCoreReporter;
1475
1236
  }
1476
1237
 
1238
+ interface PersistedEntityIdentity {
1239
+ readonly id: string;
1240
+ readonly proplannerId: number;
1241
+ }
1242
+ interface PersistenceAcknowledgement {
1243
+ readonly activities?: ReadonlyArray<PersistedEntityIdentity>;
1244
+ readonly links?: ReadonlyArray<PersistedEntityIdentity>;
1245
+ }
1477
1246
  declare class ScheduleCore {
1478
1247
  private _status;
1479
1248
  /** True while an async dispatch is suspended inside the write-capture window.
@@ -1492,17 +1261,15 @@ declare class ScheduleCore {
1492
1261
  }>;
1493
1262
  get status(): ScheduleCoreStatus;
1494
1263
  getSector(): Readonly<SectorMetadata>;
1495
- getActivityView(id: ActivityId$1, unit?: OutputUnit): Readonly<Activity> | null;
1496
- getAllActivitiesView(unit?: OutputUnit): ReadonlyArray<Readonly<Activity>>;
1497
- getChildrenView(parentId: ActivityId$1 | '0', unit?: OutputUnit): ReadonlyArray<Readonly<Activity>>;
1498
- getLinkView(id: LinkId, unit?: OutputUnit): Readonly<Link> | null;
1499
- getAllLinksView(unit?: OutputUnit): ReadonlyArray<Readonly<Link>>;
1500
- getProperty<Property extends keyof Activity>(activityId: ActivityId$1, property: Property, options?: {
1501
- unit?: OutputUnit;
1502
- }): Activity[Property] | null;
1264
+ getActivityView(id: ActivityId): Readonly<CoreActivity> | null;
1265
+ getAllActivitiesView(): ReadonlyArray<Readonly<CoreActivity>>;
1266
+ getChildrenView(parentId: ActivityId | '0'): ReadonlyArray<Readonly<CoreActivity>>;
1267
+ getLinkView(id: LinkId): Readonly<Link> | null;
1268
+ getAllLinksView(): ReadonlyArray<Readonly<Link>>;
1269
+ getProperty<Property extends keyof CoreActivity>(activityId: ActivityId, property: Property): CoreActivity[Property] | null;
1503
1270
  getAllIds(): readonly string[];
1504
1271
  forEachActivityId(visit: (id: string) => void): void;
1505
- getChildrenIds(parentId: ActivityId$1 | '0'): ReadonlyArray<ActivityId$1>;
1272
+ getChildrenIds(parentId: ActivityId | '0'): ReadonlyArray<ActivityId>;
1506
1273
  getSelectedActivityIds(): string[];
1507
1274
  /**
1508
1275
  * Every activity id in canonical DFS visual order (pre-order from roots,
@@ -1511,18 +1278,28 @@ declare class ScheduleCore {
1511
1278
  * on any structural mutation (add/remove/reparent/renumber), so repeated
1512
1279
  * reads between mutations are O(1).
1513
1280
  */
1514
- getVisualOrderIds(): ReadonlyArray<ActivityId$1>;
1515
- hasChild(parentId: ActivityId$1 | '0'): boolean;
1516
- getCalendar(id: CalendarId$1): Readonly<Calendar> | null;
1281
+ getVisualOrderIds(): ReadonlyArray<ActivityId>;
1282
+ hasChild(parentId: ActivityId | '0'): boolean;
1283
+ getCalendar(id: CalendarId): Readonly<Calendar> | null;
1517
1284
  getAllCalendars(): ReadonlyArray<Readonly<Calendar>>;
1518
1285
  getBaseCalendars(): ReadonlyArray<Readonly<Calendar>>;
1519
1286
  isCustomIdInUse(customId: string, currentCustomId?: string | null): boolean;
1520
1287
  getProjectWorkHours(): ProjectWorkHours | null;
1521
1288
  getModifiedLinks(): ReadonlyArray<Readonly<Link>>;
1522
1289
  markLinksPersisted(): void;
1523
- getModifiedActivities(): ReadonlyArray<Readonly<Activity>>;
1290
+ getModifiedActivities(): ReadonlyArray<Readonly<CoreActivity>>;
1524
1291
  markActivitiesPersisted(): void;
1525
- applyBaselines(points: readonly BaselinePoint[]): ReadonlyArray<Readonly<Activity>>;
1292
+ /**
1293
+ * Reconciles the backend identities returned by a successful schedule save.
1294
+ *
1295
+ * This is an application-boundary acknowledgement, not an editable schedule
1296
+ * gesture: it does not autoschedule, recompute, emit an undo entry, or invent
1297
+ * domain changes. Every assignment is validated before the first mutation so
1298
+ * a malformed/partial response cannot leave the core half-reconciled. Once
1299
+ * applied, the complete live graph becomes the new save-tracker baseline.
1300
+ */
1301
+ acknowledgePersistence(acknowledgement: PersistenceAcknowledgement): void;
1302
+ applyBaselines(points: readonly BaselinePoint[]): ReadonlyArray<Readonly<CoreActivity>>;
1526
1303
  /**
1527
1304
  * Whole-tree ponderator recompute (zeroes, then redistributes 100 within
1528
1305
  * each parent from its children's active baselines, weighted by `criterion`).
@@ -1530,25 +1307,25 @@ declare class ScheduleCore {
1530
1307
  * The base rollup (`applyBaselines`) depends on fresh ponderators, so callers
1531
1308
  * run this before it on a criterion change or baseline save.
1532
1309
  */
1533
- recomputeAllPonderators(criterion: ActivityCreter): ReadonlyArray<Readonly<Activity>>;
1310
+ recomputeAllPonderators(criterion: ActivityCreter): ReadonlyArray<Readonly<CoreActivity>>;
1534
1311
  /**
1535
1312
  * Recompute the weighted-progress rollup of every parent, bottom-up.
1536
1313
  * Returns the activities whose `progress` changed, for a prop-only repaint.
1537
1314
  */
1538
- recomputeAllProgressRollup(): ReadonlyArray<Readonly<Activity>>;
1315
+ recomputeAllProgressRollup(): ReadonlyArray<Readonly<CoreActivity>>;
1539
1316
  /**
1540
1317
  * Set the project's status criterion (the Baseline↔Actual toggle) and
1541
1318
  * recompute every activity's `status` against it. Stores the criterion so
1542
1319
  * future dispatches keep deriving status with it. Returns the activities
1543
1320
  * whose `status` changed, for a prop-only repaint.
1544
1321
  */
1545
- setStatusCriteria(criteria: StatusCriteria): ReadonlyArray<Readonly<Activity>>;
1546
- allocateActivityId(): ActivityId$1;
1322
+ setStatusCriteria(criteria: StatusCriteria): ReadonlyArray<Readonly<CoreActivity>>;
1323
+ allocateActivityId(): ActivityId;
1547
1324
  createActivity(input: Omit<Extract<DispatchAction, {
1548
1325
  kind: 'activity-create';
1549
- }>, 'kind'>, outputUnit?: OutputUnit): {
1326
+ }>, 'kind'>): {
1550
1327
  ok: true;
1551
- activity: Readonly<Activity>;
1328
+ activity: Readonly<CoreActivity>;
1552
1329
  changes: ChangeSet;
1553
1330
  } | {
1554
1331
  ok: false;
@@ -1574,12 +1351,8 @@ declare class ScheduleCore {
1574
1351
  } | null>;
1575
1352
  private _recomputeCriticalPathIfStale;
1576
1353
  private _runCriticalPathAndCapture;
1577
- undo(options?: {
1578
- outputUnit?: OutputUnit;
1579
- }): Promise<ChangeSet | null>;
1580
- redo(options?: {
1581
- outputUnit?: OutputUnit;
1582
- }): Promise<ChangeSet | null>;
1354
+ undo(): Promise<ChangeSet | null>;
1355
+ redo(): Promise<ChangeSet | null>;
1583
1356
  clearHistory(): void;
1584
1357
  canUndo(): boolean;
1585
1358
  canRedo(): boolean;
@@ -1601,32 +1374,18 @@ declare class ScheduleCore {
1601
1374
  private _rollback;
1602
1375
  }
1603
1376
 
1604
- /**
1605
- * Parse the raw backend payload into the core's normalized internal model.
1606
- *
1607
- * Pure function. No side effects, no state. Throws on structural errors
1608
- * (missing required fields, broken references) per Q4 in SCHEDULE_CORE_API.md.
1609
- *
1610
- * Public from the package — consumers can use this to pre-validate before
1611
- * instantiating ScheduleCore, or to round-trip data through tests.
1612
- */
1613
-
1377
+ interface ViewStateSeed {
1378
+ readonly hiddenIds: readonly ActivityId[];
1379
+ }
1614
1380
  interface ParsedInput {
1615
1381
  sector: SectorMetadata;
1616
- activities: Activity[];
1382
+ activities: CoreActivity[];
1617
1383
  links: Link[];
1618
1384
  calendars: Calendar[];
1619
- /**
1620
- * Baseline calendars, kept SEPARATE from the scheduling `calendars`. They
1621
- * are never used to resolve an activity's calendar — only for the baseline
1622
- * render. Parsed from the raw `baseCalendars` input (the backend's
1623
- * `showBaseCalendar`); reshaped here (id+'-base', baseDefault, exceptions
1624
- * from `baseexceptiondays`) so the core owns the differentiation instead of
1625
- * the frontend `refreshCalendarsRewrite`.
1626
- */
1627
1385
  baseCalendars: Calendar[];
1386
+ viewStateSeed: ViewStateSeed;
1628
1387
  }
1629
- declare function parseFromBackend(input: BackendInput, reporter?: ScheduleCoreReporter): ParsedInput;
1388
+ declare function parseFromBackend(input: BackendScheduleInput, reporter?: ScheduleCoreReporter): ParsedInput;
1630
1389
 
1631
1390
  /**
1632
1391
  * Returns the ACTIVE baseline point of an activity, or null.
@@ -1648,8 +1407,8 @@ declare function parseFromBackend(input: BackendInput, reporter?: ScheduleCoreRe
1648
1407
  * the legacy `if (base.sectorbaselineversion.active)` check.
1649
1408
  */
1650
1409
  declare function getActiveBaseline(activity: {
1651
- baseline_points?: unknown;
1652
- } | null | undefined): BaselinePoint | null;
1410
+ baselinePoints?: readonly CoreBaselinePoint[];
1411
+ } | null | undefined): CoreBaselinePoint | null;
1653
1412
 
1654
1413
  /**
1655
1414
  * Surface this function needs from ScheduleState — kept structural so the
@@ -1668,7 +1427,7 @@ interface BaselineApplyAdapter {
1668
1427
  * `baseline_points` reset to `[]`. Returns the ids of activities whose
1669
1428
  * `baseline_points` changed (so the caller can repaint just those).
1670
1429
  */
1671
- declare function applyBaselinePoints(adapter: BaselineApplyAdapter, points: readonly BaselinePoint[]): string[];
1430
+ declare function applyBaselinePoints(adapter: BaselineApplyAdapter, points: readonly BaselinePoint[], reporter: ScheduleCoreReporter): string[];
1672
1431
 
1673
1432
  interface CalendarLike {
1674
1433
  calculateDuration(start: Date, end: Date): number;
@@ -1742,9 +1501,9 @@ declare function recomputeAllPonderators(criterion: ActivityCreter, adapter: Act
1742
1501
  *
1743
1502
  * PROGRESS-ONLY by design: unlike the dispatch post-processor
1744
1503
  * `recomputeParentFromChildren` (post-processors/parent-bounds.ts), this does NOT
1745
- * touch parent start/end/duration — only `progress` and the milestone mirror
1746
- * `for_disable_milestone_duration`. That keeps it testable in isolation
1747
- * (no calendars/dates needed) and matches what `check_progress` actually did.
1504
+ * touch parent start/end/duration — only `progress`. That keeps it testable
1505
+ * in isolation (no calendars/dates needed) and matches what `check_progress`
1506
+ * actually did.
1748
1507
  *
1749
1508
  * Order is load-bearing (unlike ponderators, which are order-independent): a
1750
1509
  * grandparent's rollup consumes its children-parents' ALREADY rolled-up
@@ -1761,127 +1520,8 @@ declare function recomputeAllPonderators(criterion: ActivityCreter, adapter: Act
1761
1520
 
1762
1521
  declare function recomputeAllProgressRollup(adapter: ActivityWriter): void;
1763
1522
 
1764
- /**
1765
- * Task creation pipeline — types.
1766
- *
1767
- * Ports the pure parts of `src/assets/js/custom_actions/createTask/` into a
1768
- * functional pipeline that replay tests (and eventually prod) can invoke
1769
- * against an adapter instead of the live gantt.
1770
- */
1771
-
1772
- /**
1773
- * Shape of the task object AFTER the pipeline configures it.
1774
- *
1775
- * Mirrors the canonical `Activity` interface (from `../../types.ts`) plus
1776
- * a handful of Outbuild-specific fields (responsables, tags, subcontractId,
1777
- * real_constraint_type) and legacy lifecycle flags (new_task, isNewActivity,
1778
- * $source, $target) that downstream consumers still read.
1779
- *
1780
- * Every field in `Activity` is present here. The defaults for the
1781
- * non-runtime-computed ones live in `NEW_ACTIVITY_DEFAULTS`.
1782
- */
1783
- interface NewActivityFields {
1784
- text: string;
1785
- description: string;
1786
- type: 'task' | 'milestone' | 'project';
1787
- start_date: Date;
1788
- end_date: Date;
1789
- duration: number;
1790
- progress: number;
1791
- constraint_type: ConstraintType | null;
1792
- constraint_date: Date | null;
1793
- calendar_id: CalendarId;
1794
- /** Parent id (string) or `'0'` for root. Always string — no number drift. */
1795
- parent: ActivityId | '0';
1796
- auto_scheduling: boolean;
1797
- hhWorkTime: number;
1798
- cost: number;
1799
- used_cost: number;
1800
- /**
1801
- * Earned cost: `(progress/100) × activeBaseline.cost`. A fresh activity has
1802
- * progress 0 and no active baseline, so it starts at 0 — matching what the
1803
- * load-path `emitRealCost` would compute for a new leaf. Seeded explicitly so
1804
- * the field is never `undefined` (which surfaced as `NaN` downstream).
1805
- */
1806
- real_cost: number;
1807
- /** Real worked hours; aggregated from progress submittals. Starts at 0. */
1808
- real_work: number;
1809
- /**
1810
- * Baseline-derived weighting factor used by the parent.progress rollup.
1811
- * Starts at 0 (no baseline yet); set by the backend on baseline import.
1812
- * Not editable from the schedule UI — see `project_ponderator_not_editable`.
1813
- */
1814
- ponderator: number;
1815
- responsables: unknown[];
1816
- tags: unknown[];
1817
- subcontractId: string | number | null;
1818
- real_constraint_type: ConstraintType | null;
1819
- should_be_showed: boolean;
1820
- /** View-model visibility bit (`visible !== false` = visible). */
1821
- visible: boolean;
1822
- activityModifications: unknown[];
1823
- pendingRequests: unknown[];
1824
- /** String form, matches Sequelize BIGINT serialization. */
1825
- unique_correlative_id: string;
1826
- start_date_backup: string;
1827
- new_task: true;
1828
- isNewActivity: true;
1829
- /**
1830
- * Tracks outgoing link ids (this activity is the link source).
1831
- * Initialized empty; mutated by link-create / link-delete to keep the
1832
- * index consistent. The snapshot reads it directly, so it must always
1833
- * exist (not undefined) — see D1 in DIVERGENCES_activity_create.md.
1834
- */
1835
- $source: string[];
1836
- /** Same as $source for incoming links (this activity is the target). */
1837
- $target: string[];
1838
- /** Pass-through bucket for any extra fields the caller provides. */
1839
- [key: string]: unknown;
1840
- }
1841
-
1842
- /**
1843
- * Working-day vocabulary — genuine cross-component primitive (creation
1844
- * defaults, internal/state context fallbacks, link lag display). The value
1845
- * is the FALLBACK only; a sector- or calendar-provided hoursPerDay always
1846
- * takes precedence at every consumer.
1847
- */
1848
- declare const DEFAULT_HOURS_PER_DAY = 8;
1849
-
1850
- /**
1851
- * Defaults for newly-created activities — the **canonical template** that
1852
- * `buildNewActivity` spreads before applying caller-provided overrides.
1853
- *
1854
- * Single source of truth: any documentation that says "a new activity
1855
- * starts as X" must reference this constant, never inline literals.
1856
- *
1857
- * The shape produced by spreading this constant + the runtime-computed
1858
- * fields below is a complete Activity (every field in the `Activity`
1859
- * interface from `../../types.ts` is accounted for).
1860
- *
1861
- * Fields NOT in this constant are computed at runtime because they depend
1862
- * on input or context:
1863
- * - `id` → allocated by `ActivityIdGenerator.next()`
1864
- * - `parent` → from `DispatchAction.parentId` (or `'0'`)
1865
- * - `start_date` → inherited from parent or `fallbackStartDate`,
1866
- * then snapped to the calendar's next
1867
- * working-time boundary
1868
- * - `end_date` → calendar-aware via `adapter.calculateEndDate`
1869
- * - `duration` → override > `sector.hoursPerDay` > `8`
1870
- * - `calendar_id` → override > `sector.defaultCalendar`
1871
- * - `unique_correlative_id` → allocated by `UniqueCorrelativeIdGenerator.next()`
1872
- * - `custom_id` → allocated by `customIdTracker`
1873
- * - `text` → `'New Master Plan'` when this is the very
1874
- * first activity of the sector, `'New Activity'`
1875
- * otherwise (override beats both)
1876
- * - `correlative_id` → assigned by `recomputeCorrelativeIds` after
1877
- * the new activity has been inserted in the
1878
- * parent's children list
1879
- *
1880
- * The `real_constraint_type` field is set AFTER the spread of overrides so
1881
- * it always mirrors the (possibly overridden) `constraint_type`.
1882
- */
1883
-
1884
- declare const NEW_ACTIVITY_DEFAULTS: Readonly<Omit<NewActivityFields, 'id' | 'parent' | 'start_date' | 'end_date' | 'duration' | 'calendar_id' | 'unique_correlative_id' | 'text' | 'start_date_backup'>>;
1523
+ type StaticActivityDefaults = Omit<CoreActivity, 'id' | 'parentId' | 'name' | 'startDate' | 'endDate' | 'durationHours' | 'calendarId' | 'uniqueCorrelativeId'>;
1524
+ declare const NEW_ACTIVITY_DEFAULTS: Readonly<StaticActivityDefaults>;
1885
1525
 
1886
1526
  /**
1887
1527
  * Schedule-core equivalent of the legacy frontend `checkNoUpdatedLinks`.
@@ -1992,8 +1632,8 @@ declare const LINK_CODE_TO_TYPE: {
1992
1632
  /**
1993
1633
  * Inverse boundary maps (domain → backend vocabulary).
1994
1634
  *
1995
- * The forward translations live in `parseFromBackend.ts`
1996
- * (`CONSTRAINT_LABEL_MAP`, `LINK_CODE_TO_NUMBER`). The *serialization*
1635
+ * The forward translations live in `constants.ts` (`CONSTRAINT_LABEL_MAP`)
1636
+ * and `link-display.ts` (`LINK_CODE_TO_NUMBER`). The *serialization*
1997
1637
  * core → backend is intentionally NOT owned by this package today — it
1998
1638
  * lives in the consumer bridge (`react_client/gantt.helper.js`,
1999
1639
  * `from_number_to_code` / `GanttConstraint` reverse lookup) because the
@@ -2008,6 +1648,14 @@ declare const LINK_CODE_TO_TYPE: {
2008
1648
  /** Inverse of `CONSTRAINT_LABEL_MAP` — internal code → backend label. */
2009
1649
  declare const CONSTRAINT_TYPE_TO_LABEL: Record<ConstraintType, string>;
2010
1650
 
1651
+ /**
1652
+ * Working-day vocabulary — genuine cross-component primitive (creation
1653
+ * defaults, internal/state context fallbacks, link lag display). The value
1654
+ * is the FALLBACK only; a sector- or calendar-provided hoursPerDay always
1655
+ * takes precedence at every consumer.
1656
+ */
1657
+ declare const DEFAULT_HOURS_PER_DAY = 8;
1658
+
2011
1659
  /**
2012
1660
  * Canonical catalog of `DispatchAction` kinds.
2013
1661
  *
@@ -2044,6 +1692,7 @@ declare const DISPATCH_ACTION_KIND: {
2044
1692
  readonly SELECTION_REPLACE: "selection-replace";
2045
1693
  readonly VISIBILITY_SET: "visibility-set";
2046
1694
  readonly SIR_SYNC: "sir-sync";
1695
+ readonly ACTIVITY_LOOKAHEAD_SYNC: "activity-lookahead-sync";
2047
1696
  };
2048
1697
  declare const DISPATCH_ACTION_KINDS: ReadonlyArray<DispatchActionKind>;
2049
1698
 
@@ -2119,4 +1768,4 @@ declare const DISPATCH_TRACK_EVENT: {
2119
1768
  };
2120
1769
  type DispatchTrackEvent = (typeof DISPATCH_TRACK_EVENT)[keyof typeof DISPATCH_TRACK_EVENT];
2121
1770
 
2122
- export { ACTIVITY_TYPE, type Activity, type ActivityCreter, type ActivityId$1 as ActivityId, type ActivityType, type BackendActivityInput, type BackendCalendar, type BackendCalendarException, type BackendInput, type BackendLink, type BackendScheduleImpactRequests, type BackendSector, type BackendShift, type BaselinePoint, type BaselineVersion, CALENDAR_UNIT, COLUMN, CONSTRAINT_TYPE, CONSTRAINT_TYPE_TO_LABEL, CREATION_KIND, type Calendar, type CalendarId$1 as CalendarId, type CalendarUnit, type CalendarWorktime, type ChangeSet, type ColumnName, type ConstraintType, type ConstraintWarning, type CreationKind, DEFAULT_HOURS_PER_DAY, DISPATCH_ACTION_KIND, DISPATCH_ACTION_KINDS, DISPATCH_TRACK_EVENT, type DispatchAction, type DispatchActionKind, type DispatchOptions, type DispatchRejectReason, type DispatchResult, type DispatchTrackEvent, type EntityChange, LINK_CODE_TO_TYPE, LINK_TYPE, LINK_TYPE_CODE, type Link, type LinkId, type LinkType, type LinkTypeCode, type LinksBatchOperation, NEW_ACTIVITY_DEFAULTS, type OutputUnit, type ParsedInput, type PastedActivityInput, type PastedLinkInput, type PendingRequest, REJECTION_REASON, ROOT_PARENT_ID, ScheduleCore, type ScheduleCoreInput, type ScheduleCoreReporter, type ScheduleCoreStatus, type ScheduleEffect, type SectorMetadata, type StatusCriteria, type TrackingEvent, WORK_TIME_DIRECTION, type WorkTimeDirection, applyBaselinePoints, checkNoUpdatedLinks, computeExpectedProgress, expectedProgressFromBaseline, getActiveBaseline, getUnsavedActivities, isRootParent, normalizeParentKey, parseFromBackend, recomputeAllPonderators, recomputeAllProgressRollup, willRunCriticalPath, yieldToBrowser };
1771
+ export { ACTIVITY_TYPE, type ActivityCreter, type ActivityId, type ActivityType, type BackendActivityInput, type BackendCalendarInput, type BackendLinkInput, type BackendScheduleInput, type BackendSectorInput, type BaselinePoint, type BaselineVersion, CALENDAR_UNIT, COLUMN, CONSTRAINT_TYPE, CONSTRAINT_TYPE_TO_LABEL, CREATION_KIND, type Calendar, type CalendarId, type CalendarUnit, type CalendarWorktime, type ChangeSet, type ColumnName, type ConstraintType, type ConstraintWarning, type CoreActivity, type CreationKind, DEFAULT_HOURS_PER_DAY, DISPATCH_ACTION_KIND, DISPATCH_ACTION_KINDS, DISPATCH_TRACK_EVENT, type DispatchAction, type DispatchActionKind, type DispatchOptions, type DispatchRejectReason, type DispatchResult, type DispatchTrackEvent, type EntityChange, LINK_CODE_TO_TYPE, LINK_TYPE, LINK_TYPE_CODE, type Link, type LinkId, type LinkType, type LinkTypeCode, type LinksBatchOperation, NEW_ACTIVITY_DEFAULTS, type ParsedInput, type PastedActivityInput, type PastedLinkInput, type PendingRequest, type PersistedEntityIdentity, type PersistenceAcknowledgement, REJECTION_REASON, ROOT_PARENT_ID, ScheduleCore, type ScheduleCoreInput, type ScheduleCoreReporter, type ScheduleCoreStatus, type ScheduleEffect, type SectorMetadata, type StatusCriteria, type TrackingEvent, WORK_TIME_DIRECTION, type WorkTimeDirection, applyBaselinePoints, checkNoUpdatedLinks, computeExpectedProgress, expectedProgressFromBaseline, getActiveBaseline, getUnsavedActivities, isRootParent, normalizeParentKey, parseFromBackend, recomputeAllPonderators, recomputeAllProgressRollup, willRunCriticalPath, yieldToBrowser };