@mcp-abap-adt/interfaces-adt 20.2.0 → 22.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,215 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [22.0.0] - 2026-10-28
11
+
12
+ A major for one change: the ABAP cloud table loses the program and include
13
+ operations the cloud refuses (see "Changed (breaking)"). Everything else is
14
+ added beside 21.0.0's types: each keeps its meaning, and a type parameter
15
+ added to an existing type has the 21.0.0 type as its default.
16
+
17
+ ### Changed (breaking)
18
+
19
+ - **`ADT_TYPES_CLOUD`: a program and an include change nothing.** ABAP cloud
20
+ refuses to create either (`403`, S_DEVELOP, measured on the BTP trial
21
+ 2026-10-28), so `PROG/P` and `PROG/I` no longer list `create`, `update`,
22
+ `lock`, `unlock`, `activate`, `validate`, `deletionCheck` or `delete`.
23
+ What a delivered one answers stays: `read`, `source` and `readMetadata`
24
+ (measured on both), `check` and `versions` for a program (measured),
25
+ and the operations not measured — the enhancement reads, `transport`,
26
+ `run`, `profile` and the unit-test runs — as the release's `typestructure`
27
+ lists them. Leaving out the change operations beyond `create` is an
28
+ inference from the refusal: S_DEVELOP is the change authorization, and an
29
+ object nobody can create has nothing of one's own to change. A function
30
+ include (`FUGR/I`) is unchanged: the cloud creates one (`200`, measured).
31
+ `AdtTypeCodeWith<'cloud', Op>` and `AdtCodeWith<AdtModernVariant, Op>` no
32
+ longer name `PROG/P` or `PROG/I` for those operations, and the cloud table
33
+ is no longer the on-premise one in operations.
34
+
35
+ ### Added
36
+
37
+ - **`updateMetadata`** on `CLAS/OC`, `INTF/OI`, `FUGR/FF` and `DDLS/DF` in
38
+ `ADT_TYPES_ONPREM` and `ADT_TYPES_CLOUD`, and on `PROG/P` in
39
+ `ADT_TYPES_ONPREM`: the object's whole metadata document, written back with
40
+ the media type it was read with, answers `200` on S/4HANA 2025 and on ABAP
41
+ cloud (measured 2026-10-27). 7.40 is not measured yet and keeps none.
42
+
43
+ - **Intersecting helpers.** `AdtCodeOf<V>` and `AdtCodeWith<V, Op>`: the codes
44
+ every variant of `V` lists (with `Op`) — the default modern variant,
45
+ `AdtModernVariant` (`'onprem' | 'cloud'`), gets what both newer tables
46
+ serve. `AdtCodeOfIn<Tables, V>` and `AdtCodeWithIn<Tables, V, Op>` are the
47
+ same over any set of tables; `AdtServingVariantsIn<Tables, A>` and
48
+ `AdtPerformingVariantsIn<Tables, A, Op>` name the variants whose table
49
+ serves an API, or one of its codes an operation. `AdtTypeCodeOf`,
50
+ `AdtTypeCodeWith`, `AdtApiWith` and `AdtApiWithIn` are unchanged; their docs
51
+ now state what they answer for a union of variants — the APIs all of them
52
+ serve, and for those the codes and operations any of them lists.
53
+ - **Utility code tables**, `ADT_UTILITY_CODES_ONPREM`, `_CLOUD`,
54
+ `_BASIS_740` (`IAdtUtilityCodeTables`, `AdtUtilityCodeTable<R>`,
55
+ `IAdtUtilityCodeFacts<R>`, `AdtUtilityOperation`, `AdtUtilityCodeWith<V,
56
+ Op>`, `AdtUtilityCode`): the codes `getUtils()` takes beyond the API tables,
57
+ each with its operations, whether they were measured, and its evidence.
58
+ - `VIEW/DV`, a DDIC database view, on every release: group activation,
59
+ group deletion and where-used, under `/sap/bc/adt/ddic/views`. No API
60
+ serves it — a **group-only code**, `AdtGroupOnlyCode`,
61
+ `AdtGroupOnlyCodeOf<V>`. Sent, unmeasured.
62
+ - `DEVC/K` in a group activation on the newer releases — sent, unmeasured.
63
+ - `DEVC/K` in `fetchNodeStructure` on 7.40 — measured (the legacy
64
+ `UtilsReaders` cycle). A table of its own rather than a package entry on
65
+ 7.40, because an entry would gate `getPackage()` open where every package
66
+ member is refused, and a new `AdtOperation` word would break a 21.0.0
67
+ consumer's exhaustive map over the vocabulary.
68
+ - `IObjectReference<C>`, `IGetWhereUsedParams<C>` and
69
+ `IGetWhereUsedScopeParams<C>` take a group-only code as their type
70
+ argument (`IObjectReference<'VIEW/DV'>`). Their defaults are 21.0.0's: a
71
+ bare `IObjectReference` still admits `AdtTypeCode` alone.
72
+ - **What each group operation is given:** `AdtGroupActivationCode<V>`,
73
+ `AdtGroupDeletionCheckCode<V>`, `AdtGroupDeletionCode<V>` (no `MSAG/NN`,
74
+ which has no address of its own), `AdtWhereUsedCode<V>` (no `FUGR/I` or
75
+ `MSAG/NN`), and the references over them, `IAdtGroupActivationReference<V>`,
76
+ `IAdtGroupDeletionCheckReference<V>`, `IAdtGroupDeletionReference<V>`,
77
+ `IAdtWhereUsedParamsOf<V>`, `IAdtWhereUsedScopeParamsOf<V>`, built by
78
+ `IAdtCodedReference<C>`: `parentName` required for each parented code, and
79
+ a reference from a code known only by its set compiles when it names its
80
+ parent — inside TypeScript's 25-combination limit.
81
+ - `IAdtTypedGroupLifecycle<TActivation, TDeletionCheck, TDeletion, V>` and
82
+ `IAdtTypedWhereUsed<TWhereUsed, TScope, V>`: the group and where-used members
83
+ over those references. New atoms beside `IAdtGroupLifecycle` and
84
+ `IAdtWhereUsed`, with the same member names: an implementation declaring
85
+ both offers both signatures, and a caller passing `IObjectReference[]` is
86
+ unaffected. Adding the signatures to the 21.0.0 atoms instead would have
87
+ made every implementation of them stop compiling.
88
+ - `IAdtTypeStructure<TTypeStructure>`: `getTypeStructure({ headers })`,
89
+ `POST /sap/bc/adt/repository/typestructure`, an atom of its own like
90
+ `IAdtObjectProperties`, and `IUtilResults.typeStructure`, its reading —
91
+ optional, so a 21.0.0 result set is still one.
92
+
93
+ ## [21.0.0] - 2026-10-27
94
+
95
+ ### Added
96
+
97
+ - **The ADT type tables**, one per release variant: `ADT_TYPES_ONPREM`
98
+ (S/4HANA 2025 on-premise), `ADT_TYPES_CLOUD` (ABAP cloud) and
99
+ `ADT_TYPES_BASIS_740` (SAP_BASIS 7.40 SP04), `as const`, keyed by API — the
100
+ client's factory name. Each entry holds its `kind`, its `collection` and its
101
+ `codes`; each code its `parent` API, `nameMaxLength`, `operations` and
102
+ `evidence`, the corpus case of the release's `typestructure` answer, and,
103
+ where it lives elsewhere than its API, its own `collection` (the enhancement
104
+ codes: `/sap/bc/adt/enhancements/enhoxhh`, `/enhoxhb`, `/enhsxsb`). The
105
+ local class includes and the transport request are entries with
106
+ `codes: {}`, their `parent`, `operations` and `evidence` on the entry. An
107
+ API the 7.40 client refuses whole is absent from its table, and an operation
108
+ it refuses is absent from its code.
109
+ - The operations' closed vocabulary, `AdtOperation`. The ABAP Unit runners'
110
+ four members are four operations, `unitTestRun`, `unitTestRunSync`,
111
+ `unitTestStatus` and `unitTestResult`, because 7.40 serves them apart: there
112
+ `run` and `runSync` are served for a class, a program and a function group,
113
+ only `runSync` for a function module, and `getStatus` and `getResult` for
114
+ none (no run id to poll or fetch).
115
+ - The entry shape every table `satisfies` (`AdtApiTable<R>`, `AdtApiEntry<R>`,
116
+ `IAdtCodedApiEntry<R>`, `IAdtCodelessApiEntry<R>`, `IAdtCodeFacts<R>`,
117
+ `AdtApiName`, `AdtOperations`, `AdtCollection`, `AdtTypeEvidence<R>`,
118
+ `AdtCheckedTable<T>`): a misspelt field, an operation outside the
119
+ vocabulary, an API with no factory, another release's evidence, a codeless
120
+ entry without evidence or a coded entry without a code does not compile.
121
+ - The variants and the types derived from the tables: `AdtVariant`
122
+ (`'onprem' | 'cloud' | 'basis740'`), `IAdtTypeTables`, `AdtApi<V>`,
123
+ `AdtTypeCode`, `AdtTypeCodeOf<V>`, `AdtApiWith<V, Op>` and
124
+ `AdtApiWithIn<T, Op>` (the APIs one code of which performs every operation
125
+ of `Op` — operations spread across two codes do not count),
126
+ `AdtTypeCodeWith<V, Op>`, `AdtObjectKind`, `AdtSourceTypeCode`,
127
+ `AdtParentedTypeCode`.
128
+ - `IAdtAnsweredObject`: `{ type: AdtTypeCode }` or `{ unknownType: string }`,
129
+ exclusive — what a code read from an answer is, so an unknown one reaches the
130
+ consumer as the text ADT sent rather than being dropped.
131
+ - `AdtObjectIdentity<TConfig, TParent>`: what an identifying member takes —
132
+ `Partial<TConfig>` itself when `TParent` is `never`, otherwise every field
133
+ optional but `TParent`, which is required.
134
+
135
+ ### Changed (breaking)
136
+
137
+ - **The identifying atoms take the parent's field as a last type parameter,**
138
+ `TParent extends keyof TConfig = never`: `IAdtReadable`,
139
+ `IAdtMetadataReadable`, `IAdtEnhancementHost`, `IAdtIncludeEnhancementHost`,
140
+ `IAdtDeletable` (after `TChecked`), `IAdtValidatable`, `IAdtCheckable`,
141
+ `IAdtActivatable`, `IAdtLockable`, `IAdtVersionable`, `IAdtTransportAware`.
142
+ Their `config` is `AdtObjectIdentity<TConfig, TParent>`. With the default it
143
+ is `Partial<TConfig>` — the same type as before, so an existing contract and
144
+ code generic in `TConfig` compile unchanged. A contract whose API has a
145
+ parent passes its field: `functionGroupName` for a function module and a
146
+ function include, `className` for the four local class includes and for a
147
+ message class message; its identifying members then require it.
148
+ - **`IObjectReference` is generic in its code,**
149
+ `IObjectReference<C extends AdtTypeCode = AdtTypeCode>`: `type` is `C`, and
150
+ `parentName` is required when `[C] extends [AdtParentedTypeCode]` —
151
+ `IObjectReference<'FUGR/FF'>` needs it — and optional otherwise, the default
152
+ included. The condition is not distributive: a reference built from a code
153
+ typed `AdtTypeCode` compiles, and an interface can extend `IObjectReference`
154
+ (a union of one member per code exceeds TypeScript's 25 combinations and
155
+ cannot be extended). The group operations take `IObjectReference[]`, so a
156
+ caller that wants the parent enforced types its references by code.
157
+ - **Every code parameter is a code of the tables:**
158
+ - `IAdtObjectAccess`: `readObjectSource` and `getObjectSourceUri` take an
159
+ `AdtSourceTypeCode` (the codes the library reads a source of);
160
+ `readObjectMetadata` and `supportsSourceCode` an `AdtTypeCode` (any
161
+ object has metadata, and asking whether a code has source is asked of any
162
+ code).
163
+ - `IAdtRepositoryStructure.fetchNodeStructure(parentType)` and
164
+ `getObjectStructure(objectType)` take an `AdtTypeCode`: the node and
165
+ object structures are asked of any object — a package's contents, a
166
+ class's includes, a program's parts — so no narrower set is stated.
167
+ - `IGetWhereUsedScopeParams.object_type` and `IGetWhereUsedParams.object_type`
168
+ are an `AdtTypeCode`: where-used is asked of any object.
169
+ - `ISearchObjectsParams.objectType` is an `AdtTypeCode`: the search filters
170
+ by any code.
171
+
172
+ ### Removed (breaking)
173
+
174
+ - `AdtObjectTypeLower`, `AdtObjectType`, `AdtSourceObjectTypeLower` and
175
+ `AdtSourceObjectType`. With them go the codes no release lists, which no
176
+ table holds: `INTF/IF`, `STRU/DT`, `STRU/DS`, `TTYP/DF`, `TTYP/TT`,
177
+ `TTYP/ST`, `DOMA/DM`, `BDEF/BD`, `BIMP/BIM`, `BIMP/`, `BIMPL/`, `FUGR/FC`,
178
+ `FUNC`, bare `SCGR`, `DSFD/DSF`, `DSFI/DSF`, `SUSO/O`, the bare `FUGR` and
179
+ `DTEL`, the lower-case spellings and the friendly names.
180
+
181
+ ### Known library defects, entered as served
182
+
183
+ The tables declare what the library sends, so two members that send a request
184
+ known or inferred to fail are entered as served rather than hidden:
185
+
186
+ - `transformation` `validate` posts to `/sap/bc/adt/xslt/validation`, which
187
+ answers `404` — a known-wrong address.
188
+ - `enhancement` `versions` for `ENHO/XHB` and `ENHS/XSB` addresses
189
+ `…/source/main/versions`, which these source-less codes lack — an inferred
190
+ `404`, unmeasured.
191
+
192
+ ### Migration
193
+
194
+ - Replace `AdtObjectType` with `AdtTypeCode` and `AdtSourceObjectType` with
195
+ `AdtSourceTypeCode` — or `AdtTypeCodeOf<V>` / `AdtTypeCodeWith<V, 'source'>`
196
+ where the variant is known — and pass upper-case codes: `'CLAS/OC'` for
197
+ `'class'`, `'FUGR/FF'` for `'functionmodule'`, `'DDLS/DF'` for `'view'`.
198
+ - Replace each dropped code with the one the releases list: `INTF/IF` →
199
+ `INTF/OI`; `STRU/DT`, `STRU/DS` → `TABL/DS`; `DOMA/DM` → `DOMA/DD`;
200
+ `BDEF/BD` → `BDEF/BDO`; `BIMP/BIM`, `BIMP/`, `BIMPL/` → `CLAS/OC`;
201
+ `DSFD/DSF` → `DSFD/SCF`; `DSFI/DSF` → `DSFI/SFI`; `SUSO/O` → `AUTH`;
202
+ `FUNC` → `FUGR/FF` for a module, `FUGR/F` for a group; `FUGR/FC` and `SCGR`
203
+ have no replacement the library serves.
204
+ - `TTYP/DF`, `TTYP/TT` and `TTYP/ST` become `TTYP/DA` **where any code is
205
+ taken** — `readObjectMetadata`, `supportsSourceCode`, a reference, a
206
+ where-used or search parameter. A table type has no source: `TTYP/DA` is no
207
+ `AdtSourceTypeCode`, so a `readObjectSource` or `getObjectSourceUri` call
208
+ on a table type has no replacement and goes — read its document with
209
+ `readObjectMetadata`.
210
+ - A contract whose API has a parent passes its field to the identifying atoms
211
+ — `IAdtReadable<IFunctionModuleConfig, R, 'functionGroupName'>` — and a
212
+ caller then names it. An `IObjectReference<'FUGR/FF'>` or
213
+ `IObjectReference<'FUGR/I'>` names `parentName`.
214
+ - Type a result's code read from an answer as `IAdtAnsweredObject`, and handle
215
+ `unknownType`.
216
+ - An implementation that declares `(config: Partial<TConfig>, …)` still
217
+ satisfies every atom; nothing an implementation sends changes.
218
+
10
219
  ## [20.2.0] - 2026-10-24
11
220
 
12
221
  ### Added
package/README.md CHANGED
@@ -5,12 +5,14 @@ ADT contracts: object operations, runtime analysis, execution, feeds and service
5
5
  ## TL;DR
6
6
 
7
7
  - **Only ADT.** The test is who imports this package: `@mcp-abap-adt/adt-clients` and whatever replaces its objects, and nobody else. Measured against every repository in development before 11.0.0 — the only others reaching in were `gcts-client` and `cloud-llm-hub`, for `IAbapConnection`, `IAbapRequestOptions` and `IAdtResponse`. Since 11.0.0 the first two come from `interfaces-adt-connection`; `IAdtResponse` is still here.
8
- - What it holds: ADT object operations for 31 object types, runtime analysis, execution, feeds, service bindings, `IAdtResponse` and the error codes. **The ABAP connection** — `IAbapConnection`, `IAdtWireResponse`, its capability atoms, `ITimeoutConfig` — is [`interfaces-adt-connection`](../interfaces-adt-connection) since 11.0.0, and is not re-exported here.
8
+ - What it holds: ADT object operations for 31 object types, the ADT type tables per release variant, runtime analysis, execution, feeds, service bindings, `IAdtResponse` and the error codes. **The ABAP connection** — `IAbapConnection`, `IAdtWireResponse`, its capability atoms, `ITimeoutConfig` — is [`interfaces-adt-connection`](../interfaces-adt-connection) since 11.0.0, and is not re-exported here.
9
9
  - **What left, and where.** Every HTTP header name, the HTTP frame and `HttpError` → [`interfaces-network`](../interfaces-network). Cloud ALM → [`interfaces-calm`](../interfaces-calm). `XmlNode` → [`interfaces-utils`](../interfaces-utils). Authentication in general — credentials, OAuth grants, tokens, interactive login, SAML assertions, `AUTH_TYPE_JWT`/`BASIC` → [`interfaces-auth`](../interfaces-auth). Everything naming SAP or BTP — `ISapConfig`, `SapAuthType`, `SapConnectionType`, `IConfig`, `IConnectionConfig`, `IAuthorizationConfig`, `ICertificateMaterialLoader`, `IServiceKeyStore`, `ISessionStore`, `ITokenProviderResult`, the two validation results and `AUTH_TYPE_XSUAA` with its union → [`interfaces-auth-sap`](../interfaces-auth-sap). Of those, `IConfig`, `IConnectionConfig`, `IServiceKeyStore`, `ISessionStore` and `ITokenProviderResult` moved on to [`interfaces-auth-broker`](../interfaces-auth-broker) in `interfaces-auth-sap` 2.0.0. `ISessionState` and `ISessionStorage` are deleted, not moved.
10
10
  - `IAdtWireResponse` extends `IHttpWireResponse` from `-network` and keeps the headers ADT sends (`sap-adt-location`, both spellings of `content-location`). It lives in `interfaces-adt-connection` since 11.0.0, name and shape unchanged.
11
11
  - Since 14.0.0 `IDebuggerIdentity` is a union by `debuggingMode` (required), `attach` takes the identity, `condition` is for line breakpoints only, and `IAbapDebugger` gains `TSettings` and five members. The CHANGELOG has the migration note.
12
12
  - Since 15.0.0 `skipCount` is gone from breakpoints (the server ignores it) and `clientId` pairs an answer row with its request. The CHANGELOG has the migration note.
13
13
  - Since 15.1.0 the plain class and program run take `debuggee` (`IDebuggeeIds`): the terminal id and IDE id a terminal-mode listener catches the run by.
14
+ - Since 22.0.0, the ABAP cloud table creates and changes no program or include (`403`, S_DEVELOP; see "Migrating to 22.0.0"), and `updateMetadata` is listed where it was measured. Beside that, additions only: intersecting helpers (`AdtCodeOf<V>`, `AdtCodeWith<V, Op>`, `AdtServingVariantsIn`, `AdtPerformingVariantsIn`; the default `AdtModernVariant` gets what both newer tables serve), utility code tables per variant (`ADT_UTILITY_CODES_*`: the group-only `VIEW/DV`, `DEVC/K` in a modern group activation and in 7.40's node structure), group references per operation with the typed atoms `IAdtTypedGroupLifecycle` and `IAdtTypedWhereUsed`, and `IAdtTypeStructure` with its `IUtilResults.typeStructure` slot. See "Intersections, group-only codes and group references".
15
+ - Since 21.0.0 the object type codes are the library's own tables — `ADT_TYPES_ONPREM` (S/4HANA 2025), `ADT_TYPES_CLOUD` (ABAP cloud), `ADT_TYPES_BASIS_740` (SAP_BASIS 7.40 SP04), keyed by API — and every code in a contract is an `AdtTypeCode` drawn from them. `AdtObjectTypeLower`, `AdtObjectType`, `AdtSourceObjectTypeLower` and `AdtSourceObjectType` are removed, and with them the codes no release lists. An identifying atom takes the parent's field as its last type parameter (`TParent`, default `never`, which leaves the config `Partial<TConfig>` as before), and `IObjectReference<C>` requires `parentName` for a code with a parent. A code read from an answer is an `IAdtAnsweredObject`. See "The ADT type tables" and "Migrating to 21.0.0".
14
16
  - Since 20.2.0 every object's result-set contract (`IClassResults`, `IProgramResults`, … 30 in all, `IMessageClassMessageResults<TRead, TWritten, TDeleted>` among them) and `IServiceBindingPublicationConfig` are declared here, in the object's own `IAdtX.ts`: the slot map an implementation is constructed with, each slot an `IResultStrategy<unknown>`. A consumer composes its client contract from these and the atoms. Additions only.
15
17
  - Since 20.1.0 `IAdtObjectProperties` reads one repository object's properties from `/informationsystem/objectproperties/values?uri=`, any object uri (a transaction by its `vit` workbench uri); its own atom, not part of `IAdtInformationSystem`.
16
18
  - Since 20.0.0 `IAdtClientOptions` has no `enableAcceptCorrection`: correcting a refused format is the consumer's own. See "Migrating to 20.0.0".
@@ -30,26 +32,181 @@ npm install @mcp-abap-adt/interfaces-adt
30
32
 
31
33
  | directory | files | what |
32
34
  |---|---|---|
33
- | `adt/` | 39 | the object contracts: capability atoms, the object types, `IAdtResponse`, `IAdtError`, the error codes, the transport request's object list |
35
+ | `adt/` | 42 | the object contracts: capability atoms, the object types, the ADT type tables and their entry shape, `IAdtResponse`, `IAdtError`, the error codes, the transport request's object list |
34
36
  | `runtime/` | 14 | runtime analysis: the debuggers (`IAbapDebugger`, `IAmdpDebugger`) and `IMemorySnapshots`, `IProfiler`, the trace contracts (`ITraceListing`/`ITraceReading`, `ICrossTrace`, `ISt05Trace`), `IApplicationLog`, `IAtcLog` and the ATC run (`IAtcRunOptions`, `IAtcFindings`), `IDdicActivation`, `IGatewayErrorLog`, `IRuntimeDumps`, `ISystemMessages` |
35
37
  | `execution/` | 3 | class and program execution, with profiling |
36
38
  | `feeds/` | 2 | the ADT feed contracts |
37
39
  | `service/` | 1 | service definitions and bindings |
38
40
  | `shared/` | 1 | what more than one object type needs |
39
41
 
40
- Six directories, all ADT. `connection/` left for `interfaces-adt-connection` in 11.0.0. `sap/`, `auth/`, `token/`, `session/`, `serviceKey/`, `store/`, `validation/` and `Headers.ts` were here until 9.0.0 and are listed above under what left; `__typechecks__/` holds 24 files that compile shapes this contract must and must not accept, and ships in no tarball.
42
+ Six directories, all ADT. `connection/` left for `interfaces-adt-connection` in 11.0.0. `sap/`, `auth/`, `token/`, `session/`, `serviceKey/`, `store/`, `validation/` and `Headers.ts` were here until 9.0.0 and are listed above under what left; `__typechecks__/` holds 30 files that compile shapes this contract must and must not accept, and ships in no tarball.
41
43
 
42
44
  The contract rules — what a member answers, how a strategy is supplied, how a contract is built — are in [`docs/architecture/ARCHITECTURE.md`](../../docs/architecture/ARCHITECTURE.md). Domain-by-domain documentation with examples used to sit in the facade's README; the facade is deleted, and each package documents its own contracts.
43
45
 
44
46
  **There is no facade to stay compatible with.** It was pinned to its 44.0.0 surface in both directions — nothing from that release could disappear from it and nothing could appear without being written down — and `tools/check-surface.js`, `surface-44.0.0.txt`, `baseline-44.0.0.json` and `surface-added.txt` existed to enforce exactly that. The facade is deleted in its 52.0.0 (decision 34), so the property is gone along with the files that proved it; git holds them. What `check-surface.js` still asks is the half that never depended on it: is each symbol declared in the package `tools/package-map.json` assigns it to.
45
47
 
48
+ ## The ADT type tables
49
+
50
+ What the library serves, per release variant, is declared here as three `as
51
+ const` tables — constants, written by hand:
52
+
53
+ | table | variant | release |
54
+ |---|---|---|
55
+ | `ADT_TYPES_ONPREM` | `'onprem'` | S/4HANA 2025 on-premise |
56
+ | `ADT_TYPES_CLOUD` | `'cloud'` | ABAP cloud |
57
+ | `ADT_TYPES_BASIS_740` | `'basis740'` | SAP_BASIS 7.40 SP04 |
58
+
59
+ **Keyed by API, not by code.** The key is the client's factory name (`class`
60
+ for `getClass()`, `functionModule`, `request` for `getRequest()`), because one
61
+ code serves two APIs (`CLAS/OC`: `class` and `behaviorImplementation`;
62
+ `TABL/DS`: `structure` and `appendStructure`) and one API several codes
63
+ (`enhancement`: `ENHO/XHH`, `ENHO/XHB`, `ENHS/XSB`). An entry holds:
64
+
65
+ - `kind` — the object's kind in the tools' one vocabulary (`function_module`);
66
+ two APIs on one code share it;
67
+ - `collection` — the ADT collection its resource lives in, the parent's for an
68
+ API addressed under a parent;
69
+ - `codes` — for each code: `parent` (the parent API, or `null`),
70
+ `nameMaxLength`, `operations` and `evidence`, the corpus case of the
71
+ release's `typestructure` answer that lists the code
72
+ (`system-description-basis-740--07-typestructure`); and, where a code lives
73
+ elsewhere than its API, its own `collection` — the enhancement codes under
74
+ `/sap/bc/adt/enhancements/enhoxhh`, `/enhoxhb` and `/enhsxsb`.
75
+
76
+ The local class includes and the transport request have no code the library
77
+ sends: their entries have `codes: {}`, and their `parent`, `operations` and
78
+ `evidence` on the entry — the case that lists the parent's code, or for the
79
+ request the release's `typestructure` case. A coded entry names at least one
80
+ code: `IAdtTypeTables` takes each table as `AdtCheckedTable<T>`, which refuses
81
+ an empty `codes` that `satisfies` cannot see.
82
+
83
+ **Operations** come from one closed vocabulary, `AdtOperation`: `create`,
84
+ `read`, `source`, `readMetadata`, `update`, `updateMetadata`, `lock`,
85
+ `unlock`, `activate`, `check`, `validate`, `versions`, `deletionCheck`,
86
+ `delete`, `transport`; the families of one API (`readEnhancementElements`,
87
+ `readEnhancementOptions`, `activateTestClasses`, `checkCdsTestDoubles`, the
88
+ feature toggle's `switchOn`, `switchOff`, `getRuntimeState`, `checkState`, the
89
+ service binding's `getServiceBindingTypes`, `getServiceGroup`, the transport
90
+ request's `list` … `changeTaskType`); `run` and `profile` for the executors;
91
+ and `unitTestRun`, `unitTestRunSync`, `unitTestStatus`, `unitTestResult` for
92
+ the ABAP Unit runners' four members, which 7.40 serves apart. `source` says the object has a source the
93
+ library reads; `AdtSourceTypeCode` is drawn from it.
94
+
95
+ **What is not in a table is not served.** An API whose every member the 7.40
96
+ client refuses is absent from `ADT_TYPES_BASIS_740`, and an operation it
97
+ refuses is absent from its code — 7.40 has no `deletionCheck`, no `transport`,
98
+ no `run`. On ABAP cloud a program and an include list no operation that
99
+ changes an object, since the cloud refuses to create either. The entry shape (`AdtApiTable<R>`) refuses a misspelt field, an
100
+ operation outside the vocabulary, an API with no factory and another release's
101
+ evidence at compile time.
102
+
103
+ **Derived types**, all from the tables:
104
+
105
+ | type | what |
106
+ |---|---|
107
+ | `AdtVariant` | `'onprem' \| 'cloud' \| 'basis740'` |
108
+ | `AdtApi<V>` | the APIs of variant `V` |
109
+ | `AdtTypeCode` | every code of any table |
110
+ | `AdtTypeCodeOf<V>` | the codes of variant `V` |
111
+ | `AdtApiWith<V, Op>` | the APIs of `V` one code of which performs every operation of `Op` (`AdtApiWithIn<T, Op>` over any table) |
112
+ | `AdtTypeCodeWith<V, Op>` | the codes of `V` whose facts list `Op` |
113
+ | `AdtObjectKind` | every kind |
114
+ | `AdtSourceTypeCode` | the codes with `source` |
115
+ | `AdtParentedTypeCode` | the codes with a parent API: `FUGR/FF`, `FUGR/I` |
116
+
117
+ A map a consumer keeps over the codes is typed by them, and the compiler then
118
+ asks for every code and refuses any other:
119
+
120
+ ```ts
121
+ const label: { readonly [C in AdtTypeCode]: string } = { 'CLAS/OC': 'Class', /* … every code */ };
122
+ ```
123
+
124
+ **Proved against the systems elsewhere.** This package holds no code, so it
125
+ holds no test against the releases: the conformance check in
126
+ `@mcp-abap-adt/adt-clients` reads each release's recorded `typestructure`,
127
+ `discovery` and, on the newer releases, `urimapper` answers. It fails on a code
128
+ not listed, a parent or a name length that disagrees, a collection not
129
+ advertised, and an address built for a sample object that differs from the
130
+ `urimapper` answer for it. It holds the capabilities too: `run` on a code that
131
+ does not list `EXECUTE`, or `profile` without `PROFILE`, is a conflict; a
132
+ `create` on a code without `CREATE` is listed apart, since ADT creates those
133
+ through their own collection; and a code listing `CREATE` that no entry
134
+ creates goes into the coverage. `src/__typechecks__/` holds the tables
135
+ recorded cell for cell — per variant, API and code, the parent and the exact
136
+ set of operations — as an exact equality, so a table edit is made twice, on
137
+ purpose.
138
+
139
+ **An answered code.** A code read from an ADT answer is an
140
+ `IAdtAnsweredObject`: `{ type: AdtTypeCode }` when the tables know it,
141
+ `{ unknownType: string }` with the text as sent when they do not. The two are
142
+ exclusive.
143
+
144
+ **Parents.** The atoms that identify an object take the parent's field as
145
+ their last type parameter, `TParent extends keyof TConfig = never`, and their
146
+ `config` is `AdtObjectIdentity<TConfig, TParent>`: with `never` that is
147
+ `Partial<TConfig>` itself — the same type as before 21.0.0, so a contract
148
+ written then, or code generic in `TConfig`, is unchanged — and otherwise every
149
+ field optional but `TParent`, which is required. A contract whose API has a
150
+ parent passes it: `functionGroupName` for a function module and a function
151
+ include, `className` for a local class include and a message class message.
152
+
153
+ ```ts
154
+ type ModuleRead = IAdtReadable<IFunctionModuleConfig, string, 'functionGroupName'>;
155
+ // read({ functionModuleName }) does not compile; read({ functionGroupName, functionModuleName }) does
156
+ ```
157
+
158
+ `IObjectReference<C extends AdtTypeCode = AdtTypeCode>` requires `parentName`
159
+ when `[C] extends [AdtParentedTypeCode]` — `IObjectReference<'FUGR/FF'>` —
160
+ and leaves it optional otherwise, the default included, so a reference built
161
+ from a code typed `AdtTypeCode` compiles and an interface can extend it.
162
+
163
+ ### Intersections, group-only codes and group references (22.0.0)
164
+
165
+ **A union of variants.** `AdtTypeCodeOf<V>`, `AdtTypeCodeWith<V, Op>` and
166
+ `AdtApiWith<V, Op>` read a union of variants as one union table: the APIs all
167
+ of them serve, and for those the codes and operations any of them lists. The
168
+ intersecting helpers ask every variant: `AdtCodeOf<V>` and `AdtCodeWith<V, Op>`
169
+ are the codes every variant of `V` lists (with `Op`), and
170
+ `AdtServingVariantsIn<IAdtTypeTables, A>` and
171
+ `AdtPerformingVariantsIn<IAdtTypeTables, A, Op>` name the variants that serve
172
+ an API or perform an operation on one of its codes — what a client's gates
173
+ need. For `AdtModernVariant`, `'onprem' | 'cloud'`, that is what both tables
174
+ serve. `AdtCodeOfIn` and `AdtCodeWithIn` take any set of tables.
175
+
176
+ **Utility codes.** `ADT_UTILITY_CODES_ONPREM`, `_CLOUD` and `_BASIS_740` hold
177
+ what `getUtils()` takes beyond the API tables, with its operations
178
+ (`AdtUtilityOperation`), whether they were measured, and the evidence:
179
+
180
+ | code | where | operations | measured |
181
+ |---|---|---|---|
182
+ | `VIEW/DV` | every release, `/sap/bc/adt/ddic/views` | group activation, group deletion, where-used | no |
183
+ | `DEVC/K` | S/4HANA 2025, ABAP cloud | group activation | no |
184
+ | `DEVC/K` | SAP_BASIS 7.40 SP04 | node structure | yes |
185
+
186
+ `VIEW/DV` is a **group-only code** (`AdtGroupOnlyCode`): no API serves it, so
187
+ it is no `AdtTypeCode`. `IObjectReference<'VIEW/DV'>` and
188
+ `IGetWhereUsedParams<'VIEW/DV'>` name it; the defaults do not.
189
+
190
+ **Group references.** `IAdtGroupActivationReference<V>`,
191
+ `IAdtGroupDeletionCheckReference<V>`, `IAdtGroupDeletionReference<V>` and
192
+ `IAdtWhereUsedParamsOf<V>` take only the codes their operation sends on `V`
193
+ — no message class in an activation, no package in a 7.40 one, no function
194
+ include in where-used — and require `parentName` for `FUGR/FF` and `FUGR/I`.
195
+ `IAdtTypedGroupLifecycle` and `IAdtTypedWhereUsed` declare the members over
196
+ them, beside `IAdtGroupLifecycle` and `IAdtWhereUsed`: a contract composed of
197
+ both takes typed references and the 21.0.0 `IObjectReference[]` alike.
198
+
199
+ **The type structure.** `IAdtTypeStructure.getTypeStructure({ headers })`
200
+ posts to `/sap/bc/adt/repository/typestructure`; its reading is
201
+ `IUtilResults.typeStructure`, optional so a 21.0.0 set is still one.
202
+
46
203
  ## Enhancements and their hosts
47
204
 
48
205
  `EnhancementType` accepts `enhoxhb` (BAdI implementation, ENHO/XHB), `enhoxhh`
49
206
  (source code plugin, ENHO/XHH), and `enhsxsb` (BAdI enhancement spot, ENHS/XSB).
50
207
  The ABAP Cloud trial refuses the `enhoxhh` collection (403 on create and read;
51
208
  no content type in its discovery). Class enhancements (`enhoxh`) and plain
52
- spots (`enhsxs`) answered 500 on reads on E19 (2026-10-15) and on premise +
209
+ spots (`enhsxs`) answered 500 on reads on S/4HANA on-premise (2026-10-15) and on premise +
53
210
  trial in mcp-abap-adt `5046d8a6` (2026-10-02), which also measured Eclipse
54
211
  opening them in SAP GUI. The trial discovery lists no content type for either.
55
212
  Callers migrating from 16.0 must remove those calls; the removed subtypes now
@@ -70,7 +227,7 @@ names used to create plugins.
70
227
  atom for an include's elements and options, with the same two members. Both
71
228
  reads take optional `context` naming the include's main program (`SAPLSVIM`
72
229
  for an include of function group SVIM). Without it, both reads answered 400
73
- ED/258 "No main program for include … found" (E19, 2026-10-15). Context stays
230
+ ED/258 "No main program for include … found" (S/4HANA on-premise, 2026-10-15). Context stays
74
231
  optional because an include with a single main program is unmeasured.
75
232
  Both atoms accept per-call `analyse` and return `IAdtResponse`.
76
233
 
@@ -116,6 +273,67 @@ The field is on each member's own options, not on `IAdtAnalyseOptions` or
116
273
  `IAdtOperationOptions`. `src/__typechecks__/headersOnEveryMember.ts` holds this
117
274
  for every member and every overload.
118
275
 
276
+ ## Migrating to 22.0.0
277
+
278
+ - **ABAP cloud: no program or include of one's own.** `ADT_TYPES_CLOUD` no
279
+ longer lists `create`, `update`, `lock`, `unlock`, `activate`, `validate`,
280
+ `deletionCheck` or `delete` for `PROG/P` and `PROG/I`: the cloud refuses to
281
+ create either (`403`, S_DEVELOP). Code gated on the cloud variant, or on
282
+ the intersecting helpers over `AdtModernVariant` (`AdtCodeWith`,
283
+ `AdtPerformingVariantsIn` — what both newer tables serve), that creates or
284
+ changes a program or an include stops compiling; on ABAP cloud the system
285
+ would have refused it. The union helpers (`AdtApiWith`, `AdtTypeCodeWith`)
286
+ over `AdtModernVariant` still name the program, since on-premise creates
287
+ one. Reading, checking and versioning a delivered program
288
+ compile as before. A function include (`FUGR/I`) is unchanged.
289
+ - Nothing else breaks: every other change is an addition (see the
290
+ CHANGELOG).
291
+
292
+ ## Migrating to 21.0.0
293
+
294
+ Every break is a type error; nothing a correct call sends changes.
295
+
296
+ - **The four unions are gone.** Replace `AdtObjectType` with `AdtTypeCode` and
297
+ `AdtSourceObjectType` with `AdtSourceTypeCode`, or with the variant's own
298
+ `AdtTypeCodeOf<V>` / `AdtTypeCodeWith<V, 'source'>` where the variant is
299
+ known. The lower-case spellings and the friendly names (`'class'`,
300
+ `'functionmodule'`, `'view'`, …) are no codes: pass the upper-case code
301
+ (`'CLAS/OC'`, `'FUGR/FF'`, `'DDLS/DF'`).
302
+ - **The codes no release lists do not compile.** `INTF/IF` is `INTF/OI`;
303
+ `STRU/DT` and `STRU/DS` are `TABL/DS`; `DOMA/DM` is `DOMA/DD`; `BDEF/BD` is
304
+ `BDEF/BDO`; `BIMP/BIM`, `BIMP/` and `BIMPL/` are `CLAS/OC`; `DSFD/DSF` is
305
+ `DSFD/SCF`, `DSFI/DSF` is `DSFI/SFI`, `SUSO/O` is `AUTH`; a function module
306
+ is `FUGR/FF` and a function group `FUGR/F`, so `FUNC` and `FUGR/FC` go; bare
307
+ `SCGR` and the other bare codes (`FUGR`, `DTEL`) are none — `AUTH` is the
308
+ one bare code a table holds.
309
+ - **A table type is `TTYP/DA` where any code is taken.** `TTYP/DF`, `TTYP/TT`
310
+ and `TTYP/ST` become `TTYP/DA` in `readObjectMetadata`, `supportsSourceCode`,
311
+ a reference, a where-used or a search parameter. A table type has no source,
312
+ so `TTYP/DA` is no `AdtSourceTypeCode`: a `readObjectSource` or
313
+ `getObjectSourceUri` of a table type has no replacement — read its document
314
+ with `readObjectMetadata`.
315
+ - **Every code parameter takes these codes:** `IObjectReference.type`,
316
+ `readObjectSource`, `getObjectSourceUri` (`AdtSourceTypeCode`),
317
+ `readObjectMetadata`, `supportsSourceCode`, `fetchNodeStructure`'s
318
+ `parentType`, `getObjectStructure`'s `objectType`, the where-used
319
+ parameters' `object_type` and `ISearchObjectsParams.objectType`
320
+ (`AdtTypeCode`).
321
+ - **A parent is named by the contract.** A contract composing the identifying
322
+ atoms for a function module or a function include passes
323
+ `'functionGroupName'` as their `TParent`, for a local class include or a
324
+ message class message `'className'`; a caller of that contract then names
325
+ the parent. A contract that passes nothing is unchanged. An
326
+ `IObjectReference<'FUGR/FF'>` or `IObjectReference<'FUGR/I'>` names
327
+ `parentName`.
328
+ - **An implementation** declaring an identifying member as
329
+ `(config: Partial<TConfig>, …)` still satisfies the atom — it accepts more.
330
+ - **A result** that carries a code read from an answer is typed
331
+ `IAdtAnsweredObject`: switch on `type`, and handle `unknownType` for a code
332
+ the tables do not hold.
333
+ - **The tables are new.** `ADT_TYPES_ONPREM`, `ADT_TYPES_CLOUD`,
334
+ `ADT_TYPES_BASIS_740` and the types derived from them are additions; see "The
335
+ ADT type tables".
336
+
119
337
  ## Migrating to 20.0.0
120
338
 
121
339
  `IAdtClientOptions.enableAcceptCorrection` is removed, so code that sets it