@celigo/api-specs 0.2.127 → 0.2.129

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/tool.yml CHANGED
@@ -4338,7 +4338,7 @@ components:
4338
4338
  no message text) and never cascades or promotes on its own; `Draft`
4339
4339
  descendants are kept as they are, and a `Draft` parent does not gate
4340
4340
  its children. The UI's Set inactive on a parent marks the parent and
4341
- every child `Inactive` (IO-166197). Re-enabling a child
4341
+ every child `Inactive`. Re-enabling a child
4342
4342
  means re-enabling its ancestors in the same payload. Edits that keep
4343
4343
  existing rows must carry their stored status forward — rewriting a
4344
4344
  `Draft` or `Inactive` row to `Active` turns a row the user parked
@@ -5377,7 +5377,7 @@ components:
5377
5377
  no message text) and never cascades or promotes on its own; `Draft`
5378
5378
  descendants are kept as they are, and a `Draft` parent does not gate
5379
5379
  its children. The UI's Set inactive on a parent marks the parent and
5380
- every child `Inactive` (IO-166197). Re-enabling a child
5380
+ every child `Inactive`. Re-enabling a child
5381
5381
  means re-enabling its ancestors in the same payload. Edits that keep
5382
5382
  existing rows must carry their stored status forward — rewriting a
5383
5383
  `Draft` or `Inactive` row to `Active` turns a row the user parked
@@ -6085,7 +6085,7 @@ components:
6085
6085
  ``{record: {...}, settings: ..., job: ...}`` (plus
6086
6086
  ``fileMeta`` on file-provider steps) — the
6087
6087
  same runtime-context envelope Handlebars / SQL /
6088
- GraphQL specialists consume. ``mappings[].extract``
6088
+ GraphQL templates render against. ``mappings[].extract``
6089
6089
  JSONPath values MUST include the ``record.`` segment
6090
6090
  — for example ``"$.record.orderId"`` or
6091
6091
  ``"$.record.customer.email"``. PLACEHOLDER extracts
@@ -6113,9 +6113,8 @@ components:
6113
6113
  ``inputContext: record`` makes the contract
6114
6114
  self-documenting and prevents the transform from
6115
6115
  drifting into envelope mode if an upstream change ever
6116
- changes the platform default. The TransformsAgent
6117
- reads this value off the transform config and threads
6118
- it into the generator's prompt so the JSONPath form
6116
+ changes the platform default. Read this value before
6117
+ writing ``mappings[].extract`` so the JSONPath form
6119
6118
  matches the runtime root.
6120
6119
  - |-
6121
6120
  ## fileMeta on file-provider steps
@@ -13579,30 +13578,19 @@ components:
13579
13578
  would be bare ``{{{jsonSerialize record}}}`` with nothing
13580
13579
  around it, you don't need a template at all.
13581
13580
 
13582
- Production frequency: roughly 1 in 3 active HTTPImports leaves
13583
- this field empty (~35% null / empty array); closer to 1 in 2
13584
- once you count the additional ~12% of body entries that are
13585
- blank strings. The dominant case is "no body template".
13586
-
13587
13581
  Leave undefined for:
13588
13582
  - REST APIs accepting JSON CRUD payloads (the destination
13589
13583
  already wants exactly the post-mapped record shape).
13590
- - GraphQL destinations — do NOT author the body template here.
13591
- The dedicated GraphQL specialist owns the
13592
- ``{query, operationName, variables}`` shape and routes the
13593
- post-mapped record into ``variables`` automatically. Roughly
13594
- 96% of all wrapped-``jsonSerialize record`` uses in production
13595
- are GraphQL mutations; every one of those should go through
13596
- the GraphQL specialist, not through this body template.
13597
13584
  - Any case where the destination wants the mapped record as-is.
13585
+
13586
+ GraphQL destinations are different: the body is the stringified
13587
+ ``{query, operationName, variables}`` envelope described under
13588
+ ``formType``, with the post-mapped record passed in
13589
+ ``variables``.
13598
13590
  - |-
13599
- ## SET THIS FIELD when one of the production patterns below applies
13591
+ ## SET THIS FIELD when one of the patterns below applies
13600
13592
 
13601
- Production grounds these patterns: 36,445 active body entries
13602
- across HTTPImports in the last 30 days (Celigo-internal users
13603
- excluded). Choose the pattern that fits the destination's
13604
- shape, then write marker ``instructions`` describing intent
13605
- (let the Handlebars specialist produce the literal template).
13593
+ Choose the pattern that fits the destination's shape.
13606
13594
 
13607
13595
  ### Pattern A — ``{{{jsonSerialize record}}}`` inside a static wrapper
13608
13596
 
@@ -13614,13 +13602,12 @@ components:
13614
13602
  destination's field shape; the body owns the transport-level
13615
13603
  scaffolding.
13616
13604
 
13617
- Production frequency: roughly 115 / 36,445 (0.3%) of body
13618
- entries when the destination is non-GraphQL. Rare but real;
13619
- the use cases that fit are obvious when the user describes
13620
- them ("wrap each request in a SQS-style message envelope",
13621
- "add a batch header with timestamp + interface name", etc.).
13605
+ Rare for non-GraphQL destinations, but real; the use cases
13606
+ that fit are obvious when the user describes them ("wrap each
13607
+ request in a SQS-style message envelope", "add a batch header
13608
+ with timestamp + interface name", etc.).
13622
13609
 
13623
- Real production shapes:
13610
+ Typical shapes:
13624
13611
  - Message-bus envelope:
13625
13612
  ``{"MessageBody": {"class": "EntityUpdate", "payload": {{{jsonSerialize record}}}}}``
13626
13613
  - Metadata wrap:
@@ -13631,8 +13618,7 @@ components:
13631
13618
  NEVER emit BARE ``{{{jsonSerialize record}}}`` with no wrapper.
13632
13619
  The platform sends the post-mapped record as JSON automatically
13633
13620
  when body is undefined; bare ``jsonSerialize record`` produces
13634
- identical wire output and shows up in 0.7% of production body
13635
- entries — every one of those is redundant config the user has
13621
+ identical wire output, so it is redundant config the user has
13636
13622
  to maintain for zero benefit.
13637
13623
 
13638
13624
  ### Pattern B — Batch / page wrapper around mapped records
@@ -13679,15 +13665,14 @@ components:
13679
13665
  anti-pattern is the ``jsonSerialize`` wrap, not any particular
13680
13666
  path shape.
13681
13667
 
13682
- - Production frequency: 15 / 36,445 (0.04%) — essentially never.
13668
+ - Essentially never needed.
13683
13669
  - Failure mode: the body validator sees the PRE-mapped sample
13684
13670
  shape, can't resolve the post-mapped path during validation,
13685
13671
  and ``jsonSerialize`` on an unresolved path raises
13686
13672
  ``Helper {{jsonSerialize}} expects an argument`` — the
13687
13673
  template fails validation even when it would render at
13688
- runtime. The specialist enters a retry loop, tries variations
13689
- (``getValue`` wrappers, alternate paths), and converges on
13690
- failure.
13674
+ runtime. Variations (``getValue`` wrappers, alternate paths)
13675
+ fail the same way.
13691
13676
 
13692
13677
  If you find yourself wanting to reference a per-field
13693
13678
  post-mapped scalar wrapped in ``jsonSerialize``, your situation
@@ -13750,16 +13735,6 @@ components:
13750
13735
  before choosing: form-data APIs get the parts array above;
13751
13736
  multipart/related APIs get the hand-authored document. Never
13752
13737
  mix the two shapes in one body.
13753
- - |-
13754
- ## Marker instructions style
13755
-
13756
- When emitting a ``$agent: handlebars`` marker at this field,
13757
- write the ``instructions`` as INTENT (what the body should
13758
- produce: destination fields, shape, encoding), not as literal
13759
- Handlebars syntax. Embedding literal ``{{{jsonSerialize record.X}}}``
13760
- in the instructions risks the specialist following it verbatim
13761
- even when a simpler template would work — one of the ways the
13762
- per-field anti-pattern above gets introduced.
13763
13738
  examples:
13764
13739
  - - '{"name": "{{record.name}}", "email": "{{record.email}}"}'
13765
13740
  - - '{"requestData": {{{jsonSerialize record}}}}'
@@ -13851,9 +13826,7 @@ components:
13851
13826
  - |-
13852
13827
  The value MUST match the ``name`` of a lookup entry in ``http.lookups``.
13853
13828
  The lookup config itself (HTTP path, method, extract,
13854
- fallback chain) is authored separately — typically by the LookupsAgent
13855
- specialist via a ``$agent:
13856
- lookup`` marker.
13829
+ fallback chain) is defined separately, in that entry.
13857
13830
  - |-
13858
13831
  ## Mutually exclusive with ``existingExtract``
13859
13832
 
@@ -14333,9 +14306,8 @@ components:
14333
14306
 
14334
14307
  The Celigo platform persists lookups in TWO locations on an HTTP
14335
14308
  import: top-level ``lookups`` and ``http.lookups``. Both arrays
14336
- MUST hold byte-for-byte identical content. The import engine
14337
- and the MappingsAgent both maintain this mirror on every save —
14338
- callers never have to write both manually.
14309
+ MUST hold byte-for-byte identical content, so write both on
14310
+ every save.
14339
14311
  - |-
14340
14312
  ## Static vs dynamic vs cached
14341
14313
 
@@ -14611,7 +14583,7 @@ components:
14611
14583
  computedObject.fileName." — an error the platform labels source `internal` although the
14612
14584
  template is the cause. The run-time-proven way to keep the source file's name on a
14613
14585
  `blob: true` import is `{{record.fileMeta.fileName}}` on `file.fileName` with this field
14614
- omitted (the production runs of one FTP blob import set exactly that); the same template
14586
+ omitted (recorded runs of an FTP blob import set exactly that); the same template
14615
14587
  on this field has not been run. The field's editor preview (data version 1, its default)
14616
14588
  exposes the record as `data` —
14617
14589
  the `{blobKey, fileMeta}` record on a blob import, the page's record array otherwise —
@@ -14991,8 +14963,8 @@ components:
14991
14963
  ## Mirror invariant
14992
14964
  The Celigo platform persists lookups in TWO locations on a JDBC
14993
14965
  import: top-level `lookups` and `jdbc.lookups`. Both arrays
14994
- must hold byte-for-byte identical content — the MappingsAgent
14995
- writes both on every save.
14966
+ must hold byte-for-byte identical content, so write both on every
14967
+ save.
14996
14968
  x-celigo-agent:
14997
14969
  - lookup
14998
14970
  Mongodb:
@@ -15471,25 +15443,22 @@ components:
15471
15443
  substitutions FIRST against the incoming source record (pre-mapped),
15472
15444
  then the substituted expression is sent to NetSuite as a saved-search query.
15473
15445
  - |-
15474
- ## Handlebars conventions (production grounded)
15446
+ ## Handlebars conventions
15475
15447
 
15476
15448
  - **No `record.` prefix** — substitutions reference top-level
15477
15449
  source-record fields directly. `{{{id}}}` / `{{{Id}}}` /
15478
15450
  `{{{externalid}}}` / `{{{[Internal ID]}}}` — NOT
15479
- `{{{record.id}}}`. Production: only 122 / 55,328 expressions
15480
- (0.2%) use the `record.` prefix; the dominant convention is
15481
- top-level paths.
15482
- - **Triple braces `{{{...}}}`** are the preferred form (78% of
15483
- production); double-brace `{{...}}` also works for cases
15484
- where you want the platform's default HTML-escape (rare in
15485
- this field).
15451
+ `{{{record.id}}}`. Top-level paths are the established
15452
+ convention.
15453
+ - **Triple braces `{{{...}}}`** are the preferred form;
15454
+ double-brace `{{...}}` also works for cases where you want
15455
+ the platform's default HTML-escape (rare in this field).
15486
15456
  - **Bracket notation for field names with spaces or special
15487
15457
  chars**: `{{{[Field With Spaces]}}}`, `{{{[Internal ID]}}}`.
15488
- Anchored to ~10% of production expressions.
15489
15458
  - |-
15490
15459
  ## Canonical patterns
15491
15460
 
15492
- ### Simple lookup by internal ID (most common — 8.4% of all expressions)
15461
+ ### Simple lookup by internal ID (most common)
15493
15462
 
15494
15463
  `["internalid","is","{{{id}}}"]`
15495
15464
 
@@ -15560,8 +15529,8 @@ components:
15560
15529
  `is` / `equalto` / `internalid anyof` value to `isempty` before the
15561
15530
  search. On `restletVersion: suiteapp2.0` that search is not treated as
15562
15531
  "no match": it can return existing records, and `addupdate` then
15563
- updates one of them — an unrelated record receives the mapping (seen
15564
- in production as `cant_modify_sub` on a customer the record never
15532
+ updates one of them — an unrelated record receives the mapping (for
15533
+ example, a `cant_modify_sub` error on a customer the record never
15565
15534
  named). SuiteBundle and SuiteApp 1.0 discard a blank `internalid`
15566
15535
  match and create. Design so the operational lookup never renders
15567
15536
  empty: key it on a value every record carries (the source id stored
@@ -15648,10 +15617,6 @@ components:
15648
15617
  - |-
15649
15618
  Validated via the dedicated `PUT /v1/netsuiteDA/previewImportMappingFields`
15650
15619
  endpoint (NOT `/v1/processors/mapperProcessor`).
15651
- - |-
15652
- Managed by the MappingsAgent (`$agent: mapping`) — resource-authoring
15653
- agents must emit a specialist marker at this field rather than
15654
- generating the mapping inline.
15655
15620
  properties:
15656
15621
  fields:
15657
15622
  type: array
@@ -15728,8 +15693,8 @@ components:
15728
15693
  this block ONLY when the destination record type genuinely requires the
15729
15694
  subrecord.
15730
15695
  - |-
15731
- **Real-world `recordType` values** (ranked by
15732
- production frequency across NetSuite DA imports):
15696
+ **Common `recordType` values** (most common
15697
+ first):
15733
15698
  * `inventorydetail` — by far the most common.
15734
15699
  Serial / lot / bin assignments on sales-order,
15735
15700
  item-fulfillment, purchase-order, and inventory-
@@ -15799,8 +15764,8 @@ components:
15799
15764
  type: string
15800
15765
  description: |
15801
15766
  Secondary reference-field identifier used on a
15802
- small fraction of subrecord blocks in production
15803
- (~3%). Exact semantics are not publicly
15767
+ small fraction of subrecord blocks. Exact
15768
+ semantics are not publicly
15804
15769
  documented by Celigo — match the value on
15805
15770
  existing resources when present; do NOT
15806
15771
  synthesize one. Leave unset unless a template
@@ -15829,6 +15794,22 @@ components:
15829
15794
  existing record: on an `add`-only operation every record fails with
15830
15795
  `The mapping condition:"record_updated" not supported for the
15831
15796
  operation`. It works on `addupdate` and `update`.
15797
+ - |-
15798
+ The condition is one of the fixed `when` values — there is no
15799
+ predicate over a source field ("when `customer.id` is not empty",
15800
+ "when `channel.name` is Point of Sale" cannot be written here).
15801
+ `extract_not_empty` is the only source-driven gate: on a lookup row
15802
+ it reads the row's `extract`, and when that is empty the row is
15803
+ skipped and the field is left unset — nothing substitutes a value.
15804
+ Value-dependent behaviour (a fallback record when the key is
15805
+ missing) belongs inside the lookup's `expression` (see
15806
+ `lookups[].expression`).
15807
+ - |-
15808
+ Two rows with the same `generate` are not a fallback pair: the
15809
+ last row for a destination decides it alone — when its condition
15810
+ skips it the field stays empty even if an earlier row produced a
15811
+ value, and when it applies it overwrites the earlier row's value
15812
+ (`ignore_if_set` reads the target record, not an earlier row).
15832
15813
  properties:
15833
15814
  lookupName:
15834
15815
  type: string
@@ -15983,9 +15964,8 @@ components:
15983
15964
  this block ONLY when the destination record type genuinely requires the
15984
15965
  subrecord.
15985
15966
  - |-
15986
- **Real-world `recordType` values** (ranked
15987
- by production frequency across NetSuite DA
15988
- imports):
15967
+ **Common `recordType` values** (most
15968
+ common first):
15989
15969
  * `inventorydetail` — by far the most
15990
15970
  common. Serial / lot / bin assignments on
15991
15971
  sales-order, item-fulfillment, purchase-
@@ -16053,9 +16033,9 @@ components:
16053
16033
  type: string
16054
16034
  description: |
16055
16035
  Secondary reference-field identifier used
16056
- on a small fraction of subrecord blocks
16057
- in production (~3%). Exact semantics are
16058
- not publicly documented by Celigo — match
16036
+ on a small fraction of subrecord blocks.
16037
+ Exact semantics are not publicly
16038
+ documented by Celigo — match
16059
16039
  the value on existing resources when
16060
16040
  present; do NOT synthesize one. Leave
16061
16041
  unset unless a template clearly requires
@@ -16084,6 +16064,18 @@ components:
16084
16064
  rows in live verification. Do not rely on that tolerance — use
16085
16065
  `when: record_updated` only on operations that can update
16086
16066
  records (`addupdate` / `update`).
16067
+ - |-
16068
+ The condition is one of the fixed `when` values — the same
16069
+ closed set as body rows, with no predicate over a source
16070
+ field; `extract_not_empty` skips the row on the lines whose
16071
+ extract is empty and leaves that line's field unset. Two
16072
+ sublist rows with the same `generate` are not a fallback
16073
+ pair either, and the order rule is not the body rows': among
16074
+ extract rows the last row decides each line alone (a skipped
16075
+ last row leaves the line's field unset even when an earlier
16076
+ row produced a value), while a hard-coded row's value lands
16077
+ on every line whatever its position — a later conditional
16078
+ extract row does not override it.
16087
16079
  properties:
16088
16080
  lookupName:
16089
16081
  type: string
@@ -16210,6 +16202,32 @@ components:
16210
16202
  shows what the expression produced for that line. With
16211
16203
  `allowFailures: true` the `default` value is used instead
16212
16204
  and no error is raised. Give every branch an output.
16205
+ - |-
16206
+ ## An empty substitution searches `isempty`
16207
+
16208
+ When the source path a criterion reads is null or absent
16209
+ (`["custentity_celigo_etail_cust_id","is","{{{customer.id}}}"]`
16210
+ on an order with no customer), the engine does not fail on
16211
+ the missing input: it searches the field with an `isempty`
16212
+ criterion, so the lookup now matches every target record
16213
+ whose field is BLANK. Two or more such records fail the
16214
+ record with `VALUE_LOOKUP_FAILED` — `More than one match
16215
+ for "[<field>,"isempty"]" for the record type "<recordType>"`
16216
+ (the message quotes the search field, never the empty
16217
+ source path); none fail it as `Could not find a match`;
16218
+ exactly one silently resolves to that record. Keep an empty
16219
+ key out of the search inside the expression — branch on
16220
+ the key: `{{#if customer.id}}[["custentity_celigo_etail_cust_id",
16221
+ "is","{{{customer.id}}}"]]{{else}}[["internalid","anyof",
16222
+ "<fallback internal id>"]]{{/if}}` routes records without a
16223
+ key to a fallback record while records with a key keep
16224
+ fail-on-miss; or render a value that can never match in the
16225
+ else branch and set `allowFailures: true` with `default`.
16226
+ A `searchField` / `operator` lookup (no `expression`) never
16227
+ reaches this state: an empty extract fails the record with
16228
+ `STATIC_MAPPING_ERROR` — `Exported value is empty/undefined
16229
+ for the field: $.<path>` — and resolves to `default` when
16230
+ `allowFailures` is true.
16213
16231
  - |-
16214
16232
  ## The mapping preview cannot evaluate `[*]` inside a block-helper argument
16215
16233
 
@@ -16243,19 +16261,34 @@ components:
16243
16261
  useDefaultOnMultipleMatches:
16244
16262
  type: boolean
16245
16263
  description: |-
16246
- Controls behaviour when the search matches more than one
16247
- record. When true, the `default` value is returned instead
16248
- of raising an ambiguous-match error. When false (default),
16249
- multiple matches are treated as a failure.
16264
+ When true and `allowFailures` is also true, a search that
16265
+ matches more than one record resolves to `default` instead
16266
+ of failing the record. Has no effect while `allowFailures`
16267
+ is false — an ambiguous match then fails the record whatever
16268
+ this flag says.
16269
+ x-celigo-ai-guidance:
16270
+ - |-
16271
+ Set it together with `allowFailures: true` whenever the
16272
+ search value can be empty or duplicated: with
16273
+ `allowFailures: true` alone an ambiguous match resolves to
16274
+ ONE of the matching records with no error, and with this
16275
+ flag alone the record still fails `More than one match`.
16276
+ Every ambiguous match then becomes `default`, a genuinely
16277
+ duplicated key included — when that must still fail, keep
16278
+ `allowFailures` false and handle the empty key in the
16279
+ `expression` instead (see `expression`).
16250
16280
  allowFailures:
16251
16281
  type:
16252
16282
  - boolean
16253
16283
  - 'null'
16254
16284
  description: |-
16255
16285
  When true, a lookup miss (no matching record and no
16256
- `default`) resolves to `null` and the import continues.
16257
- When false (default), a miss halts the record. May be
16258
- stored as null (treated as unset).
16286
+ `default`) resolves to `null` and the import continues, and
16287
+ a search matching more than one record resolves to one of
16288
+ them unless `useDefaultOnMultipleMatches` routes it to
16289
+ `default`. When false (default), a miss and an ambiguous
16290
+ match both halt the record. May be stored as null (treated
16291
+ as unset).
16259
16292
  map:
16260
16293
  type:
16261
16294
  - object
@@ -16282,8 +16315,8 @@ components:
16282
16315
  ## Mirror invariant
16283
16316
  The Celigo platform persists NetSuite Distributed Import lookups in
16284
16317
  TWO locations: `netsuite_da.lookups` and top-level `lookups`.
16285
- Both arrays must hold byte-for-byte identical content — the
16286
- MappingsAgent writes both on every save.
16318
+ Both arrays must hold byte-for-byte identical content, so write
16319
+ both on every save.
16287
16320
  - |-
16288
16321
  ## One context for body and sublist lookups
16289
16322
  Every lookup's `expression` renders against the whole source
@@ -16412,8 +16445,8 @@ components:
16412
16445
  **Mirror invariant**
16413
16446
  The Celigo platform persists lookups in TWO locations on an RDBMS
16414
16447
  import: top-level `lookups` and `rdbms.lookups`. Both arrays
16415
- must hold byte-for-byte identical content — the MappingsAgent
16416
- writes both on every save.
16448
+ must hold byte-for-byte identical content, so write both on every
16449
+ save.
16417
16450
  items:
16418
16451
  type: object
16419
16452
  properties:
@@ -16538,7 +16571,7 @@ components:
16538
16571
  - **Nested fields**: `{{record.properties.email}}` (auto-quoted)
16539
16572
  or `{{{record.properties.email}}}` (raw).
16540
16573
  - |-
16541
- ## EXAMPLES (production-grounded)
16574
+ ## EXAMPLES
16542
16575
 
16543
16576
  - INSERT (string columns, auto-quoted): `["INSERT INTO customers (name, email) VALUES ({{record.name}}, {{record.email}})"]`
16544
16577
  - INSERT (mixed numeric + string): `["INSERT INTO orders (qty, sku) VALUES ({{{record.qty}}}, {{record.sku}})"]`
@@ -17399,8 +17432,7 @@ components:
17399
17432
  "wrapper" JavaScript module that invokes a custom function (typically to
17400
17433
  integrate with a system Celigo doesn't have a first-class connector for).
17401
17434
  - |-
17402
- Wrapper imports use Mapper 1.0 for field mappings and the generic Celigo lookup shape.
17403
- The MappingsAgent operates in `v1_standard` mode for this adaptor type —
17435
+ Wrapper imports use Mapper 1.0 for field mappings and the generic Celigo lookup shape:
17404
17436
  mappings live in `resource.mapping` (fields/lists) and lookups mirror at
17405
17437
  `resource.lookups` and `resource.wrapper.lookups`.
17406
17438
  properties:
@@ -17448,8 +17480,8 @@ components:
17448
17480
  ## Mirror invariant
17449
17481
  The Celigo platform persists lookups in TWO locations on a
17450
17482
  Wrapper import: top-level `lookups` and `wrapper.lookups`.
17451
- Both arrays must hold byte-for-byte identical content — the
17452
- MappingsAgent writes both on every save.
17483
+ Both arrays must hold byte-for-byte identical content, so write
17484
+ both on every save.
17453
17485
  if:
17454
17486
  not:
17455
17487
  propertyNames:
@@ -17484,8 +17516,8 @@ components:
17484
17516
  **Mirror invariant**
17485
17517
  The Celigo platform stores lookups in TWO locations on a Salesforce
17486
17518
  import resource: top-level ``lookups`` and ``salesforce.lookups``.
17487
- Both arrays must hold byte-for-byte identical content — the
17488
- MappingsAgent writes both on every save.
17519
+ Both arrays must hold byte-for-byte identical content, so write
17520
+ both on every save.
17489
17521
 
17490
17522
  **Static vs dynamic lookups**
17491
17523
  - **Static** — only ``map`` + optional ``default``. No Salesforce
@@ -19651,10 +19683,8 @@ components:
19651
19683
  update this field — the wrapper itself stays the same shape,
19652
19684
  just points at a different Tool.
19653
19685
  - |-
19654
- The agent that authors the wrapper does not author the Tool itself;
19655
- Tool authoring goes through the Tools page agent's `create_tool` / `update_tool` tools (or,
19656
- when invoked from a flow / API / Tool dispatch path,
19657
- through the Tool Builder which delegates to the Tool engine's brief-based entry point).
19686
+ Writing the wrapper does not create or change the Tool itself;
19687
+ author the Tool as its own resource through `/v1/tools`.
19658
19688
  examples:
19659
19689
  - 69ce8ae7cbbb51405ae42ae5
19660
19690
  overrides:
@@ -24950,7 +24980,7 @@ components:
24950
24980
  Optional on a `blob: true` file-provider import: when omitted the platform reads the
24951
24981
  record's root `blobKey` — the field a blob export emits on its `{blobKey, fileMeta}`
24952
24982
  record — so a file-transfer flow needs no `blobKeyPath`. Observed on an FTP import
24953
- (production runs writing files with no `blobKeyPath`) and on a Google Drive folder
24983
+ (recorded runs writing files with no `blobKeyPath`) and on a Google Drive folder
24954
24984
  upload (`http.type: file`, the marketplace file-transfer template's shape); other
24955
24985
  file providers were not probed. Set it only when a response mapping placed the key
24956
24986
  elsewhere; on those two providers its absence is not a cause of upload failures.
@@ -25132,13 +25162,9 @@ components:
25132
25162
  - |-
25133
25163
  JavaScript hook references attached to lifecycle stages of the import.
25134
25164
  Engage hooks ONLY when the user explicitly wants scripting OR a requirement
25135
- cannot be expressed through declarative specialists (mapping / filter /
25165
+ cannot be expressed through declarative configuration (mappings / filters /
25136
25166
  responseTransform).
25137
25167
  Hooks bypass the platform's declarative validation, so use them sparingly.
25138
- - |-
25139
- Phase A authoring scope: ``preMap`` and ``postMap`` only.
25140
- ``postSubmit`` and ``postAggregate`` are Phase B's territory (they author
25141
- against the real destination response).
25142
25168
  properties:
25143
25169
  preMap:
25144
25170
  type: object
@@ -25155,7 +25181,7 @@ components:
25155
25181
  before the mapping sees them (drop archived records,
25156
25182
  normalize date strings, split a record into many). Don't
25157
25183
  engage for static value substitution or simple field
25158
- renames — that's the mapping specialist's job.
25184
+ renames — mappings handle those.
25159
25185
 
25160
25186
  Runtime contract: ``options.data[]`` (the page of upstream
25161
25187
  records) → array of the same length.
@@ -25197,11 +25223,6 @@ components:
25197
25223
  Post-submit JavaScript hook — runs AFTER each batch of
25198
25224
  destination writes, on the destination's response.
25199
25225
 
25200
- **Phase B owns this slot.** Phase A must NOT emit a
25201
- ``$agent`` marker here (see "Phase A vs Phase B ownership"
25202
- in the engine prompt). Phase B authors this against the
25203
- real probe response.
25204
-
25205
25226
  Runtime contract: ``options.responseData[]`` (one per
25206
25227
  submitted record; ``{statusCode, errors, _json, ...}`` —
25207
25228
  ``id`` is present on real runs but absent from the
@@ -25226,11 +25247,6 @@ components:
25226
25247
  ``invalid_hook`` ("unsupported postAggregate hook") —
25227
25248
  never emit it for non-file adaptors.
25228
25249
 
25229
- **Phase B owns this slot.** Phase A must NOT emit a
25230
- ``$agent`` marker here (see "Phase A vs Phase B ownership"
25231
- in the engine prompt). Phase B authors this against the
25232
- real probe response.
25233
-
25234
25250
  Runtime contract: ``options.postAggregateData``
25235
25251
  (``{success, _json, code, message, source}``) → no return
25236
25252
  value; side effects only (logging, notifying, downstream
@@ -25282,8 +25298,7 @@ components:
25282
25298
 
25283
25299
  REQUIRED for ``SalesforceImport`` and ``WrapperImport``: these
25284
25300
  adaptors must use Mapper 1.0; Mapper 2.0 is not supported for
25285
- them. The agent's adaptor→mode classifier routes them here
25286
- automatically. ``NetSuiteDistributedImport`` is also V1-required
25301
+ them. ``NetSuiteDistributedImport`` is also V1-required
25287
25302
  but uses a NetSuite-specific variant at its adaptor-scoped copy
25288
25303
  ``netsuite_da.mapping`` (richer sublist / subRecord vocabulary) —
25289
25304
  not this field.
@@ -25292,17 +25307,9 @@ components:
25292
25307
  ``FTPImport``, ``JDBCImport``, etc.) when the user explicitly asks
25293
25308
  for Mapper 1.0 — e.g. when the import wraps a legacy v1 connector
25294
25309
  or is being migrated from an older integration. Those adaptors
25295
- default to Mapper 2.0 at the top-level ``mappings`` (plural) field;
25296
- see :mod:`celigo_agents.helpers.mappings.mapping_mode` for the
25297
- adaptor → default-mode classifier. Do not emit a marker here
25298
- unsolicited; the v2 default produces better output for modern
25299
- connectors.
25300
- - |-
25301
- ## Specialist marker
25302
-
25303
- Managed by the MappingsAgent (``$agent: mapping``) — resource-
25304
- authoring agents must emit a specialist marker at this field
25305
- rather than generating mapping content inline.
25310
+ default to Mapper 2.0 at the top-level ``mappings`` (plural) field.
25311
+ Do not set this field unsolicited; the v2 default produces better
25312
+ output for modern connectors.
25306
25313
  - |-
25307
25314
  Allowed (but not the default) on other import adaptors such as
25308
25315
  ``HTTPImport``, ``RDBMSImport``, ``FTPImport``, and
@@ -25319,8 +25326,8 @@ components:
25319
25326
 
25320
25327
  Lookups referenced by ``lookupName`` live on the top-level
25321
25328
  ``resource.lookups`` array (mirrored under the adaptor key for
25322
- adaptors that maintain their own copy — see the mirror pattern in
25323
- the MappingsAgent architecture). Lookups are independent of this
25329
+ adaptors that maintain their own copy — see the mirror invariant
25330
+ on ``lookups``). Lookups are independent of this
25324
25331
  mapping: they are neither created nor cleared automatically when
25325
25332
  this mapping changes.
25326
25333
  properties:
@@ -25435,9 +25442,8 @@ components:
25435
25442
  - |-
25436
25443
  ## Mirror invariant
25437
25444
 
25438
- Both arrays MUST hold byte-for-byte identical content. The
25439
- MappingsAgent writes both on every save and treats them as a
25440
- single logical field.
25445
+ Both arrays MUST hold byte-for-byte identical content: write
25446
+ both on every save and treat them as a single logical field.
25441
25447
  - |-
25442
25448
  ## Shape
25443
25449
 
@@ -25498,7 +25504,7 @@ components:
25498
25504
  - ``envelope``: the mapper sees a wrapped object of the shape
25499
25505
  ``{record: {...}, settings: ..., job: ...}`` — the same
25500
25506
  runtime-context envelope Handlebars / SQL / GraphQL
25501
- specialists consume. ``mappings[].extract`` JSONPath values
25507
+ templates render against. ``mappings[].extract`` JSONPath values
25502
25508
  MUST include the ``record.`` segment — for example
25503
25509
  ``"$.record.orderId"`` or ``"$.record.customer.email"``.
25504
25510
  PLACEHOLDER extracts use ``"$.record.PLACEHOLDER_<field>"``.
@@ -25523,9 +25529,9 @@ components:
25523
25529
  platform, but emitting ``inputContext: record`` makes the
25524
25530
  contract self-documenting and prevents the mapper from drifting
25525
25531
  into envelope mode if an upstream change ever changes the
25526
- platform default. The MappingsAgent reads this value off the
25527
- resource and threads it into the mapping generator's prompt so
25528
- the JSONPath form matches the runtime root.
25532
+ platform default. Read this value before writing
25533
+ ``mappings[].extract`` so the JSONPath form matches the runtime
25534
+ root.
25529
25535
  settingsForm:
25530
25536
  x-celigo-agent:
25531
25537
  - settings_form
@@ -25826,9 +25832,9 @@ components:
25826
25832
  Substitute ``<modifiedTimestampField>`` with the actual
25827
25833
  timestamp field the target entity exposes in its response. Do
25828
25834
  NOT invent or copy field names from an example authored for a
25829
- different endpoint -- an unknown field name causes a runtime
25830
- "unknown property" / "invalid column" error the build cannot
25831
- catch. See the engine's filter-field grounding principle.
25835
+ different endpoint -- an unknown field name causes an
25836
+ "unknown property" / "invalid column" error that surfaces only
25837
+ at run time.
25832
25838
 
25833
25839
  For Salesforce, this field is required and has the following default values:
25834
25840
  - LastModifiedDate
@@ -35208,7 +35214,7 @@ components:
35208
35214
  `[application · stage=apiCall] search.createColumn:
35209
35215
  Missing a required argument: name`. The platform
35210
35216
  validation runs before any column data is read, so
35211
- the build fails fast.
35217
+ the export fails fast.
35212
35218
  - |-
35213
35219
  ## NAME MUST BE A SEARCH COLUMN, NOT A BODY FIELD
35214
35220
  NetSuite distinguishes between body fields (the
@@ -35216,9 +35222,8 @@ components:
35216
35222
  search columns (the fields exposed for filtering /
35217
35223
  sorting in saved searches, like `shipaddress1`).
35218
35224
  `columns[].name` MUST be a search column ID, not
35219
- a body field ID. See the SEARCH COLUMNS section of
35220
- the metadata fetcher output for the valid search
35221
- column names for the chosen `recordType`.
35225
+ a body field ID: take it from the chosen
35226
+ `recordType`'s SEARCH COLUMNS list.
35222
35227
  - |-
35223
35228
  ## EXAMPLES
35224
35229
  - `"internalid"` -- the record's internal id
@@ -35960,7 +35965,7 @@ components:
35960
35965
  If the folder internal ID is required to be dynamic based on the data you are integrating,
35961
35966
  you can specify the JSON path to the field in your data containing the folder
35962
35967
  internal ID values instead — with DOUBLE braces (e.g. {{record.folderId}}).
35963
- Production usage is dominantly a static numeric ID; dynamic substitution is rare.
35968
+ Default to a static numeric ID; dynamic substitution is the exception.
35964
35969
  - |-
35965
35970
  ## FIELD BEHAVIOR:
35966
35971
  - Identifies the specific folder in NetSuite's file cabinet to export files from
@@ -35985,7 +35990,7 @@ components:
35985
35990
  - May be linked to folder creation or folder search operations to retrieve valid IDs.
35986
35991
  - |-
35987
35992
  ## EXAMPLES:
35988
- - "12345" - Static folder internal ID (the dominant production form)
35993
+ - "12345" - Static folder internal ID (the usual form)
35989
35994
  - "67890" - Another valid folder internal ID
35990
35995
  - "{{record.folderId}}" - Dynamic folder ID from integration data (double braces)
35991
35996
  - |-