@almadar/core 7.25.0 → 8.0.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.
@@ -1,557 +1,12 @@
1
- import { a6 as EntityField, a9 as EntityPersistence, cX as TraitReference, c$ as TraitScope, cS as TraitEventListener, a2 as Entity, br as Page, bh as OrbitalSchema, cE as Trait } from '../schema-BVni4uNf.js';
1
+ import { e as DomainEntity, J as ParseResult, l as DomainPage, D as DomainBehavior, j as DomainGuard, H as GuardCondition, c as DomainDocument, Q as SectionMapping, P as ParseError, k as DomainMutation } from '../diff-factory-calls-DlBcMWPM.js';
2
+ export { A as ASTNode, C as CallSiteDiff, a as ComparisonCondition, b as ComparisonOperator, d as DomainEffect, f as DomainField, g as DomainFieldDefault, h as DomainFieldItems, i as DomainFieldType, m as DomainPageAction, n as DomainPageSection, o as DomainRelationship, p as DomainRuleOverlayEntry, q as DomainTick, r as DomainTransition, E as EffectType, F as FactoryCallSite, s as FactoryCallSiteParams, t as FactoryEntitySignature, u as FactoryPageSignature, v as FactoryParamValue, w as FactorySignature, x as FactorySignatureCatalog, y as FactorySignatureEntityField, z as FactoryTraitSignature, B as FieldCheckCondition, G as FieldReference, L as LogicalCondition, I as LogicalOperator, O as OwnershipOverlayEntry, K as PresentationNavItem, M as PresentationOverlay, R as RelationshipType, N as RuleOverlay, S as SchemaFieldType, T as SourceLocation, U as SourceRange, V as TraitOverlay, W as TraitOverlayEntry, X as TraitOverlayListener, Y as TranslationBinding, Z as TranslationResult, _ as TranslationWarning, $ as UserCheckCondition, a0 as diffFactoryCalls, a1 as translateDomainToParams } from '../diff-factory-calls-DlBcMWPM.js';
2
3
  import { S as SExpr } from '../expression-BVRFm0sV.js';
4
+ import { y as Entity, bg as Trait } from '../trait-BPe356_9.js';
5
+ export { H as EntityPersistence, bD as TraitScope } from '../trait-BPe356_9.js';
6
+ import { aa as Page, a3 as OrbitalSchema } from '../schema-Bg4qX43l.js';
3
7
  import 'zod';
4
8
  import '@almadar/patterns';
5
9
 
6
- /**
7
- * Domain Language Types
8
- *
9
- * AST node types for the domain language that maps to KFlow schema.
10
- * All entity references use explicit names (e.g., Order, Task, CurrentUser)
11
- * per GAP-002 - no magic variables like `entity.` or `context.`.
12
- *
13
- * @packageDocumentation
14
- */
15
-
16
- /**
17
- * Field type mapping: OrbitalSchema type → Domain Language keyword
18
- *
19
- * This is the single source of truth for type conversion.
20
- * When adding new field types to OrbitalSchema, add the mapping here.
21
- */
22
- declare const FIELD_TYPE_MAPPING: {
23
- readonly string: "text";
24
- readonly number: "number";
25
- readonly boolean: "yes/no";
26
- readonly date: "date";
27
- readonly timestamp: "timestamp";
28
- readonly datetime: "datetime";
29
- readonly array: "list";
30
- readonly object: "object";
31
- readonly enum: "enum";
32
- readonly relation: "relation";
33
- };
34
- /**
35
- * Effect operator mapping: Both systems use the same operator names
36
- */
37
- declare const EFFECT_OPERATORS: readonly ["set", "emit", "navigate", "render-ui", "persist", "call-service", "spawn", "despawn", "do", "notify"];
38
- /**
39
- * Effect operator names (S-expression first element)
40
- * These are the operators used in S-expression effects like ['emit', ...]
41
- */
42
- type EffectType = (typeof EFFECT_OPERATORS)[number];
43
- interface SourceLocation {
44
- line: number;
45
- column: number;
46
- offset: number;
47
- }
48
- interface SourceRange {
49
- start: SourceLocation;
50
- end: SourceLocation;
51
- }
52
- interface ASTNode {
53
- type: string;
54
- range?: SourceRange;
55
- }
56
- /**
57
- * Domain Language field types
58
- *
59
- * Note: These map to OrbitalSchema types via DOMAIN_TO_SCHEMA_FIELD_TYPE
60
- */
61
- type DomainFieldType = 'text' | 'long text' | 'number' | 'currency' | 'date' | 'timestamp' | 'datetime' | 'yes/no' | 'enum' | 'list' | 'object' | 'relation';
62
- /**
63
- * OrbitalSchema field types (for reference)
64
- */
65
- type SchemaFieldType = keyof typeof FIELD_TYPE_MAPPING;
66
- /**
67
- * Default value for a `DomainField`. Mirrors the JSON-leaf shape an
68
- * `EntityField.default` may carry on `OrbitalSchema`: scalar, list, or
69
- * nested object (when the field type is `'object'` or `'list'`).
70
- */
71
- type DomainFieldDefault = string | number | boolean | null | DomainFieldDefault[] | {
72
- [k: string]: DomainFieldDefault;
73
- };
74
- /**
75
- * For `fieldType: 'list'`, the typed shape of each item. Mirrors
76
- * `EntityField.items` on `OrbitalSchema`. Currently a single-level
77
- * type tag (matching how the schema uses it); extend if/when nested
78
- * list-of-list / list-of-object signatures are required.
79
- */
80
- interface DomainFieldItems {
81
- type: DomainFieldType;
82
- }
83
- interface DomainField extends ASTNode {
84
- type: 'field';
85
- name: string;
86
- fieldType: DomainFieldType;
87
- required: boolean;
88
- unique: boolean;
89
- auto: boolean;
90
- default?: DomainFieldDefault;
91
- enumValues?: string[];
92
- /** List-of-X item type when `fieldType === 'list'`. */
93
- items?: DomainFieldItems;
94
- }
95
- type RelationshipType = 'belongs_to' | 'has_many' | 'has_one';
96
- interface DomainRelationship extends ASTNode {
97
- type: 'relationship';
98
- relationshipType: RelationshipType;
99
- targetEntity: string;
100
- alias?: string;
101
- }
102
- interface DomainEntity extends ASTNode {
103
- type: 'entity';
104
- name: string;
105
- description: string;
106
- fields: DomainField[];
107
- relationships: DomainRelationship[];
108
- states?: string[];
109
- initialState?: string;
110
- /**
111
- * Storage mode on the resolved schema. Mirrors `EntityPersistence` in
112
- * `@almadar/core/types/entity.ts`. Omitted ⇒ projector defaults to
113
- * `'persistent'`. Domain text syntax: `Persistence: <value>` line in
114
- * the entity section.
115
- */
116
- persistence?: EntityPersistence;
117
- /**
118
- * Storage collection key. Mirrors `OrbitalSchema.entities[i].collection`.
119
- * Omitted ⇒ defaults to `plural(name).toLowerCase()`. Surfaced to the
120
- * factory translator so the LLM can override the storage key without
121
- * touching the entity name (e.g. entity `Product` → collection
122
- * `"catalog"`).
123
- */
124
- collection?: string;
125
- }
126
- interface DomainPageSection extends ASTNode {
127
- type: 'page_section';
128
- description: string;
129
- }
130
- interface DomainPageAction extends ASTNode {
131
- type: 'page_action';
132
- trigger: string;
133
- action: string;
134
- }
135
- interface DomainPage extends ASTNode {
136
- type: 'page';
137
- name: string;
138
- description: string;
139
- purpose: string;
140
- url: string;
141
- primaryEntity?: string;
142
- traitName?: string;
143
- sections: DomainPageSection[];
144
- actions: DomainPageAction[];
145
- onAccess?: string;
146
- }
147
- type ComparisonOperator = '==' | '!=' | '>' | '<' | '>=' | '<=';
148
- type LogicalOperator = 'AND' | 'OR';
149
- interface FieldReference extends ASTNode {
150
- type: 'field_reference';
151
- entityName: string;
152
- fieldName: string;
153
- }
154
- interface FieldCheckCondition extends ASTNode {
155
- type: 'field_check';
156
- field: FieldReference;
157
- check: 'provided' | 'empty' | 'equals';
158
- value?: string | number | boolean;
159
- }
160
- interface ComparisonCondition extends ASTNode {
161
- type: 'comparison';
162
- field: FieldReference;
163
- operator: ComparisonOperator;
164
- value: string | number | boolean;
165
- }
166
- interface UserCheckCondition extends ASTNode {
167
- type: 'user_check';
168
- check: 'is_role' | 'owns_this';
169
- role?: string;
170
- ownerField?: string;
171
- }
172
- interface LogicalCondition extends ASTNode {
173
- type: 'logical';
174
- operator: LogicalOperator;
175
- left: GuardCondition;
176
- right: GuardCondition;
177
- }
178
- type GuardCondition = FieldCheckCondition | ComparisonCondition | UserCheckCondition | LogicalCondition;
179
- interface DomainGuard extends ASTNode {
180
- type: 'guard';
181
- condition: GuardCondition;
182
- raw: string;
183
- }
184
- interface DomainEffect extends ASTNode {
185
- type: 'effect';
186
- effectType: EffectType;
187
- description: string;
188
- config: Record<string, unknown>;
189
- }
190
- interface DomainTransition extends ASTNode {
191
- type: 'transition';
192
- fromState: string;
193
- toState: string;
194
- event: string;
195
- guards: DomainGuard[];
196
- effects: DomainEffect[];
197
- }
198
- interface DomainTick extends ASTNode {
199
- type: 'tick';
200
- name: string;
201
- interval: string;
202
- intervalMs?: number;
203
- guard?: DomainGuard;
204
- effects: DomainEffect[];
205
- }
206
- interface DomainBehavior extends ASTNode {
207
- type: 'behavior';
208
- name: string;
209
- entityName: string;
210
- states: string[];
211
- initialState: string;
212
- transitions: DomainTransition[];
213
- ticks: DomainTick[];
214
- rules: string[];
215
- /**
216
- * Instance- vs collection-scoped state machine. Mirrors
217
- * `Trait.scope: TraitScope` in `@almadar/core/types/trait.ts`.
218
- * Omitted ⇒ projector defaults to `'instance'`. Domain text syntax:
219
- * `Scope: instance|collection` line in the behavior section.
220
- */
221
- scope?: TraitScope;
222
- }
223
- interface DomainDocument extends ASTNode {
224
- type: 'document';
225
- entities: DomainEntity[];
226
- pages: DomainPage[];
227
- behaviors: DomainBehavior[];
228
- }
229
- interface SectionMapping {
230
- sectionId: string;
231
- sectionType: 'entity' | 'page' | 'behavior' | 'tick';
232
- schemaPath: string;
233
- domainText: string;
234
- aiDescription?: string;
235
- range?: SourceRange;
236
- lastModified?: number;
237
- }
238
- interface ParseError {
239
- message: string;
240
- range?: SourceRange;
241
- suggestion?: string;
242
- }
243
- interface ParseResult<T> {
244
- success: boolean;
245
- data?: T;
246
- errors: ParseError[];
247
- warnings: ParseError[];
248
- }
249
- /**
250
- * One field on a factory's canonical entity, in signature form. Mirrors
251
- * the subset of `EntityField` that the projector needs to score a
252
- * domain-entity match. Auto-added audit fields (id / createdAt /
253
- * updatedAt) are omitted by the extractor.
254
- */
255
- interface FactorySignatureEntityField {
256
- name: string;
257
- type: SchemaFieldType;
258
- required: boolean;
259
- }
260
- /**
261
- * The canonical entity a factory produces. Almost always one entity
262
- * per orbital; modeled as an array to keep the door open for orbitals
263
- * that compose multiple entities.
264
- */
265
- interface FactoryEntitySignature {
266
- /** Canonical entity name the factory's params build (e.g. `"ChatMessage"`). */
267
- name: string;
268
- /** Fields the factory emits, post-auto-field stripping. */
269
- fields: ReadonlyArray<FactorySignatureEntityField>;
270
- /** Persistence mode declared on the canonical entity in the `.orb`. */
271
- persistence: EntityPersistence;
272
- }
273
- /**
274
- * One trait the factory composes into the orbital. The projector reads
275
- * these to determine which factory's trait stack covers a given
276
- * `DomainBehavior` + which override knobs a presentation overlay can
277
- * deterministically target. Trait identity is by `name` only; the
278
- * projector matches structurally on the event / config arrays — no
279
- * inferred "kind" tag.
280
- */
281
- interface FactoryTraitSignature {
282
- /** Canonical trait name post-rename (e.g. `"ChatMessageList"`). */
283
- name: string;
284
- /** Event keys this trait emits (post-rename). Read directly from
285
- * the trait's `emits[].event`. */
286
- emittedEvents: ReadonlyArray<string>;
287
- /** Event keys this trait listens for. Read directly from `listens[].event`. */
288
- listenedEvents: ReadonlyArray<string>;
289
- /** Config keys overridable via `traitOverrides.<name>.config.<key>`.
290
- * Read directly from the trait's `config` declaration block. */
291
- overridableConfigKeys: ReadonlyArray<string>;
292
- /** Capability tags lifted directly from the source `.lolo` trait's
293
- * header annotations. Free-form strings — the Phase 4 translator
294
- * overlay matches rules to traits by exact set membership. Empty
295
- * when the trait declared none. See `docs/Almadar_Domain_Language.md`
296
- * Phase 3. */
297
- capabilities: ReadonlyArray<string>;
298
- }
299
- /** One page the factory emits. The path is the factory default; the
300
- * projector may override via `params.pagePath` or `params.pages[].path`. */
301
- interface FactoryPageSignature {
302
- name: string;
303
- defaultPath: string;
304
- primaryEntity: string;
305
- }
306
- interface FactorySignature {
307
- /** Organism the factory belongs to (e.g. `"std-realtime-chat"`). */
308
- organism: string;
309
- /** Orbital this factory builds within that organism. */
310
- orbital: string;
311
- /** Tier the factory sits in (informational; drives nothing today). */
312
- tier: 'atoms' | 'molecules' | 'organisms';
313
- /** Path of the generated factory source (relative to the std root). */
314
- factoryPath: string;
315
- /** Canonical entity surface(s) the factory produces. */
316
- entities: ReadonlyArray<FactoryEntitySignature>;
317
- /** Trait stack the factory composes. */
318
- traits: ReadonlyArray<FactoryTraitSignature>;
319
- /** Pages the factory emits. */
320
- pages: ReadonlyArray<FactoryPageSignature>;
321
- /** Union of all `traits[].emittedEvents`. */
322
- emittedEvents: ReadonlyArray<string>;
323
- /** Union of all `traits[].listenedEvents`. */
324
- listenedEvents: ReadonlyArray<string>;
325
- }
326
- /**
327
- * Aggregate catalog written to
328
- * `packages/almadar-std/behaviors/registry/factory-signatures.json`.
329
- * Sorted by organism then orbital. One entry per factory in the
330
- * regenerate pipeline.
331
- */
332
- interface FactorySignatureCatalog {
333
- /** Generated-by version stamp (the `@almadar/std` minor it shipped in). */
334
- generatedFromStdVersion: string;
335
- /** Sorted list of factory signatures. */
336
- signatures: ReadonlyArray<FactorySignature>;
337
- }
338
- /**
339
- * A single factory invocation, as the typed result of the translator.
340
- * Lower into runtime by calling the factory at `factoryPath` with
341
- * these `params`. Stable identity for downstream diffing is
342
- * `(organism, orbital)`.
343
- */
344
- interface FactoryCallSite {
345
- /** Matches `FactorySignature.organism`. */
346
- organism: string;
347
- /** Matches `FactorySignature.orbital`. */
348
- orbital: string;
349
- /** Matches `FactorySignature.factoryPath`. Convenience pointer; the
350
- * authoritative source remains the signature catalog. */
351
- factoryPath: string;
352
- /** Typed param surface fed to the factory at invocation time. */
353
- params: FactoryCallSiteParams;
354
- }
355
- /**
356
- * The typed param surface every factory's call site populates. Each
357
- * field on this interface corresponds to one row in the translator's
358
- * domain↔factory mapping table. Adding a new domain concept means
359
- * adding a field here AND wiring it in `translateDomainToParams`.
360
- *
361
- * Fields are all optional because not every factory consumes every
362
- * concept; the translator only sets what the chosen signature
363
- * advertises.
364
- */
365
- interface FactoryCallSiteParams {
366
- /** Override `signature.entities[0].name` (entity rename). */
367
- entityName?: string;
368
- /** Additional or overriding entity fields. Caller wins on collision. */
369
- entityFields?: ReadonlyArray<EntityField>;
370
- /** Override `signature.entities[0].persistence`. */
371
- persistence?: EntityPersistence;
372
- /** Override the entity's storage collection key. Defaults to
373
- * `plural(entityName).toLowerCase()` at factory dispatch time
374
- * when omitted. */
375
- collection?: string;
376
- /** Per-page path overrides keyed by `signature.pages[i].name`. */
377
- pagePaths?: Readonly<Record<string, string>>;
378
- /** Trait config overrides keyed by `signature.traits[i].name`. Each
379
- * value is a record keyed by the trait's `overridableConfigKeys`. */
380
- traitOverrides?: Readonly<Record<string, {
381
- config?: Readonly<Record<string, FactoryParamValue>>;
382
- }>>;
383
- /** Extra traits to compose into the orbital that aren't part of the
384
- * canonical signature trait stack. Used when a domain behavior
385
- * isn't covered by any canonical trait. */
386
- extraTraits?: ReadonlyArray<TraitReference>;
387
- }
388
- /**
389
- * Allowed leaf values for the typed factory-param surface. Same as
390
- * `DomainFieldDefault` minus null, plus arrays + records to mirror
391
- * the trait-config shape factories accept today.
392
- */
393
- type FactoryParamValue = string | number | boolean | ReadonlyArray<FactoryParamValue> | {
394
- readonly [key: string]: FactoryParamValue;
395
- };
396
- /**
397
- * Discriminated union of edits to a `DomainDocument`. Each variant
398
- * carries typed AST nodes already defined in this file — never raw
399
- * JSON. `applyMutation` is total over this union.
400
- */
401
- type DomainMutation = {
402
- kind: 'add-entity';
403
- entity: DomainEntity;
404
- } | {
405
- kind: 'remove-entity';
406
- entityName: string;
407
- } | {
408
- kind: 'rename-entity';
409
- from: string;
410
- to: string;
411
- } | {
412
- kind: 'update-entity';
413
- entityName: string;
414
- entity: DomainEntity;
415
- } | {
416
- kind: 'add-field';
417
- entityName: string;
418
- field: DomainField;
419
- } | {
420
- kind: 'remove-field';
421
- entityName: string;
422
- fieldName: string;
423
- } | {
424
- kind: 'update-field';
425
- entityName: string;
426
- field: DomainField;
427
- } | {
428
- kind: 'add-page';
429
- page: DomainPage;
430
- } | {
431
- kind: 'remove-page';
432
- pageName: string;
433
- } | {
434
- kind: 'update-page';
435
- pageName: string;
436
- page: DomainPage;
437
- } | {
438
- kind: 'add-behavior';
439
- behavior: DomainBehavior;
440
- } | {
441
- kind: 'remove-behavior';
442
- behaviorName: string;
443
- } | {
444
- kind: 'update-behavior';
445
- behaviorName: string;
446
- behavior: DomainBehavior;
447
- } | {
448
- kind: 'add-transition';
449
- behaviorName: string;
450
- transition: DomainTransition;
451
- } | {
452
- kind: 'remove-transition';
453
- behaviorName: string;
454
- from: string;
455
- to: string;
456
- event: string;
457
- } | {
458
- kind: 'add-relationship';
459
- entityName: string;
460
- relationship: DomainRelationship;
461
- } | {
462
- kind: 'remove-relationship';
463
- entityName: string;
464
- targetEntity: string;
465
- relationshipType: RelationshipType;
466
- };
467
- /**
468
- * Cross-cutting presentation knobs that don't live in `DomainDocument`
469
- * because they're factory-layer concerns (nav items live on a layout
470
- * trait; theme is a separate `ThemeRef`). The translator reads these
471
- * and threads them into the matching factory params.
472
- */
473
- interface PresentationOverlay {
474
- /** Nav items to add to the orbital's layout trait. The translator
475
- * looks for a `signature.traits[i]` with `overridableConfigKeys`
476
- * including `navItems` and writes into `traitOverrides[name].config.navItems`. */
477
- navAdditions?: ReadonlyArray<PresentationNavItem>;
478
- /** Optional theme ref override for the orbital. */
479
- themeRef?: string;
480
- }
481
- interface PresentationNavItem {
482
- label: string;
483
- path: string;
484
- /** Optional icon key (consumer-resolved). */
485
- icon?: string;
486
- }
487
- /**
488
- * LLM-authored trait-level overrides keyed by trait name (matches
489
- * `signature.traits[].name`). Each entry's `config` keys are
490
- * validated against `signature.traits[i].overridableConfigKeys`;
491
- * unknown trait names or unknown config keys emit typed warnings
492
- * and are skipped. Mirrors the existing call-site override surface
493
- * on `TraitReference` in `OrbitalSchema`.
494
- */
495
- type TraitOverlay = Readonly<Record<string, TraitOverlayEntry>>;
496
- interface TraitOverlayEntry {
497
- config?: Readonly<Record<string, FactoryParamValue>>;
498
- linkedEntity?: string;
499
- events?: Readonly<Record<string, string>>;
500
- name?: string;
501
- emitsScope?: 'internal' | 'external';
502
- /** Reuses `TraitEventListener` from `@almadar/core/types/trait` so the
503
- * overlay's listen entries carry the same `event` / `triggers` /
504
- * `source` / `guard` shape as everywhere else — no narrower clone. */
505
- listens?: ReadonlyArray<TraitEventListener>;
506
- }
507
- /** @deprecated Phase 4.1 placeholder — use `TraitEventListener` instead.
508
- * Kept as a structural type alias so callers that imported it keep
509
- * compiling through the transition; will be removed in 7.25.0. */
510
- type TraitOverlayListener = TraitEventListener;
511
- /**
512
- * Rules carry a free-form `capability: string` that the translator
513
- * matches against `signature.traits[].capabilities` (source-tagged
514
- * in `.lolo`, propagated via `@almadar/core@7.22.0`).
515
- *
516
- * NO closed enum on `capability` — atoms advertise capability
517
- * strings in their `.lolo` headers, and the catalog grows the
518
- * vocabulary organically. The agent emits whatever capability
519
- * string the user's domain expresses; if no trait in the catalog
520
- * advertises that capability, the translator emits a typed warning.
521
- */
522
- interface RuleOverlay {
523
- rules: ReadonlyArray<DomainRuleOverlayEntry>;
524
- /**
525
- * Entity-level ownership signal. Until Phase 1.5 promotes
526
- * `ownedBy` into `DomainEntity`, ownership rides here as a
527
- * parallel typed channel. The translator threads it into the
528
- * matched trait's `config.ownerField` (when the matched trait
529
- * advertises that key in `overridableConfigKeys`).
530
- */
531
- ownership?: ReadonlyArray<OwnershipOverlayEntry>;
532
- }
533
- interface DomainRuleOverlayEntry {
534
- id: string;
535
- /** Free-form capability label, matched against
536
- * `signature.traits[].capabilities` by exact set membership. */
537
- capability: string;
538
- description: string;
539
- /** Entity names this rule binds to. Empty array = cross-cutting:
540
- * the rule applies to every orbital the translator visits. */
541
- appliesTo: ReadonlyArray<string>;
542
- /** Optional role name (e.g. `"admin"`) when the rule is role-scoped. */
543
- role?: string;
544
- /** Optional extra config knobs threaded into the matched trait's
545
- * `config`. Validated against the trait's `overridableConfigKeys`. */
546
- config?: Readonly<Record<string, FactoryParamValue>>;
547
- }
548
- interface OwnershipOverlayEntry {
549
- /** Entity name (matches `DomainEntity.name`). */
550
- entity: string;
551
- /** Field name on the entity that carries the owner identifier. */
552
- ownerField: string;
553
- }
554
-
555
10
  /**
556
11
  * Domain Language Tokens
557
12
  *
@@ -1032,88 +487,6 @@ declare function applySectionUpdate(schema: OrbitalSchema, sectionType: 'entity'
1032
487
  */
1033
488
  declare function deleteSection(schema: OrbitalSchema, sectionType: 'entity' | 'page' | 'behavior' | 'tick', sectionId: string): OrbitalSchema;
1034
489
 
1035
- /**
1036
- * Deterministic translator: one `DomainDocument` slice + one chosen
1037
- * `FactorySignature` → one `FactoryCallSite`. The agent picks the
1038
- * signature upstream via embedding-search over the catalog; this
1039
- * function does ZERO matching. It just lowers domain fields onto the
1040
- * factory's advertised param surface, field-by-field.
1041
- *
1042
- * The binding (which `DomainEntity` / `DomainPage[]` map to this
1043
- * orbital) is the agent's explicit decision and is passed in. No name
1044
- * matching, no scoring, no tie-breaks.
1045
- *
1046
- * Adding a new domain concept means:
1047
- * 1. Add a field on `DomainEntity` / `DomainPage` / `DomainBehavior`
1048
- * (`packages/almadar-core/src/domain-language/types.ts`).
1049
- * 2. Make sure at least one factory signature advertises a
1050
- * consuming knob (Phase 1.5 gate — generated by
1051
- * almadar-pattern-sync from `.orb`).
1052
- * 3. Add one helper-fn row below that lowers the new field into
1053
- * `FactoryCallSiteParams`.
1054
- *
1055
- * If a binding field has no signature consumer, the translator emits
1056
- * a typed warning and SKIPS the field — that's the loud signal the
1057
- * field shouldn't have been admitted to the language.
1058
- */
1059
-
1060
- /**
1061
- * The slice of `DomainDocument` that maps onto the chosen signature.
1062
- * The agent assembles this when it picks the signature: it knows
1063
- * which `DomainEntity` / `DomainPage[]` are this orbital's
1064
- * responsibility.
1065
- */
1066
- interface TranslationBinding {
1067
- /** The single domain entity this signature's orbital owns. */
1068
- entity: DomainEntity;
1069
- /** Pages from the domain doc that map to this orbital's pages. The
1070
- * translator pairs them with `signature.pages[]` by name. */
1071
- pages?: ReadonlyArray<DomainPage>;
1072
- }
1073
- interface TranslationWarning {
1074
- /** Dotted path of the domain field that couldn't be lowered. */
1075
- field: string;
1076
- /** Human-readable reason. */
1077
- reason: string;
1078
- }
1079
- interface TranslationResult {
1080
- callSite: FactoryCallSite;
1081
- warnings: ReadonlyArray<TranslationWarning>;
1082
- }
1083
- declare function translateDomainToParams(binding: TranslationBinding, signature: FactorySignature, presentation?: PresentationOverlay, ruleOverlay?: RuleOverlay, traitOverlay?: TraitOverlay, catalog?: ReadonlyArray<FactorySignature>): TranslationResult;
1084
-
1085
- /**
1086
- * Structural diff between two `FactoryCallSite[]` lists. Pure typed,
1087
- * no side effects. Used by downstream consumers (agent planner, UI
1088
- * cascade view) to turn a "previous calls" + "next calls" pair into a
1089
- * minimal change set.
1090
- *
1091
- * Identity for diffing is `(organism, orbital)`. Renames are not
1092
- * handled here — they show up as a delete + add. The agent layer is
1093
- * expected to merge those back into a `'rename'` op if it can prove
1094
- * the underlying domain entity was renamed.
1095
- */
1096
-
1097
- type CallSiteDiff = {
1098
- kind: 'add';
1099
- orbitalName: string;
1100
- next: FactoryCallSite;
1101
- } | {
1102
- kind: 'delete';
1103
- orbitalName: string;
1104
- prior: FactoryCallSite;
1105
- } | {
1106
- kind: 'edit';
1107
- orbitalName: string;
1108
- prior: FactoryCallSite;
1109
- next: FactoryCallSite;
1110
- } | {
1111
- kind: 'keep';
1112
- orbitalName: string;
1113
- call: FactoryCallSite;
1114
- };
1115
- declare function diffFactoryCalls(prior: ReadonlyArray<FactoryCallSite>, next: ReadonlyArray<FactoryCallSite>): ReadonlyArray<CallSiteDiff>;
1116
-
1117
490
  /**
1118
491
  * Section Mapping
1119
492
  *
@@ -1255,6 +628,55 @@ declare function validateDomainChunk(chunk: DomainChunk): string[];
1255
628
  */
1256
629
  declare function formatMergeSummary(result: MergeResult): string;
1257
630
 
631
+ /**
632
+ * Phase 5 — `mergeDocuments(base, overlay)` overlay reducer.
633
+ *
634
+ * The studio questionnaire renders `mergeDocuments(factoryBase,
635
+ * userOverlay)` as its surface — the user edits the overlay; the base
636
+ * never mutates. Server-side, the planner reads the user's persisted
637
+ * overlay and merges it on top of the catalog's `baseDocument` to
638
+ * derive the final `DomainDocument` fed to `translateDomainToParams`.
639
+ *
640
+ * Semantics:
641
+ * - `entities[]`, `pages[]`, `behaviors[]` matched by `name`. The
642
+ * overlay's entry replaces the base's; missing names from one side
643
+ * are kept verbatim from the other.
644
+ * - Within a matched entity / page / behavior, overlay fields win
645
+ * (overlay-replace, not deep-merge). This means a user clearing
646
+ * `fields: []` is honoured rather than silently re-inflating from
647
+ * the base. The questionnaire UI emits partial overlays only for
648
+ * the slots the user touched, so this is the right granularity.
649
+ * - Arrays inside matched entries (`entities[i].fields[]`,
650
+ * `pages[i].sections[]`) are NOT field-level merged — the overlay
651
+ * replaces the base array verbatim when present. For granular
652
+ * additions ("add a field"), the UI authors a `DomainMutation`
653
+ * and applies via `applyMutation` instead of going through
654
+ * `mergeDocuments`.
655
+ * - Top-level `type` is always `'document'`.
656
+ *
657
+ * Pure function — no I/O, no mutation of inputs. Returns a new
658
+ * `DomainDocument`.
659
+ *
660
+ * @packageDocumentation
661
+ */
662
+
663
+ /**
664
+ * Compose a base `DomainDocument` (factory catalog baseline) with a
665
+ * user-authored overlay (questionnaire answers + edits). Entities,
666
+ * pages, and behaviors are matched by `name`; the overlay replaces
667
+ * any base entry with the same name. Unmatched entries on either side
668
+ * survive unchanged.
669
+ *
670
+ * Idempotent: `mergeDocuments(d, emptyDocument)` returns a deep-copy
671
+ * of `d`. `mergeDocuments(emptyDocument, d)` likewise.
672
+ *
673
+ * @param base The starting document (factory `baseDocument` or
674
+ * organism-level union).
675
+ * @param overlay The user-authored overlay carrying edits.
676
+ * @returns A new merged document; neither input is mutated.
677
+ */
678
+ declare function mergeDocuments(base: DomainDocument, overlay: DomainDocument): DomainDocument;
679
+
1258
680
  /**
1259
681
  * Domain Language Registry
1260
682
  *
@@ -1408,4 +830,4 @@ declare function generateDomainLanguageReference(): string;
1408
830
  */
1409
831
  declare function applyMutation(doc: DomainDocument, mut: DomainMutation): DomainDocument;
1410
832
 
1411
- export { type ASTNode, type CallSiteDiff, type ComparisonCondition, type ComparisonOperator, type DomainBehavior, type DomainChunk, type DomainDocument, type DomainEffect, type DomainEntity, type DomainField, type DomainFieldDefault, type DomainFieldItems, type DomainFieldType, type DomainGuard, type DomainMutation, type DomainPage, type DomainPageAction, type DomainPageSection, type DomainRelationship, type DomainRuleOverlayEntry, type DomainTick, type DomainToSchemaResult, type DomainTransition, EFFECT_REGISTRY, type EffectMapping, type EffectType, EntityPersistence, FIELD_TYPE_REGISTRY, type FactoryCallSite, type FactoryCallSiteParams, type FactoryEntitySignature, type FactoryPageSignature, type FactoryParamValue, type FactorySignature, type FactorySignatureCatalog, type FactorySignatureEntityField, type FactoryTraitSignature, type FieldCheckCondition, type FieldReference, type FieldTypeMapping, GUARD_REGISTRY, type GuardCondition, type GuardMapping, KEYWORDS, Lexer, type LogicalCondition, type LogicalOperator, MULTI_WORD_KEYWORDS, type MappingStore, type MergeResult, type OwnershipOverlayEntry, type ParseError, type ParseResult, type PresentationNavItem, type PresentationOverlay, type RelationshipType, type RuleOverlay, type SchemaFieldType, type SchemaToDomainResult, type SectionMapping, type SourceLocation, type SourceRange, type Token, TokenType, type TraitOverlay, type TraitOverlayEntry, type TraitOverlayListener, TraitScope, type TranslationBinding, type TranslationResult, type TranslationWarning, type UserCheckCondition, applyMutation, applySectionUpdate, computeSchemaHash, convertDomainToSchema, convertEntitiesToDomain, convertPagesToDomain, convertSchemaToDomain, convertTraitsToDomain, createMappingStore, deleteSection, detectChanges, diffFactoryCalls, domainKeywordToSchemaType, findMapping, findMappingByPath, findMappingsByType, formatBehaviorToDomain, formatBehaviorToSchema, formatDomainGuardToSchema, formatEntityToDomain, formatEntityToSchema, formatGuardConditionToDomain, formatGuardToDomain, formatGuardToSchema, formatMergeSummary, formatPageToDomain, formatPageToSchema, formatSchemaEntityToDomain, formatSchemaGuardToDomain, formatSchemaPageToDomain, formatSchemaTraitToDomain, generateDomainLanguageReference, generateSectionId, getEffectMapping, getFieldTypeMapping, getGuardMapping, getRegisteredEffects, getRegisteredFieldTypes, getRegisteredGuards, getRegistryStats, getSchemaPath, hasSchemaChanged, isEffectRegistered, isFieldTypeRegistered, isGuardRegistered, mergeDomainChunks, parseBehavior, parseDomainEffect, parseDomainEffects, parseDomainGuard, parseEntity, parseGuard, parsePage, parseSectionId, removeMapping, resolveConflict, schemaEntityToDomainEntity, schemaPageToDomainPage, schemaTraitToDomainBehavior, schemaTypeToDomainKeyword, tokenize, translateDomainToParams, updateMappingRange, updateSchemaHash, upsertMapping, validateDomainChunk };
833
+ export { DomainBehavior, type DomainChunk, DomainDocument, DomainEntity, DomainGuard, DomainMutation, DomainPage, type DomainToSchemaResult, EFFECT_REGISTRY, type EffectMapping, FIELD_TYPE_REGISTRY, type FieldTypeMapping, GUARD_REGISTRY, GuardCondition, type GuardMapping, KEYWORDS, Lexer, MULTI_WORD_KEYWORDS, type MappingStore, type MergeResult, ParseError, ParseResult, type SchemaToDomainResult, SectionMapping, type Token, TokenType, applyMutation, applySectionUpdate, computeSchemaHash, convertDomainToSchema, convertEntitiesToDomain, convertPagesToDomain, convertSchemaToDomain, convertTraitsToDomain, createMappingStore, deleteSection, detectChanges, domainKeywordToSchemaType, findMapping, findMappingByPath, findMappingsByType, formatBehaviorToDomain, formatBehaviorToSchema, formatDomainGuardToSchema, formatEntityToDomain, formatEntityToSchema, formatGuardConditionToDomain, formatGuardToDomain, formatGuardToSchema, formatMergeSummary, formatPageToDomain, formatPageToSchema, formatSchemaEntityToDomain, formatSchemaGuardToDomain, formatSchemaPageToDomain, formatSchemaTraitToDomain, generateDomainLanguageReference, generateSectionId, getEffectMapping, getFieldTypeMapping, getGuardMapping, getRegisteredEffects, getRegisteredFieldTypes, getRegisteredGuards, getRegistryStats, getSchemaPath, hasSchemaChanged, isEffectRegistered, isFieldTypeRegistered, isGuardRegistered, mergeDocuments, mergeDomainChunks, parseBehavior, parseDomainEffect, parseDomainEffects, parseDomainGuard, parseEntity, parseGuard, parsePage, parseSectionId, removeMapping, resolveConflict, schemaEntityToDomainEntity, schemaPageToDomainPage, schemaTraitToDomainBehavior, schemaTypeToDomainKeyword, tokenize, updateMappingRange, updateSchemaHash, upsertMapping, validateDomainChunk };