@mcp-abap-adt/adt-clients 23.0.0 → 23.0.1

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/README.md CHANGED
@@ -940,6 +940,7 @@ member uses it on your behalf; `create()` and `update()` issue one request each.
940
940
  - **[Documentation index](docs/README.md)**
941
941
  - **[Migrating to 23.0.0](docs/usage/MIGRATION-23.md)** – the replacing code for every removed behaviour
942
942
  - **[Client API reference](docs/usage/CLIENT_API_REFERENCE.md)** – every client, member and result set
943
+ - **[Workarounds](docs/usage/WORKAROUNDS.md)** – SAP-side behaviour a consumer has to work around, with the evidence for each
943
944
  - **[Architecture](docs/architecture/ARCHITECTURE.md)** – package structure and design decisions
944
945
  - **[Decisions](docs/architecture/DECISIONS.md)** – the choices that could have gone the other way, and why
945
946
  - **[Operation Delays](docs/usage/OPERATION_DELAYS.md)** – configurable delays for SAP operations in tests
@@ -7,7 +7,8 @@
7
7
  * Every member answers `IAdtResponse<T>`, where T is what the result set given
8
8
  * at construction makes of that endpoint's answer.
9
9
  *
10
- * Operation chains:
10
+ * The sequences Eclipse follows — each step is its own member here, one
11
+ * request each, and the caller composes them:
11
12
  * - Create: validate → create → check
12
13
  * - Update: lock → check → update → unlock
13
14
  * - Delete: check(deletion) → delete
@@ -38,12 +39,16 @@ export declare class AdtPackage<R extends IPackageResults = typeof packageDocume
38
39
  /** Validate the package's configuration before creating it. */
39
40
  validate<E extends IAdtError = IAdtError>(config: Partial<IPackageConfig>, options?: IAdtOperationOptions<E>): Promise<IAdtResponse<ReturnType<R['validation']>, E>>;
40
41
  /**
41
- * Create the package: validate → create → check.
42
+ * Create the package: one POST. Eclipse validates before it and runs a
43
+ * check after it; both are members of their own here.
42
44
  *
43
- * The check is a checkrun on the new object, the way Eclipse does it, not a
45
+ * That check is a checkrun on the new object, the way Eclipse does it, not a
44
46
  * second call to the validation endpoint — captured 2026-08-31, which
45
47
  * validates, creates, then posts `/sap/bc/adt/checkruns` on the created
46
48
  * package before it is ever locked.
49
+ *
50
+ * A package can be saved only once per ABAP session: PAK/058 — see
51
+ * docs/usage/WORKAROUNDS.md. Over RFC the create counts as that save.
47
52
  */
48
53
  create<E extends IAdtError = IAdtError>(config: Omit<IPackageConfig, 'source'> & {
49
54
  source?: never;
@@ -57,40 +62,8 @@ export declare class AdtPackage<R extends IPackageResults = typeof packageDocume
57
62
  /**
58
63
  * Update the package's metadata.
59
64
  *
60
- * **Package update over RFC fails**, and not for the reason the old comment
61
- * gave. It said the PUT "cannot access the PAK lock created by the LOCK
62
- * call". Measured 2026-08-31, that is wrong: the PUT reads the
63
- * parameter, validates the handle, and accepts ours. Four answers from the
64
- * same endpoint, same session, same package, over rfc:
65
- *
66
- * PUT with no lockHandle 400 ExceptionParameterNotFound
67
- * SADT_RESOURCE/017 "Parameter lockHandle
68
- * could not be found"
69
- * PUT with a made-up handle 423 ExceptionResourceInvalidLockHandle
70
- * SADT_RESOURCE/026 "is not locked
71
- * (invalid lock handle: DEADBEEF…)"
72
- * a second _action=LOCK 403 ExceptionResourceNoAccess
73
- * EU/510 "User … is currently editing"
74
- * PUT with OUR handle 400 ExceptionResourceAlreadyExists
75
- * PAK/058 "Package … is already locked"
76
- *
77
- * The first two say the lock handle is read and checked, and ours passes both
78
- * checks — a PUT that could not see the lock would answer 423, exactly as the
79
- * made-up handle does. The third says the ADT resource lock is ours and is
80
- * recognised as ours.
81
- *
82
- * So the refusal comes from a layer past the ADT lock. PAK is the package
83
- * framework's own message class, and PAK/058 is what it answers when its own
84
- * lock cannot be taken. That state does not survive the hop between internal
85
- * contexts that SADT_REST_RFC_ENDPOINT makes per call; the enqueue handle
86
- * does, which is why UNLOCK afterwards answers 200.
87
- *
88
- * It is packages alone. In the same rfc run 31 other updates pass — classes,
89
- * interfaces, domains, data elements, tables, structures, DDL, behaviour
90
- * definitions — and no PAK message appears anywhere else in the log. Not
91
- * critical for release: http is the primary transport for modern on-premise
92
- * systems, and rfc exists for BASIS < 7.50, where package CRUD is not
93
- * supported regardless.
65
+ * A package can be saved only once per ABAP session: PAK/058 — see
66
+ * docs/usage/WORKAROUNDS.md. Opening a new session is the caller's.
94
67
  *
95
68
  * **The whole content, every time.** This is a replace, never a merge. Read
96
69
  * what the object holds, change what you mean to change, and pass the result:
@@ -108,14 +81,9 @@ export declare class AdtPackage<R extends IPackageResults = typeof packageDocume
108
81
  /**
109
82
  * Delete the package.
110
83
  *
111
- * A package this session has just updated cannot be deleted by this session —
112
- * measured 2026-08-31: `deletion/check` answers `isDeletable="true"`
113
- * while `deletion/delete` answers HTTP 200 carrying `isDeleted="false"` and
114
- * PAK/058, "package is already locked", even though the UNLOCK moments
115
- * earlier answered 200. It is not a delay: retried for 30 seconds inside the
116
- * run it never succeeds, and the same request one second after the run ends
117
- * deletes it on the first attempt. The PAK lock belongs to the ABAP session
118
- * and goes with it.
84
+ * A package can be saved only once per ABAP session: PAK/058 — see
85
+ * docs/usage/WORKAROUNDS.md. A delete from a session that saved the package
86
+ * is refused; from a new session it succeeds.
119
87
  *
120
88
  * The answer is a 200 either way, and `isDeleted="false"` is in its body: a
121
89
  * caller who wants that read as a failure passes `analyseDeletion` (from
@@ -1 +1 @@
1
- {"version":3,"file":"AdtPackage.d.ts","sourceRoot":"","sources":["../../../src/core/package/AdtPackage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AdtPackage.d.ts","sourceRoot":"","sources":["../../../src/core/package/AdtPackage.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,8 @@
8
8
  * Every member answers `IAdtResponse<T>`, where T is what the result set given
9
9
  * at construction makes of that endpoint's answer.
10
10
  *
11
- * Operation chains:
11
+ * The sequences Eclipse follows — each step is its own member here, one
12
+ * request each, and the caller composes them:
12
13
  * - Create: validate → create → check
13
14
  * - Update: lock → check → update → unlock
14
15
  * - Delete: check(deletion) → delete
@@ -76,12 +77,16 @@ class AdtPackage {
76
77
  }), this.results.validation, options?.analyse);
77
78
  }
78
79
  /**
79
- * Create the package: validate → create → check.
80
+ * Create the package: one POST. Eclipse validates before it and runs a
81
+ * check after it; both are members of their own here.
80
82
  *
81
- * The check is a checkrun on the new object, the way Eclipse does it, not a
83
+ * That check is a checkrun on the new object, the way Eclipse does it, not a
82
84
  * second call to the validation endpoint — captured 2026-08-31, which
83
85
  * validates, creates, then posts `/sap/bc/adt/checkruns` on the created
84
86
  * package before it is ever locked.
87
+ *
88
+ * A package can be saved only once per ABAP session: PAK/058 — see
89
+ * docs/usage/WORKAROUNDS.md. Over RFC the create counts as that save.
85
90
  */
86
91
  async create(config, options) {
87
92
  // **No guard here, unlike every other create.**
@@ -128,40 +133,8 @@ class AdtPackage {
128
133
  /**
129
134
  * Update the package's metadata.
130
135
  *
131
- * **Package update over RFC fails**, and not for the reason the old comment
132
- * gave. It said the PUT "cannot access the PAK lock created by the LOCK
133
- * call". Measured 2026-08-31, that is wrong: the PUT reads the
134
- * parameter, validates the handle, and accepts ours. Four answers from the
135
- * same endpoint, same session, same package, over rfc:
136
- *
137
- * PUT with no lockHandle 400 ExceptionParameterNotFound
138
- * SADT_RESOURCE/017 "Parameter lockHandle
139
- * could not be found"
140
- * PUT with a made-up handle 423 ExceptionResourceInvalidLockHandle
141
- * SADT_RESOURCE/026 "is not locked
142
- * (invalid lock handle: DEADBEEF…)"
143
- * a second _action=LOCK 403 ExceptionResourceNoAccess
144
- * EU/510 "User … is currently editing"
145
- * PUT with OUR handle 400 ExceptionResourceAlreadyExists
146
- * PAK/058 "Package … is already locked"
147
- *
148
- * The first two say the lock handle is read and checked, and ours passes both
149
- * checks — a PUT that could not see the lock would answer 423, exactly as the
150
- * made-up handle does. The third says the ADT resource lock is ours and is
151
- * recognised as ours.
152
- *
153
- * So the refusal comes from a layer past the ADT lock. PAK is the package
154
- * framework's own message class, and PAK/058 is what it answers when its own
155
- * lock cannot be taken. That state does not survive the hop between internal
156
- * contexts that SADT_REST_RFC_ENDPOINT makes per call; the enqueue handle
157
- * does, which is why UNLOCK afterwards answers 200.
158
- *
159
- * It is packages alone. In the same rfc run 31 other updates pass — classes,
160
- * interfaces, domains, data elements, tables, structures, DDL, behaviour
161
- * definitions — and no PAK message appears anywhere else in the log. Not
162
- * critical for release: http is the primary transport for modern on-premise
163
- * systems, and rfc exists for BASIS < 7.50, where package CRUD is not
164
- * supported regardless.
136
+ * A package can be saved only once per ABAP session: PAK/058 — see
137
+ * docs/usage/WORKAROUNDS.md. Opening a new session is the caller's.
165
138
  *
166
139
  * **The whole content, every time.** This is a replace, never a merge. Read
167
140
  * what the object holds, change what you mean to change, and pass the result:
@@ -215,14 +188,9 @@ class AdtPackage {
215
188
  /**
216
189
  * Delete the package.
217
190
  *
218
- * A package this session has just updated cannot be deleted by this session —
219
- * measured 2026-08-31: `deletion/check` answers `isDeletable="true"`
220
- * while `deletion/delete` answers HTTP 200 carrying `isDeleted="false"` and
221
- * PAK/058, "package is already locked", even though the UNLOCK moments
222
- * earlier answered 200. It is not a delay: retried for 30 seconds inside the
223
- * run it never succeeds, and the same request one second after the run ends
224
- * deletes it on the first attempt. The PAK lock belongs to the ABAP session
225
- * and goes with it.
191
+ * A package can be saved only once per ABAP session: PAK/058 — see
192
+ * docs/usage/WORKAROUNDS.md. A delete from a session that saved the package
193
+ * is refused; from a new session it succeeds.
226
194
  *
227
195
  * The answer is a 200 either way, and `isDeleted="false"` is in its body: a
228
196
  * caller who wants that read as a failure passes `analyseDeletion` (from
@@ -41,10 +41,9 @@ export type PackageValidationResult = string;
41
41
  /**
42
42
  * What the deletion answers.
43
43
  *
44
- * Measured 2026-08-31: a package this session has just updated cannot be
45
- * deleted by this session. `deletion/check` answers `isDeletable="true"` while
46
- * `deletion/delete` answers **200** carrying `isDeleted="false"` and PAK/058,
47
- * "package is already locked" — so the document, not the status, is the verdict.
44
+ * A refusal arrives as **200** carrying `isDeleted="false"`, so the document,
45
+ * not the status, is the verdict. A package can be saved only once per ABAP
46
+ * session: PAK/058 — see docs/usage/WORKAROUNDS.md.
48
47
  */
49
48
  export type PackageDeletionResult = string;
50
49
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/package/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAIpE,YAAY,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AAEnC;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AAErC;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAExC;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE7C;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEtC,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACnD,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC7C,0DAA0D;IAC1D,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;CAClD;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;CAUF,CAAC;AAE5B;;;;;;;;;GASG;AAEH,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/package/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAIpE,YAAY,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC;AAEnC;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AAErC;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAExC;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEtC,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC9C,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC5C,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IACnD,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;IAC7C,0DAA0D;IAC1D,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;CAClD;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;CAUF,CAAC;AAE5B;;;;;;;;;GASG;AAEH,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B"}
@@ -22,10 +22,10 @@ const timeouts_1 = require("../../utils/timeouts");
22
22
  */
23
23
  async function updatePackage(connection, params, document, lockHandle) {
24
24
  const encodedName = (0, internalUtils_1.encodeSapObjectName)(params.package_name.toLowerCase());
25
- const corrNrParam = params.transport_request
26
- ? `&corrNr=${params.transport_request}`
27
- : '';
28
- const url = `/sap/bc/adt/packages/${encodedName}?lockHandle=${encodeURIComponent(lockHandle)}${corrNrParam}`;
25
+ // `writeQuery`, like every other write: interpolating the handle directly
26
+ // sent `?lockHandle=undefined` when there was none, and SAP answered a
27
+ // refusal about a handle nobody passed.
28
+ const url = `/sap/bc/adt/packages/${encodedName}${(0, internalUtils_1.writeQuery)(lockHandle, params.transport_request)}`;
29
29
  return connection.makeAdtRequest({
30
30
  url,
31
31
  method: 'PUT',
package/docs/README.md CHANGED
@@ -25,6 +25,7 @@ Complete documentation for the `@mcp-abap-adt/adt-clients` package.
25
25
  - [**STATEFUL_SESSION_GUIDE.md**](usage/STATEFUL_SESSION_GUIDE.md) - Guide for stateful session management
26
26
  - [**CHECK_LOCAL_TEST_CLASS.md**](usage/CHECK_LOCAL_TEST_CLASS.md) - Guide for validating ABAP Unit test classes
27
27
  - [**DEBUG.md**](usage/DEBUG.md) - Debugging and troubleshooting guide
28
+ - [**WORKAROUNDS.md**](usage/WORKAROUNDS.md) — SAP-side behaviour a consumer has to work around (PAK/058, refusals inside a `200`, empty `200` reads, activation flags, transport search, …): symptom, cause, rule, workaround and evidence for each
28
29
  - [TROUBLESHOOTING.md](usage/TROUBLESHOOTING.md) — what ADT answers when it refuses, and why the message is often accurate about the wrong thing
29
30
  - [**OPERATION_DELAYS.md**](usage/OPERATION_DELAYS.md) - Detailed guide on operation delays and timing
30
31
  - [**OPERATION_DELAYS_SUMMARY.md**](usage/OPERATION_DELAYS_SUMMARY.md) - Quick reference for operation delays
@@ -54,6 +55,8 @@ docs/
54
55
  │ ├── OBJECT_LIFECYCLE.md # The create → … → activate flow and its exceptions
55
56
  │ ├── CLIENT_API_REFERENCE.md # Client API reference
56
57
  │ ├── STATEFUL_SESSION_GUIDE.md # Session management
58
+ │ ├── WORKAROUNDS.md # SAP-side behaviour and its workarounds
59
+ │ ├── TROUBLESHOOTING.md # Refusals that name the wrong cause
57
60
  │ ├── CHECK_LOCAL_TEST_CLASS.md # Local test class validation
58
61
  │ ├── DEBUG.md # Debugging guide
59
62
  │ ├── OPERATION_DELAYS.md # Operation delays (detailed)
@@ -126,6 +126,8 @@ caller who asks for those shapes rather than the document.
126
126
  - [`MIGRATION-23.md`](MIGRATION-23.md) — the readings and verdicts that moved
127
127
  to `@mcp-abap-adt/adt-strategies` in 23.0.0
128
128
  - [`MIGRATION-19.md`](MIGRATION-19.md) — what moved to the consumer in 19.0.0
129
+ - [`WORKAROUNDS.md`](WORKAROUNDS.md) — the SAP-side behaviour behind several of
130
+ these answers, and what a consumer does about it
129
131
  - [`TROUBLESHOOTING.md`](TROUBLESHOOTING.md) — answers that are accurate about
130
132
  the wrong thing, including the `S_ABPLNGVS` language-version refusal
131
133
  - [`../../examples`](../../examples) — the sequences, written out
@@ -391,11 +391,11 @@ verdict and this library does not look for one in the body either: reading an
391
391
  activation checklist is your `analyse`, written from the responses your own
392
392
  system gives.
393
393
 
394
- Two things worth knowing while you write it. `activationExecuted="false"` has
395
- been observed on an object that was already active, with no message attached —
396
- so the flag on its own does not separate "nothing to do" from "refused". And a
397
- locked object refuses with HTTP 403, which never reaches a body-reading strategy
398
- at all.
394
+ Two things worth knowing while you write it: `activationExecuted="false"` with
395
+ no message means "nothing to do", and a locked object refuses with HTTP 403,
396
+ which never reaches a body-reading strategy at all — see
397
+ [WORKAROUNDS.md](WORKAROUNDS.md#activationexecuted-false-is-not-a-failure).
398
+ `analyseActivation` in `@mcp-abap-adt/adt-strategies` reads both.
399
399
 
400
400
  ## How to check a created object, and when
401
401
 
@@ -524,56 +524,14 @@ all: it is changed and deleted directly.
524
524
 
525
525
  ## What a bare `create()` actually leaves, per type
526
526
 
527
- A POST sometimes builds a minimal working object and sometimes builds nothing.
528
- Which one you get is a property of the type, and it is not guessable — measured
529
- on a cloud system by creating each and asking every way of reading it:
530
-
531
- | Type | What the POST left | A read straight after |
532
- |---|---|---|
533
- | `domain` | a complete object — the create carries the content | 2067 bytes |
534
- | `interface` | a generated skeleton | 53 bytes |
535
- | `class` | a generated skeleton | **refused**, `400`, "wrong input data" |
536
- | `ddl` | an object with no content | `200`, empty |
537
- | `serviceDefinition` | **nothing — the create itself is refused** | — |
538
-
539
- `serviceDefinition` is the clearest case of the second kind: there is nothing to
540
- generate a service from, so the POST answers *"Check of condition failed"* and
541
- no object is made. `program` could not be measured here — an ABAP Cloud system
542
- refuses it outright with `S_DEVELOP`.
543
-
544
- ### The class has a skeleton; you just cannot read it yet
545
-
546
- The class row above is the one to be careful with, because the refusal invites
547
- the wrong conclusion. SAP *did* generate a minimal class. It is stored as the
548
- active version, and it becomes readable the moment the first source is written:
549
-
550
- ```
551
- GET …/source/main?version=active 200 class ZAC_PROBE_INACT definition ← SAP's, lower case
552
- GET …/source/main?version=inactive 200 CLASS zac_probe_inact DEFINITION … ← ours, as written
553
- ```
554
-
555
- Before that first write, every read refuses — `active`, `inactive`, neither,
556
- metadata, source. And nothing else lifts it:
557
-
558
- ```
559
- create ok
560
- read after create refused, wrong input data
561
- read after 30s refused ← not timing
562
- lock ok
563
- read while locked refused
564
- read after unlock refused ← not the lock either
565
- ```
566
-
567
- So the object is not empty and it is not broken. It is unfinished, and the first
568
- `update()` is what finishes it. Activation is a separate matter again: it
569
- promotes what you wrote into the active version, replacing the skeleton.
570
-
571
- **`getVersions()` will not tell you any of this.** It answers `ok` in every state
572
- above — the feed, which `objectVersions` in `@mcp-abap-adt/adt-strategies`
573
- reads — listing version slots rather than content — `99999` for the inactive,
574
- `00000` for the active — so it reports two entries for the class nothing can
575
- read. The count drops to one when activation consumes the inactive slot, which
576
- is real but is not an answer to "is there anything to read".
527
+ A POST sometimes builds a minimal working object and sometimes builds nothing,
528
+ and which one you get is a property of the type: a domain is complete, an
529
+ interface has a generated skeleton, a DDL source answers `200` with an empty
530
+ body, a class has a skeleton that **no read can see until its first source
531
+ write**, and a service definition's create is refused outright.
532
+ `getVersions()` answers `ok` in every one of those states. The measured table,
533
+ the class's read sequence and what to do are in
534
+ [WORKAROUNDS.md](WORKAROUNDS.md#what-a-bare-create-leaves-depends-on-the-type).
577
535
 
578
536
  ## The name is taken from the POST onward, and `validate()` may not say so
579
537
 
@@ -607,18 +565,12 @@ its package.
607
565
 
608
566
  ## Absence does not have one wording
609
567
 
610
- Deleting each object and reading it again produced three different sentences:
611
-
612
- ```
613
- domain Error while importing object ZAC_UNFIN_DOM from the database
614
- interface Resource INTERFACE ZAC_UNFIN_INTF does not exist.
615
- ddl Data definition ZAC_UNFIN_DDLS of version does not exist
616
- ```
617
-
618
- All three are refusals and all three mean the same thing. None of them is worth
619
- matching on: the text is the server's, it is language-dependent, and it varies
620
- by type. If you need to branch on absence, branch on the failure your own
621
- `analyse` decided, not on the sentence.
568
+ Deleting an object and reading it again answers a different sentence per type —
569
+ *"Error while importing object … from the database"* for a domain, *"Resource
570
+ INTERFACE … does not exist."*, *"Data definition … of version does not
571
+ exist"*. All mean the same thing, and none is worth matching on: branch on the
572
+ failure your own `analyse` decided. See
573
+ [WORKAROUNDS.md](WORKAROUNDS.md#what-a-bare-create-leaves-depends-on-the-type).
622
574
 
623
575
  Reproduce with `npx ts-node scripts/probe-inactive-metadata.ts` and
624
576
  `npx ts-node scripts/probe-unfinished-create.ts`.
@@ -183,14 +183,10 @@ Some endpoints via RFC don't support specific Accept content types. The library
183
183
 
184
184
  RFC returns base64 lock handles that may contain spaces, `+`, `=`. All lock handles are encoded with `encodeURIComponent()` when placed in URL query parameters.
185
185
 
186
- ## Known limitation: package update
186
+ ## Packages: one save per ABAP session
187
187
 
188
- `AdtPackage.updateMetadata()` does not work over RFC. Everything else on a package does
189
- — create, lock, unlock, delete — and every other object type updates normally.
190
- The save is refused with `400 ExceptionResourceAlreadyExists`, `PAK/058`, and
191
- the cause sits below the ADT lock, in the package framework's own state rather
192
- than in the lock handle this library sends.
193
-
194
- The evidence and the four endpoint answers that place it are in
195
- [`docs/development/RFC_TESTING.md`](../development/RFC_TESTING.md#known-limitation-package-update).
196
- Use HTTP for package changes on a system that supports it.
188
+ A package can be saved only once per ABAP session: the next update or delete
189
+ from that session is refused with `PAK/058`. Over RFC every call shares one
190
+ session, so an update straight after a create is already refused. The rule for
191
+ both transports and the workaround are in
192
+ [WORKAROUNDS.md](WORKAROUNDS.md#a-package-can-be-saved-only-once-per-abap-session).
@@ -84,11 +84,12 @@ middle of one operation would take every other caller down with it. The library
84
84
  goes as far as `setSessionType('stateful' | 'stateless')` and no further.
85
85
 
86
86
  Some ADT operations cannot be done twice in one ABAP session, and this is where
87
- that lands on you rather than on us. The clearest case: a package the session
88
- has just updated **cannot be deleted by that same session** — ADT answers
89
- `PAK/058`, and the same delete from any other session succeeds on the first
90
- attempt, immediately, while the first session is still open. It is ownership of
91
- the framework's state, not a delay: retried for 30 seconds it never succeeds.
87
+ that lands on you rather than on us. The clearest case: a package can be saved
88
+ only once per ABAP session — the next update or delete from that session is
89
+ refused with `PAK/058`, and the same request from any other session succeeds at
90
+ once. It is `CL_PACKAGE`'s session buffer, not a delay: retrying never helps.
91
+ The rule for HTTP and RFC, the evidence and the workaround are in
92
+ [WORKAROUNDS.md](WORKAROUNDS.md#a-package-can-be-saved-only-once-per-abap-session).
92
93
 
93
94
  So when an operation refuses in a way that names editing or locking, and the
94
95
  object is one your session has just changed, the fix is a different session —
@@ -4,6 +4,10 @@ ADT answers are often accurate about the wrong thing. Everything below was
4
4
  observed against a running system, and each entry says what the message looks
5
5
  like, what it actually means, and how to tell the two apart.
6
6
 
7
+ SAP-side behaviour with a consumer-side workaround is collected in
8
+ [WORKAROUNDS.md](WORKAROUNDS.md); the entries below that belong there are short
9
+ and link to it.
10
+
7
11
  ## "You are not authorized to make changes (authorization object S_ABPLNGVS)"
8
12
 
9
13
  Arrives as a `403` with an `<exc:exception>` document, `adtType`
@@ -54,76 +58,30 @@ language version its software component fixes; whether the user holds that value
54
58
  in `ABP_LNG_VS`; and whether they hold the specific `ACTVT` for the operation
55
59
  that failed rather than for the one that succeeded.
56
60
 
57
- **The trap.** It is raised wherever the language version cannot be satisfied —
58
- including cases that have nothing to do with your rights. Creating a class into a
59
- package **that does not exist** answers with this object rather than "package not
60
- found": with no package there is no software component, so there is no language
61
- version to check against, and the refusal surfaces as an authorization failure.
62
-
63
- Before going to PFCG, check that the package in the request exists and that its
64
- software component allows the language version you are writing.
61
+ **The trap.** It is also raised for a create into a package **that does not
62
+ exist** — before going to PFCG, check the package. See
63
+ [WORKAROUNDS.md](WORKAROUNDS.md#s_abplngvs-refuses-a-create-into-a-package-that-does-not-exist).
65
64
 
66
65
  ## A read of an object that is not there returns 200 and an empty body
67
66
 
68
- ADT largely does not refuse a request for a missing object. `source/main` never
69
- answers 404; it answers **200 with zero bytes**. A not-yet-ready read of a
70
- domain, data element, package, table type or function group does the same.
71
-
72
- So "the object is not there" and "the object is there and empty" arrive as the
73
- identical answer, and neither the status nor the body can tell them apart.
74
-
75
- **Why it matters more than it looks.** A read-modify-write that trusts the status
76
- reads nothing, writes nothing back, and erases the object. A listing that treats
77
- the same answer as a failure reports an error for an empty package.
78
-
79
- Neither reading can be the library's, which is why it is a decision you supply:
80
- pass `analyse` in the operation options to say which one applies to your call.
67
+ `source/main` never answers 404, and a not-yet-ready metadata read answers the
68
+ same `200` with zero bytes, so "not there" and "there and empty" are one answer.
69
+ A read-modify-write that trusts the status erases the object. See
70
+ [WORKAROUNDS.md](WORKAROUNDS.md#a-read-answers-200-with-an-empty-body-instead-of-404).
81
71
 
82
72
  ## "Resource ZCL_X: wrong input data for processing" on a read
83
73
 
84
- A `400` with an `<exc:exception>`, `adtType` `ExceptionResourceWrongData`, T100
85
- `SADT_RESOURCE/007`. Note the double space: the object type belongs there and
86
- the server left it out, which is the first sign the message is not about your
87
- request at all.
88
-
89
- It means **a class was created and no source has been written to it yet**. Every
90
- read of one refuses this way — `active`, `inactive`, or neither, metadata or
91
- source. Waiting thirty seconds does not help, and neither does a lock/unlock
92
- cycle. Writing the source does, immediately and without any activation.
93
-
94
- The object is not empty and it is not broken: SAP generated a minimal class and
95
- stored it as the active version, and you can read it back the moment the first
96
- write lands. It is unfinished, not absent.
97
-
98
- Specific to classes. An interface created the same way reads its generated
99
- skeleton at once, a domain is complete on creation, a DDL source answers 200
100
- with an empty body, and a service definition cannot be created bare at all —
101
- its POST is refused with "Check of condition failed".
102
-
103
- The trap is that it reads as "your request is malformed", so the natural
104
- response is to retry, and retrying never works. This library's own suite spent
105
- sixteen seconds a run on eight such retries before anyone measured it, and the
106
- assertion after them had never once executed.
107
-
108
- **What to do:** write the source. A class reads at `version=inactive` while
109
- still under its lock, long before any activation. Do not reach for
110
- `getVersions()` to test readiness — it answers `ok` in this state too, listing
111
- version slots rather than content. See
112
- [OBJECT_LIFECYCLE.md](OBJECT_LIFECYCLE.md#what-a-bare-create-actually-leaves-per-type).
74
+ A `400 ExceptionResourceWrongData`, `SADT_RESOURCE/007`, on every read of a
75
+ class that was created and has no source written yet. It is unfinished, not
76
+ absent or broken: write the source, do not retry. See
77
+ [WORKAROUNDS.md](WORKAROUNDS.md#what-a-bare-create-leaves-depends-on-the-type).
113
78
 
114
79
  ## "Class ZCL_X does not have a TMDIR entry" on an activation
115
80
 
116
- A `200` carrying `<msg type="E" code="OO(045)">`, alongside an informational
117
- `EU(239)` "Errors occurred during generation" — note that the summary of the
118
- errors is severity `I`, so counting by severity finds one error, not two.
119
-
120
- It means **the object does not exist**. The activation went straight to
121
- generation, looked for the class in the method directory, and found nothing.
122
- It does not say "not found", so it reads like a corrupt object; it is an absent
123
- one. The same message serves interfaces, with `Interface` in `T100KEY-V1`.
124
-
125
- Distinguish it from the entry above: `wrong input data` is an object that exists
126
- with nothing in it, `TMDIR` is an object that is not there at all.
81
+ A `200` carrying `<msg type="E" code="OO(045)">`: the object **does not exist**.
82
+ Distinguish it from the entry above — `wrong input data` is an object that
83
+ exists with nothing in it, `TMDIR` is an object that is not there at all. See
84
+ [WORKAROUNDS.md](WORKAROUNDS.md#activationexecuted-false-is-not-a-failure).
127
85
 
128
86
  ## A message class exists; its messages do not
129
87
 
@@ -201,31 +159,15 @@ an object already in this state is SAP GUI territory.
201
159
 
202
160
  ## A refusal can arrive with a 2xx
203
161
 
204
- ADT answers some refusals with **200** carrying an `<exc:exception>` document.
205
- The request reached the server and came back, so nothing throws and every layer
206
- above stores the body as a result.
207
-
208
- Measured on a trial: five of seven probed operations reported no errors
209
- while SAP had refused, three of them writes — a caller believed an object existed
210
- that did not, and that one had been deleted that had not.
211
-
212
- **The status is the channel; the document is the verdict.** There are at least
213
- three refusal shapes and they are not interchangeable:
214
-
215
- | shape | resource |
216
- |---|---|
217
- | `<exc:exception>` | most resources, any status including 200 |
218
- | `<del:message del:type="E">` in `del:checkResponse` | `/deletion/check` |
219
- | `<msg type="E">` in `chkl:messages` | `/activation` |
162
+ The status is the channel; the document is the verdict. ADT has at least three
163
+ refusal shapes, and a `200` can carry any of them. See
164
+ [WORKAROUNDS.md](WORKAROUNDS.md#a-refusal-can-arrive-with-a-2xx-and-an-error-status-names-the-fix).
220
165
 
221
166
  ## Activation reports `activationExecuted="false"` and nothing is wrong
222
167
 
223
- The flag says whether ADT did any work, not whether the work succeeded. An object
224
- that is already active answers `false` with an empty message list — identical, by
225
- the flag alone, to an object that does not exist.
226
-
227
- **Only `<msg type="E">` is the verdict.** An object locked by another session is
228
- a `403` and never reaches this document at all.
168
+ The flag says whether ADT did any work, not whether it succeeded; only
169
+ `<msg type="E">` is the verdict. See
170
+ [WORKAROUNDS.md](WORKAROUNDS.md#activationexecuted-false-is-not-a-failure).
229
171
 
230
172
  ## A deletion check that says "no" is not a failure
231
173
 
@@ -237,12 +179,8 @@ the objects are still on the system, and that is a failure.
237
179
 
238
180
  ## 406 and 415 name the exact content type in their text
239
181
 
240
- The status number says nothing actionable; the sentence names the header:
241
-
242
- - `406` — "Accepted content types: application/vnd.sap.adt.deletion.check.response.v1+xml"
243
- - `415` — "Supported Media Types: …check.request.v1+xml"
244
-
245
- Reading the body is cheaper than guessing content types from a status.
182
+ The status number says nothing actionable; the sentence names the header. See
183
+ [WORKAROUNDS.md](WORKAROUNDS.md#a-refusal-can-arrive-with-a-2xx-and-an-error-status-names-the-fix).
246
184
 
247
185
  ## "No URI-Mapping defined for URI", inside a 200
248
186