Both options framed for OQ-11 failed the deciding criterion: whether the next person finds the thing inside the platform. A CAP service or a hardened worker on Cloud Foundry is discoverable only to whoever already knows the route to it, which is ADR-002's original objection relocated rather than answered. The integration is now Integration Suite native. Nothing on Cloud Foundry, nothing in ABAP: - Arena connectivity as a custom adapter built with the Adapter SDK — sender adapter with the webhook endpoint and delta scheduler, cluster lock for single-flight login, ADK persistency for the delta cursor, tenant user credentials for Arena secrets. - Movement as iFlows to the released Product / BOM / ChangeMaster / Attachment OData APIs. - Human approval in SAP Build Process Automation (entitled in the global account, not yet assigned). Decisive: every mechanism hand-rolled in worker/ has a first-class ADK facility, so the adapter deletes that custom infrastructure rather than merely relocating it; and the ADK's Java/Maven/OSGi toolchain is not a new cost here, because the AS/400 FetchAPI servlets are already Java and Java developers can be staffed in-house. worker/ is reclassified from deliverable to specification: its 137 tests describe the Arena session, delta-cursor and webhook behaviour the adapter must reproduce. app/ has no target service under ADR-005 and is kept as reference, unrepointed. ADR-004's "side-by-side runtime" is narrowed to mean "in Integration Suite". New verification items V-5 (can an ADK adapter hold an Arena session under cluster lock — the first build) and V-6 (where SBPA tasks surface for a business user). No SAP tenant or BTP artifact was modified. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1592 lines
97 KiB
Markdown
1592 lines
97 KiB
Markdown
# CHANGELOG — arena-plm (standalone)
|
||
|
||
Append-only decision log for this package.
|
||
|
||
## 2026-09-29 — ADR-005: OQ-11 closed. Integration Suite native — Arena ADK adapter + iFlows, approval in SAP Build Process Automation
|
||
|
||
- What changed: I closed OQ-11 and wrote
|
||
`docs/adr/ADR-005-integration-suite-native.md`. The integration becomes
|
||
Integration Suite native: an Arena custom adapter built with the Adapter SDK
|
||
(sender adapter carrying the webhook endpoint and the delta scheduler), iFlows
|
||
for the movement to the released Product / BOM / ChangeMaster / Attachment
|
||
APIs, and human approval in SAP Build Process Automation. Nothing runs on
|
||
Cloud Foundry; nothing is written in ABAP. I rewrote the PRD's target
|
||
architecture accordingly and added V-5 and V-6.
|
||
- Why: both options I had framed for OQ-11 failed the criterion that actually
|
||
decides this. The test is not build cost, it is whether the next person finds
|
||
the thing inside the platform — and a CAP service or a hardened worker on
|
||
Cloud Foundry is discoverable only to whoever already knows the route to it,
|
||
which is ADR-002's original objection relocated rather than answered.
|
||
Two findings then chose between the native options:
|
||
- Every mechanism I hand-rolled in `worker/` has a first-class ADK facility:
|
||
cluster lock for single-flight login, ADK persistency for the delta cursor,
|
||
user credentials for Arena secrets, scheduler support, connection status,
|
||
tracing, endpoint visualization, and versioning rules [source: SAP Help,
|
||
*Adapter Development Process*, Cloud Integration, verified 2026-09-29]. The
|
||
adapter does not merely present better; it deletes the infrastructure the
|
||
worker existed to supply.
|
||
- I had recorded the ADK's Java/Maven/OSGi toolchain as the cost of this
|
||
route. It is not a cost in this estate: the AS/400 FetchAPI servlets on
|
||
`mcl2000` are already Java, and Java developers can be staffed in-house. One
|
||
language and one team span both ends, and the ADK covers the on-premise leg
|
||
directly through *Accessing On-Premise Application using Cloud Connector* —
|
||
which retires the deleted Cloud Foundry `fetchapi-bridge` pattern instead of
|
||
rebuilding it.
|
||
- Affected: PRD (target architecture, decisions, OQ-11 closed, V-5 and V-6
|
||
added), new ADR-005, ADR-004 narrowed. `worker/` is reclassified from
|
||
deliverable to specification; `app/` has no target service under ADR-005 and
|
||
is kept as reference, not repointed. No SAP tenant or BTP artifact was
|
||
modified.
|
||
- Decision: ADR-005. I also correct something I asserted too confidently
|
||
earlier in the day: that SAP Build Process Automation tasks surface in the
|
||
Fiori launchpad. That is now V-6, unverified — what I can state is that the
|
||
service is entitled in the global account (`process-automation`,
|
||
`process-automation-service`) and therefore needs assigning, not buying.
|
||
First build is V-5: a minimal Arena sender adapter that logs in and holds the
|
||
session under cluster lock. Nothing else starts before it.
|
||
|
||
## 2026-09-29 — Read access to the customizing tenant proven through `mc-s4hana`; the parked password is simply stale
|
||
|
||
- What changed: nothing in the tenant — I established how to read it. Through
|
||
the BTP destination `mc-s4hana`, three read-only GETs against
|
||
`my429480` all answered 200: `API_BUSINESS_PARTNER/$metadata` (EDMX v1.0,
|
||
65 entity sets), `A_BusinessPartner?$top=1` (BusinessPartner `1710`), and
|
||
`api_product/srvd_a2x/sap/product/0002/$metadata` (EDMX 4.0, 39 entity sets).
|
||
I used the destination service instance `sap-apps-dest` and its existing
|
||
service key `dest-anywhere-dest-key`; I created no key and no instance.
|
||
- Why: after retargeting, direct basic auth to the customizing tenant returned
|
||
401, and I needed to know whether the tenant was refusing the user or the
|
||
stored password was wrong.
|
||
- Affected: no SAP object, no BTP artifact. Knowledge only.
|
||
- Findings:
|
||
- `mc-s4hana` authenticates as **`BasicAuthentication` with the same user,
|
||
`AZ_API_USER`**, and succeeds. So the tenant accepts that user over basic
|
||
auth: the 401 was neither a lockout nor a user problem. The password in
|
||
`_shared/.env.starter-cust-my429480.bak` is stale, and the working value is
|
||
already held by the destination. No credential reset is needed.
|
||
- The destination's own description reads "SAP S/4HANA Public Cloud - MC
|
||
Production" while its URL is the starter customizing tenant — the same
|
||
mislabel this package carried, now visible in BTP as well. I left it alone;
|
||
it is shared, and a description is not worth an unrequested change.
|
||
- `default-env.json` alone does not work with SAP Cloud SDK v4:
|
||
`@sap-cloud-sdk/connectivity` 4.6.0 resolves bindings through `@sap/xsenv`'s
|
||
`filterServices()`, which reads `process.env.VCAP_SERVICES` and never loads
|
||
the file. `require('@sap/xsenv').loadEnv()` must run ahead of the SDK
|
||
requires (or `VCAP_SERVICES` be exported). The first attempt failed with
|
||
"Could not find service binding of type 'destination'".
|
||
- Decision: I will not copy the working password out of the destination into
|
||
`.env`. The destination is the sanctioned path for this estate, so the fix is
|
||
to make the shared CLI destination-aware rather than to hold a second copy of
|
||
a credential. Until that is done, reads against the customizing tenant go
|
||
through a destination-based call, not through `sap-api`.
|
||
|
||
## 2026-09-29 — Tooling retargeted to the starter customizing tenant; its credential is rejected
|
||
|
||
- What changed:
|
||
- I pointed the shared CLI at the starter system's customizing tenant. Both
|
||
`_shared/.env` and the root `.env` now carry `SAP_API_URL`,
|
||
`SAP_API_USER` and `SAP_API_PASSWORD` for
|
||
`https://my429480-api.s4hana.cloud.sap`; the eight `CPI_*` and `ARENA_*`
|
||
variables are untouched.
|
||
- I renamed both parked credential files so neither name asserts something
|
||
false: the client-080 credential is now
|
||
`_shared/.env.starter-dev-my431353.bak`, and the client-100 credential is
|
||
`_shared/.env.starter-cust-my429480.bak` (formerly `.env.prod-my429480.bak`,
|
||
a name that wrongly called it productive).
|
||
- I corrected the tenant references in `CLAUDE.md`, `KNOWLEDGE.md`,
|
||
`app/README.md`, `docs/handover/rap/README.md` and
|
||
`.claude/agents/rap-developer.md`: the customizing tenant is the working
|
||
target, the development tenant is parked as of 2026-09-29 with its objects
|
||
in place. No historical build record was deleted.
|
||
- I wrote `docs/adr/ADR-004-back-out-of-on-stack-rap.md` and marked ADR-002
|
||
superseded in its own file, including the note that its gate "confirm
|
||
developer-extensibility access on my429480" was unanswerable as written.
|
||
- Verification: **the customizing-tenant credential is rejected.** Read-only
|
||
GETs return HTTP 401 with SAP's logon-failed page (`Anmeldung
|
||
fehlgeschlagen`); the host resolves and answers, so this is the credential,
|
||
not reachability. I then checked every other way in and found none: the
|
||
rejected password is the only copy of that credential anywhere in my estate;
|
||
the Cloud Foundry token is expired, so the `mc-s4hana` destination is out of
|
||
reach; and the client-certificate path in the shared client looks for
|
||
`_shared/certs/az-api-user.crt` and `.key`, which do not exist. No writes of
|
||
any kind were issued to any tenant.
|
||
- Affected: `_shared/.env`, `.env`, both `.bak` files, five reference documents,
|
||
ADR-002, new ADR-004. No SAP tenant was modified.
|
||
- Decision: I left the retarget in place rather than rolling back to the
|
||
development tenant, because reverting would only restore access to the tenant
|
||
I am deliberately leaving. Restoring read access to the customizing tenant is
|
||
now a prerequisite for any verification, and the cheapest route is a Cloud
|
||
Foundry re-login — that reaches the tenant through the `mc-s4hana` destination
|
||
and needs no password at all, which is also what my coding standard requires.
|
||
|
||
## 2026-09-29 — ADR-004: I withdraw the on-stack RAP route; development tenant parked
|
||
|
||
- What changed: I corrected a tenant mislabel that had propagated through this
|
||
package, and on the corrected facts I withdrew ADR-002.
|
||
- Both `my429480` and `my431353` are tenants of the **starter system**.
|
||
`my429480` is its **customizing** tenant (client 100); `my431353` is its
|
||
**development** tenant (client 080). This package had `my429480` recorded
|
||
as "productive" and treated `my431353` as a separate development system;
|
||
both readings were wrong, and the parked credential file name
|
||
(`.env.prod-my429480.bak`) encoded the same error.
|
||
- The customizing tenant supports **key-user extensibility only** — no ABAP,
|
||
no RAP; developer extensibility exists only on client 080 [source:
|
||
fiori-tools-samples `misc/s4hana/README` "Tenant Types", verified
|
||
2026-09-29].
|
||
- I therefore parked the development tenant `my431353`, leaving all 19
|
||
activated `ZARENA_PLM` objects in place, and moved the application back to
|
||
a side-by-side runtime against released APIs.
|
||
- I rewrote the PRD accordingly: new target architecture, corrected
|
||
Systems & boundaries rows, amended acceptance test, ADR-002 marked
|
||
superseded, ADR-004 added, and the RAP-dependent verification items
|
||
(V-2, V-3, OQ-5, OQ-8, OQ-9, OQ-10) parked rather than closed (OQ-12).
|
||
- Why: I am not carrying an ABAP/RAP build for this package, and the tenant I
|
||
am working in cannot host one even if I wanted to. Keeping a PRD that
|
||
asserted an impossible architecture would have been worse than the rebuild.
|
||
- Affected: PRD.md (vision, target architecture, systems, decisions, open
|
||
questions, status), the parked tenant `my431353`, ADR-002.
|
||
- Decision: ADR-004. I park rather than delete, so the RAP route stays
|
||
reversible at zero cost. I left the replacement host open as OQ-11 —
|
||
key-user extensibility in the tenant versus a CAP service side-by-side —
|
||
and recorded my recommendation for CAP, because the connectivity worker has
|
||
to be side-by-side regardless and one runtime beats two. I will not start
|
||
building until OQ-11 is decided.
|
||
|
||
## 2026-09-29 — Outstanding sources committed and pushed
|
||
|
||
- What changed: I committed the working-tree state that had sat uncommitted
|
||
since the initial `upload current sources` commit, and pushed it: `468729e`,
|
||
42 files, 4614 insertions, 1697 deletions, fast-forward onto `origin/main`.
|
||
It carries the renamed RAP handover sources (the 11 generator-suffixed
|
||
`zz*000` names replaced by the clean object names actually built on the
|
||
tenant), the `app/` rebind edits, the build record through 2026-09-19, the
|
||
retained reentrance-login helper and the captured live `$metadata`. It drops
|
||
two files that never belonged in the repository: a tracked Eclipse installer
|
||
under a URL-mangled filename, and a machine-specific workspace file.
|
||
- Why: the package held six weeks of unversioned work, and I was about to
|
||
change direction. Nothing should be lost across that pivot.
|
||
- Affected: the whole repository; `origin/main` now matches the working tree.
|
||
- Decision: I committed the deletions as they stood rather than restoring
|
||
either file. Neither is source.
|
||
|
||
## 2026-09-18 — Reentrance-ticket login for `abap-adt-mcp`: built, tested, rejected
|
||
|
||
- What changed: I built a login helper at `tools/adt-reentrance-login/`
|
||
(Node, no dependencies): a one-shot loopback listener that captures an
|
||
ADT reentrance ticket from the `redirect-url=http://localhost:<port>/adt/redirect`
|
||
flow, writes it to a 0600 file, and probes how the tenant accepts it. It
|
||
never prints, logs or passes the ticket through argv or the environment,
|
||
and it parses the raw query itself, because `URLSearchParams` turns a
|
||
`+` in a ticket into a space and would corrupt it. Then I captured a real
|
||
ticket and tested it: `/sap/bc/adt/core/discovery` and an ABAP class
|
||
source URL answered 200 with the same 3094-byte SAML redirect page for
|
||
cookie transport, header transport and no credential, with and without
|
||
`sap-client=080`.
|
||
- Why: `abap-adt-mcp`'s browser SSO needs a window on the server's desktop,
|
||
which is unreachable over this remote session (OQ-9). ADT for VS Code
|
||
logs on with a reentrance ticket instead, so the question was whether
|
||
that ticket can feed the server's `sso2` (MYSAPSSO2 cookie) mode.
|
||
- Affected: new `tools/adt-reentrance-login/`, `~/.abap-adt-mcp/systems.json`
|
||
(switched to `sso2`, then restored to `sso`), KNOWLEDGE.md, PRD OQ-9.
|
||
- Decision: the approach is rejected on evidence. A reentrance ticket is
|
||
neither a logon-ticket cookie nor an assertion-ticket header on this
|
||
tenant, so `sso2` cannot consume it. I restored the browser-login
|
||
configuration, shredded the captured ticket, and kept the helper: it is
|
||
the only piece that would still be needed if the exchange mechanism is
|
||
ever identified. The next step, if this is revisited, is to capture what
|
||
ADT for VS Code actually sends, not to guess header names. Tenant work
|
||
continues on SAP's ADT MCP with editor paste, which is proven.
|
||
|
||
## 2026-09-16 — Worker leg active: approval BO complete on the development tenant
|
||
|
||
- What changed:
|
||
- I activated W3 (A2X projection BDEF) and W4 (service definition
|
||
`ZAPI_ARENA_CHANGE_APPROVAL`).
|
||
- I created and activated W5, the OData V4 Web API binding
|
||
`ZAPI_ARENA_CHANGE_APPR_A2X`, with binding type `OData V4 - Web API`
|
||
(`create_object` returned `.srvb.json`).
|
||
- `fetch_services`: service `ZAPI_ARENA_CHANGE_APPROVAL`, version `0001`,
|
||
V4, `isPublished: false`, `bindingCategory: "1"`.
|
||
- ATC over the five worker objects (worklist
|
||
`12ACF6BD93811FE1ACBA776536DD5BD6`): 0 errors and one priority-3
|
||
warning, W607 (+BDL 549) on BDEF `ZC_CHANGEAPPROVAL_A2X`: "CDS annotation
|
||
#CHECK … should be replaced with #MANDATORY".
|
||
|
||
[source: adt-mcp abap_activate_objects, abap_creation-create_object,
|
||
abap_atc_get_result, abap_business_services-fetch_services on 0M7DEJI,
|
||
verified 2026-09-16]
|
||
- Why: RAP-6. The worker needs create and the three execution-state
|
||
actions through a Web API, separate from the read-only UI.
|
||
- Affected: dev tenant `ZARENA_PLM` (all 19 approval-BO objects now
|
||
active), PRD RAP BO status, KNOWLEDGE.md.
|
||
- Decision: W5 stays unpublished. It is exposed to the worker's technical
|
||
user through a custom communication scenario (V-2 A2X half), not through
|
||
business-user access. I do not switch
|
||
`@AccessControl.authorizationCheck` from `#CHECK` to `#MANDATORY` now:
|
||
the warning does not block activation, and the change belongs with the
|
||
OQ-8 authorization work, which revisits all three projection and root
|
||
views together (the same annotation is in `ZR_CHANGEAPPROVAL` and
|
||
`ZC_CHANGEAPPROVAL`).
|
||
|
||
## 2026-09-16 — Worker leg: A2X projection view and access control active; A2X BDEF created
|
||
|
||
- What changed: I activated W1 (`ZC_CHANGEAPPROVAL_A2X` projection view)
|
||
and W2 (its access control); both answered "Activation successful."
|
||
I then created W3, the projection BDEF `ZC_CHANGEAPPROVAL_A2X`, empty
|
||
(`.bdef.abdl`), after W1 was active [source: adt-mcp
|
||
abap_activate_objects, abap_creation-create_object on 0M7DEJI, verified
|
||
2026-09-16]. W4 (service definition) is saved but not active.
|
||
- Why: worker leg round 2 of the approval BO.
|
||
- Affected: dev tenant `ZARENA_PLM`, PRD RAP BO status.
|
||
- Decision: W4 activates only after W3 is active. Then W5, the Web API
|
||
binding, is created and verified unpublished.
|
||
|
||
## 2026-09-16 — Worker leg round 1 created; handover brought in line with live results
|
||
|
||
- What changed: after the expired VS Code ADT logon was restored, I
|
||
created W1 (`ZC_CHANGEAPPROVAL_A2X` view), W2 (its access control, with
|
||
`protectedEntity`) and W4 (service definition
|
||
`ZAPI_ARENA_CHANGE_APPROVAL`) empty in `ZARENA_PLM` [source: adt-mcp
|
||
create_object on 0M7DEJI, verified 2026-09-16]. I also corrected
|
||
`docs/handover/rap/`: both service definition sources are comment-free,
|
||
the README records the UI leg as active, ATC-clean and published, the
|
||
activation-URI table marks the proven extensions (`.tabl.ddic`,
|
||
`.bdef.abdl`, `.srvb.json`), and the worker-leg sequence is rewritten to
|
||
two paste rounds. All 31 existing citations were preserved.
|
||
- Why: worker (A2X) leg of the approval BO (RAP-6). The handover must not
|
||
repeat today's failed activations.
|
||
- Affected: dev tenant `ZARENA_PLM`, `docs/handover/rap/`, KNOWLEDGE.md.
|
||
- Decision: pastes are opened manually from the ABAP workspace tree. I only
|
||
give the local source path and the `abap:/repotree-v1/…` target, because
|
||
editor tabs opened by URI cannot save. W5 uses binding type `OData V4 -
|
||
Web API`, the exact value the create metadata offers. W5 stays
|
||
unpublished until the custom communication scenario brief (V-2).
|
||
|
||
## 2026-09-16 — Fiori app bound to the live RAP service identity (V-2 UI half)
|
||
|
||
- What changed: I reconciled `app/` with the published service.
|
||
- Manifest dataSource and mock-server URL paths now use
|
||
`/sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/`.
|
||
- The mock `metadata.xml` is the live `$metadata`, byte-identical (sha256
|
||
`c13e86e1…`, checked).
|
||
- Mock rows carry `StatusText`, `LocalLastChangedAt`,
|
||
`__OperationControl` and `SAP__Messages`.
|
||
- All annotation targets and action strings use namespace
|
||
`com.sap.gateway.srvd.zui_arena_change_approval.v0001` and entity type
|
||
`ChangeApprovalType`.
|
||
|
||
A grep for the old identity over `app/` (excluding `node_modules`/`dist`)
|
||
returns nothing. Lint, typecheck and `@ui5/linter` are clean. The mock
|
||
server answers `$metadata` and `ChangeApproval` with `$filter`, `$count`
|
||
and `__OperationControl` selects.
|
||
- Why: V-2 and ARN-007. The app must address the service that exists.
|
||
- Affected: `app/` (manifest, `ui5-mock.yaml`, `ui5-local.yaml`,
|
||
`annotation.xml`, mock metadata and data, README), PRD V-2, new OQ-10,
|
||
KNOWLEDGE.md.
|
||
- Decision:
|
||
- (1) Action enablement belongs to the backend. The mock's local
|
||
`OperationAvailable` overrides went away with the mock metadata, and
|
||
`annotation.xml` deliberately defines none, because a local one would
|
||
replace RAP's `_it/__OperationControl/<action>` [source:
|
||
fiori-mcp-server "Action Control for Context-Dependent Actions",
|
||
verified 2026-09-16].
|
||
- (2) No real backend is configured in the UI5 tooling yet. Any live
|
||
preview targets the UI host, never `-api`. Its authentication type and
|
||
client are verified before use, not assumed.
|
||
- (3) UI annotation ownership is opened as OQ-10 rather than moved now:
|
||
consolidating would drop i18n labels and action criticality and break
|
||
the OPA section IDs mid-POC.
|
||
- (4) `dist/` is stale and must be rebuilt before any deployment.
|
||
|
||
## 2026-09-16 — Live `$metadata` captured: backend contract matches the app; identity names differ
|
||
|
||
- What changed: the published UI service's `$metadata` is captured in
|
||
`docs/v2/zui_arena_change_appr_o4.metadata.xml`. It was copied from the
|
||
browser on the UI host `my431353.s4hana.cloud.sap`; browser-decoded `&`
|
||
characters were re-escaped. The `-api` host refused the same request to a
|
||
business user ("blocked by UCON").
|
||
- Matches the app: all 17 app properties with identical EDM types
|
||
(`Edm.Boolean` flags, `Edm.Byte` criticality, `Edm.DateTimeOffset`
|
||
Precision 7), key `ID`, entity set `ChangeApproval`, and the actions
|
||
`approve`, `reject(RejectReason)` (non-nullable) and `retrySync`.
|
||
- Differs from the mock: namespace
|
||
`com.sap.gateway.srvd.zui_arena_change_approval.v0001` (from the service
|
||
definition), entity type `ChangeApprovalType`, URL segment
|
||
`zui_arena_change_appr_o4`, extra `StatusText` / `LocalLastChangedAt` /
|
||
`__OperationControl` / `SAP__Messages`, and backend-driven
|
||
`Core.OperationAvailable`.
|
||
|
||
I dispatched the app reconciliation.
|
||
- Why: V-2. The app was built against a provisional mock identity, and only
|
||
the live service can settle it.
|
||
- Affected: PRD V-2, `app/` (in progress), KNOWLEDGE.md.
|
||
- Decision: the live `$metadata` replaces the mock metadata and becomes the
|
||
app's contract. Button enablement comes from the backend's
|
||
`__OperationControl` rather than local `IsApprovable`/`IsRetriable`
|
||
overrides, unless the Fiori docs show that breaks something. Any
|
||
non-mock backend configuration points at the UI host, never `-api`.
|
||
Earlier notes claiming the binding name sets the namespace are superseded
|
||
(KNOWLEDGE 2026-09-16).
|
||
|
||
## 2026-09-16 — Approval UI service published on the development tenant
|
||
|
||
- What changed: the OData V4 UI binding `ZUI_ARENA_CHANGE_APPR_O4` is
|
||
published. The ADT for VS Code Publish code lens gave no visible
|
||
confirmation, so I verified it live: `fetch_services` reports
|
||
`isPublished: true`, and `fetch_service_information` returns
|
||
`https://my431353-api.s4hana.cloud.sap/sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/?sap-client=080`
|
||
with entity set `ChangeApproval` [source: adt-mcp
|
||
abap_business_services-fetch_services, fetch_service_information on
|
||
0M7DEJI, verified 2026-09-16].
|
||
- Why: RAP-5. The Fiori app cannot bind to an unpublished service.
|
||
- Affected: PRD RAP BO status, V-2, KNOWLEDGE.md.
|
||
- Decision: the URL path is exactly the designed one, so no binding change
|
||
follows. The app's V-2 reconciliation (dataSource first segment,
|
||
namespace, annotation targets, EDM types) is done against the live
|
||
`$metadata`, never inferred. The service reports client 080, so the
|
||
client value in any tool configuration comes from the live system.
|
||
|
||
## 2026-09-16 — UI leg active: approval BO and OData V4 UI service built on `my431353`
|
||
|
||
- What changed:
|
||
- U13, the service definition `ZUI_ARENA_CHANGE_APPROVAL`, activated after
|
||
I re-saved it without its header comment. The same definition failed
|
||
with the comment and succeeded without it, so the comment was the
|
||
blocker; the missing-draft message is not.
|
||
- I created U14, the OData V4 UI binding `ZUI_ARENA_CHANGE_APPR_O4`
|
||
(`create_object` returned `.srvb.json`), and activated it.
|
||
- ATC over all 14 UI-leg objects: 0 errors, 0 warnings, 43 infos
|
||
(worklist `12ACF6BD93811FE1ACB8096AC6763BD6`).
|
||
- `fetch_services`: service `ZUI_ARENA_CHANGE_APPROVAL`, version `0001`,
|
||
OData V4, unpublished.
|
||
|
||
[source: adt-mcp abap_activate_objects, abap_creation-create_object,
|
||
abap_atc_get_result, abap_business_services-fetch_services on 0M7DEJI,
|
||
verified 2026-09-16]
|
||
- Why: RAP-1..8 and the ARN-007 acceptance path. The service must exist
|
||
before the app can bind to it.
|
||
- Affected: dev tenant `ZARENA_PLM`, PRD RAP BO status, KNOWLEDGE.md,
|
||
handover README (both SRVD sources still carry header comments, and U9
|
||
still says `.bdef.json`).
|
||
- Decision: the service alias equals the definition name and the version
|
||
is `0001`. Publishing therefore yields
|
||
`/sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/`,
|
||
as designed, so no rename is needed before publishing. The 43 ATC infos
|
||
are reviewed in the ADT ATC view (the MCP returns only totals); infos do
|
||
not gate publishing. I correct the handover README in one pass before
|
||
the worker leg: comment-free SRVD sources and BDEF `.bdef.abdl` URIs.
|
||
|
||
## 2026-09-16 — Wave D: projection BDEF, access control and metadata extension active; service definition refused
|
||
|
||
- What changed: I activated U9 (projection BDEF `ZC_CHANGEAPPROVAL`), U11
|
||
(its access control) and U12 (its metadata extension); each answered
|
||
"Activation successful." Activating U13, the service definition
|
||
`ZUI_ARENA_CHANGE_APPROVAL`, answered "Activation failed" with two
|
||
messages and no severity:
|
||
- "Comments are not supported and will be deleted on save" (Ln 1, the
|
||
handover header block comment)
|
||
- "oData V4 services with no draft capability will be primarily
|
||
READ-ONLY" (Ln 21). The BO has no draft, by design.
|
||
|
||
CDS SDL allows comments as a language rule [source: abap-docs
|
||
/abap-docs-cloud/ABENCDS_F1_SDL_SYNTAX, ABENCDS_GENERAL_SYNTAX_RULES,
|
||
verified 2026-09-16], so the refusal comes from the service definition
|
||
tooling, not the language. U14 (the binding) was not created.
|
||
- Why: wave D of the UI leg.
|
||
- Affected: dev tenant `ZARENA_PLM`, PRD RAP BO status, KNOWLEDGE.md.
|
||
- Decision: I re-save U13 with only its definition (annotation, `define
|
||
service`, `expose`) and no header comment, then activate again. If it
|
||
still fails with only the draft message, that message is blocking, and I
|
||
read its severity in the editor's Problems view before changing anything
|
||
about draft.
|
||
|
||
## 2026-09-16 — `abap-adt-mcp` parked: SSO cannot complete over remote access
|
||
|
||
- What changed: with `SAP_BROWSER_PATH` set, the SSO login launched
|
||
Chrome with a dedicated profile on the server's desktop display and
|
||
waited on the Microsoft Entra sign-in page. The login does not use a
|
||
localhost redirect: SAML returns to the tenant, and the server harvests
|
||
the session cookies from its own Chrome over the DevTools protocol
|
||
(`dist/lib/browserLogin.js`). I tried a localhost-only DevTools relay on
|
||
a fixed port for remote interaction. It is not workable through
|
||
multi-hop SSH proxies, so I stopped it and closed the login browser. No
|
||
login happened. The server remains registered, read-only.
|
||
- Why: the sign-in has to happen inside the server's browser, and that
|
||
browser is on a desktop I cannot reach from this remote session.
|
||
- Affected: PRD OQ-9, KNOWLEDGE.md.
|
||
- Decision: I park `abap-adt-mcp` rather than remove it. One sign-in at
|
||
the server's desktop, with "stay signed in", should let later logins run
|
||
unattended in the invisible browser; that is unverified. The UI leg
|
||
finishes on the proven path: SAP `adt-mcp` for create and activate,
|
||
source pasted in the VS Code editor. Four wave-D sources, one binding and
|
||
a publish remain.
|
||
|
||
## 2026-09-16 — `abap-adt-mcp` connected; SSO blocked on browser detection
|
||
|
||
- What changed: after the restart, `abap-adt-mcp` connected. `listSystems`
|
||
showed exactly one destination, `MY431353` (client 100, SSO), with policy
|
||
`readOnly: true` and `allowedPackages: ["ZARENA_PLM"]`. The first SAP call
|
||
(`classIncludes` on `ZBP_R_CHANGEAPPROVAL`) failed before any login: "No
|
||
Chrome/Edge/Brave found for SSO login." The server's browser detection
|
||
covers only macOS paths (KNOWLEDGE 2026-09-16).
|
||
- Why: SSO login is the gate to the read-only Local Types check.
|
||
- Affected: project MCP registration (env), KNOWLEDGE.md.
|
||
- Decision: the registration gains `SAP_BROWSER_PATH=/usr/bin/google-chrome`
|
||
and nothing else changes. This is a manual step, like the original
|
||
registration.
|
||
|
||
## 2026-09-16 — `abap-adt-mcp` registered read-only in project scope
|
||
|
||
- What changed: `abap-adt-mcp` is registered in the project `.mcp.json`
|
||
(git-ignored, mode 600). It runs over stdio as `npx -y
|
||
abap-adt-mcp@2.1.0` with `MCP_READ_ONLY=1`, an audit log at
|
||
`~/.abap-adt-mcp/audit.jsonl`, and the desktop display variables for the
|
||
SSO browser. Its systems file lists only the development tenant
|
||
`my431353`, client 100, SSO, with `policy.readOnly: true` and
|
||
`allowedPackages: ["ZARENA_PLM"]`. The six existing project servers are
|
||
unchanged, `adt-mcp` included.
|
||
- Why: OQ-9. Agent-side source read and write would replace manual pasting
|
||
for the remaining RAP objects.
|
||
- Affected: project MCP configuration, PRD OQ-9.
|
||
- Decision: the first use is a read-only `getObjectSource` of the behavior
|
||
pool's Local Types include. That check settles whether wave C's
|
||
activation proved the handler constructs. Write access is enabled only
|
||
after that read succeeds. The CLAUDE.md MCP routing table changes only
|
||
once the server has written and activated an object successfully.
|
||
|
||
## 2026-09-16 — `abap-adt-mcp` source review: all checks cleared; written report not produced
|
||
|
||
- What changed: the read-only source review of `abap-adt-mcp` 2.1.0 cleared
|
||
every check it ran (install scripts, network egress, credential and
|
||
session storage, policy enforcement, dangerous primitives), observed as it
|
||
ran. It then stalled while collecting line citations, consumed its budget,
|
||
and was stopped at ~03:28, so no written report with file:line evidence
|
||
exists. As of 03:30 the package is not registered, no `~/.abap-adt-mcp`
|
||
configuration exists, and no login has happened. The tenant state is
|
||
unchanged: waves A–C are active, and wave D (U9, U11, U12, U13) exists
|
||
empty.
|
||
- Why: OQ-9 was gated on this review.
|
||
- Affected: PRD OQ-9.
|
||
- Decision: I accept the review for the development tenant only, under the
|
||
read-only-first configuration (pinned 2.1.0, `readOnly: true`,
|
||
`allowedPackages: ["ZARENA_PLM"]`, `MCP_READ_ONLY=1`, audit file on).
|
||
Registration is run by hand. The missing citations mean this clearance
|
||
does not extend to the productive tenant. Any future review brief is
|
||
scoped to named files with a size budget, because this one ran unbounded.
|
||
|
||
## 2026-09-16 — `abap-adt-mcp` registration is a manual step; read-only first
|
||
|
||
- What changed: an attempt to write `~/.abap-adt-mcp/systems.json` and to
|
||
register `abap-adt-mcp` in the project MCP configuration was refused by
|
||
Claude Code's permission guard as self-modification. Nothing was written.
|
||
I confirmed the development tenant logs in on client 100. The package's
|
||
SSO login launches Chrome visibly (`headless: false`), so the MCP server
|
||
needs the desktop session's display variables.
|
||
- Why: I want agent-side source writes (OQ-9), and registration is the
|
||
gate.
|
||
- Affected: PRD OQ-9, project `.mcp.json` (only once registered by hand),
|
||
CLAUDE.md MCP routing (only once adopted).
|
||
- Decision: the registration is run by hand, not routed around the guard.
|
||
The first configuration is read-only (`policy.readOnly: true`,
|
||
`allowedPackages: ["ZARENA_PLM"]`, `MCP_READ_ONLY=1`), limited to the
|
||
development tenant, and pinned to 2.1.0. The first login waits for the
|
||
source review verdict. Writes are enabled only after a read-only
|
||
`getObjectSource` on the behavior pool's Local Types include succeeds.
|
||
|
||
## 2026-09-16 — Community `abap-adt-mcp` smoke-tested read-only; not adopted yet (OQ-9)
|
||
|
||
- What changed: I ran `abap-adt-mcp` 2.1.0 once through `npx` over stdio.
|
||
It ran with `MCP_READ_ONLY=1` and a scratchpad systems file listing only
|
||
the development tenant, restricted to `ZARENA_PLM`. `initialize` and
|
||
`tools/list` answered: 173 tools, including source read/write and
|
||
activation. `listSystems` showed the read-only, package-restricted policy
|
||
enforced. There was no login and no SAP call. Nothing was registered in
|
||
any Claude Code or project configuration (verified 03:12). The package
|
||
remains in the local npx cache. I opened OQ-9.
|
||
- Why: SAP's ADT MCP cannot write source (V-4), so every RAP source is
|
||
pasted by hand. A server that can read and write source would remove that
|
||
step and would also let me read the behavior pool's Local Types include
|
||
directly.
|
||
- Affected: PRD OQ-9, V-4 (possible alternative), CLAUDE.md MCP routing (a
|
||
change only on adoption).
|
||
- Decision: I do not adopt it mid-build. Only four pastes and one publish
|
||
remain on the UI leg. The package was published the same day, by one
|
||
maintainer, and would hold a browser SSO session into the tenant, so it
|
||
gets a source review before any login. I run it read-only first. The
|
||
productive tenant `my429480` is never listed in its systems file.
|
||
|
||
## 2026-09-16 — Wave C active: behavior pool and UI projection view live; wave D created
|
||
|
||
- What changed: I activated U6 (base BDEF) and U7 (behavior pool
|
||
`ZBP_R_CHANGEAPPROVAL`) together in one call, then U8 (UI projection
|
||
view `ZC_CHANGEAPPROVAL`). All answered "Activation successful." The
|
||
locally cached class metadata shows the class active with category
|
||
`behaviorPool`. I then created wave D empty: U9 projection BDEF
|
||
`ZC_CHANGEAPPROVAL` (`.bdef.abdl`), U11 access control
|
||
(`.dcls.acds`), U12 metadata extension (`.ddlx.acds`) and U13 service
|
||
definition `ZUI_ARENA_CHANGE_APPROVAL` (`.srvd.acds`). `SRVD/SRV` also
|
||
offers an optional `referencedObject` create field [source: adt-mcp
|
||
abap_activate_objects, abap_creation-create_object,
|
||
get_object_type_details on 0M7DEJI, verified 2026-09-16].
|
||
- Why: wave C of the UI leg. Wave D is the last paste group before the UI
|
||
binding.
|
||
- Affected: dev tenant `ZARENA_PLM`, PRD RAP BO status, handover README
|
||
(BDEF extension `.bdef.abdl` for U9 and W3; SRVD tag list), KNOWLEDGE.md.
|
||
- Decision: I do not record `OPTIONS PRIVILEGED ACCESS`,
|
||
`%op-%action-<name>` on MODIFY response rows or `@status-rejected` as
|
||
proven yet. Activation returns no warnings, and no source says whether a
|
||
behavior pool with an empty Local Types include fails activation. I
|
||
confirm the handler source is in the Local Types include in the editor
|
||
first. Failing that, the first action call at U15 proves it at runtime.
|
||
I correct the handover README's BDEF extension and SRVD tag list in one
|
||
pass after the UI leg, rather than interrupting the paste session.
|
||
|
||
## 2026-09-16 — Wave B active: base behavior definition and root access control live
|
||
|
||
- What changed: I activated U10, the access control `ZR_CHANGEAPPROVAL`,
|
||
and U6, the managed `strict ( 2 )` behavior definition
|
||
`ZR_CHANGEAPPROVAL`. Both answered "Activation successful." U6 activated
|
||
through its `.bdef.abdl` URI on the first attempt, before its behavior
|
||
pool class existed. That also proves the three action-parameter entities
|
||
it references are active. I then created wave C empty: U7, the behavior
|
||
pool `ZBP_R_CHANGEAPPROVAL` (`create_object` returned only the global
|
||
`.clas.abap` path, no local-types include), and U8, the UI projection view
|
||
`ZC_CHANGEAPPROVAL` (`.ddls.acds`) [source: adt-mcp abap_activate_objects,
|
||
abap_creation-create_object on 0M7DEJI, verified 2026-09-16].
|
||
- Why: wave B of the UI leg.
|
||
- Affected: dev tenant `ZARENA_PLM`, PRD RAP BO status, handover README
|
||
(the BDEF activation extension is `.bdef.abdl` for U6, U9 and W3, and the
|
||
U6 fallback was not needed), KNOWLEDGE.md.
|
||
- Decision: now that an empty `ZBP_R_CHANGEAPPROVAL` exists, I activate U6
|
||
and U7 together in one call, so the BDEF is never checked against a class
|
||
that is not yet a behavior pool. The activation tool returns no warnings,
|
||
so warnings about the four unmapped calculated fields are checked in the
|
||
editor's Problems view rather than assumed absent. I locate the
|
||
local-types include live, after the global class part is saved.
|
||
|
||
## 2026-09-16 — Wave A active: table, parameter entities and root view live; wave B created
|
||
|
||
- What changed:
|
||
- I activated U1 `ZCHANGEAPPROVAL`, U2–U4 (the three action-parameter
|
||
entities) and U5 `ZR_CHANGEAPPROVAL` on `my431353`. Each activation
|
||
answered "Activation successful.", and the tool returned no warnings.
|
||
- The table activates through its `.tabl.ddic` URI; `.tabl.json` holds
|
||
only header metadata.
|
||
- U5's `cast( case … as abap_boolean preserving type )` was accepted, so
|
||
the fallback is not needed [source: adt-mcp abap_activate_objects on
|
||
0M7DEJI, verified 2026-09-16].
|
||
- I then created wave B empty: U6, the managed BDEF `ZR_CHANGEAPPROVAL`
|
||
(`create_object` returned `…/zr_changeapproval.bdef.abdl`), and U10, the
|
||
access control `ZR_CHANGEAPPROVAL` (`…/zr_changeapproval.dcls.acds`,
|
||
with `protectedEntity`).
|
||
- Why: wave A of the UI leg. Creating the U6 BDEF requires the root view to
|
||
be active, and it validated, which confirms U5 is active.
|
||
- Affected: dev tenant `ZARENA_PLM`, PRD RAP BO status, the handover README
|
||
activation table (TABL now proven; BDEF extension open), KNOWLEDGE.md.
|
||
- Decision: BDEF source is pasted into `.bdef.abdl`, not `.bdef.json`. At
|
||
U6 activation I try the `.bdef.abdl` URI first and fall back to
|
||
`.bdef.json`, which activated a generator BDEF on 2026-09-15. The README
|
||
activation table is corrected once U6 proves the extension. Activation
|
||
gives no direct active/inactive readback, so proof is indirect: U6's
|
||
activation is the first test of U2–U4, because U6 names them as action
|
||
parameters.
|
||
|
||
## 2026-09-16 — Review fixes applied to the handover; duplicate checks read with privileged access
|
||
|
||
- What changed: all four remaining review fixes are in `docs/handover/rap/`.
|
||
- `use etag` sits in the entity header of both projection BDEFs.
|
||
- `retrySync` writes APPROVED, so EXECUTING is written only by
|
||
`markExecuting`.
|
||
- All six action handlers set `%fail-cause` and `%op-%action-<name>`,
|
||
merge the internal UPDATE's failed and reported rows, and return
|
||
results only for keys that did not fail.
|
||
- The base BDEF declares `validation checkDuplicate on save { create; }`.
|
||
Its handler refuses a second non-REJECTED record with the same
|
||
`ItemNumber` + `ChangeType` + `ArenaEcoId`, within the request or
|
||
against persisted rows.
|
||
|
||
The base BDEF and README carry the OQ-8 note that `authorization master
|
||
( none )` is not final. The table's paste target is `.tabl.ddic`; its
|
||
activation extension is still pending live proof. Two of my working
|
||
sessions wrote these files concurrently between 02:36 and 02:43. I
|
||
confirmed the result is consistent and stable (content unchanged over 45
|
||
seconds at 02:45, no duplicate governance entries). This session is now
|
||
the only one driving the build.
|
||
- Why: review findings B1, M1, m1 and m4 (entry below). Every one must be
|
||
in the source before its object is pasted.
|
||
- Affected: handover U6, U7, U9, W3, U1 header, README; PRD RAP BO status.
|
||
- Decision: the duplicate check reads `ZR_CHANGEAPPROVAL` with privileged
|
||
access. The view is access-controlled, and a handler `SELECT` on it
|
||
without privileged access breaks the RAP implementation rules [source:
|
||
sap-docs sap-help abaprap_impl_rules; abap-docs
|
||
/abap-docs-cloud/ABAPSELECT_PRIVILEGED_ACCESS, verified 2026-09-16]. The
|
||
validation's failed rows carry only `cause-unspecific`, the only cause
|
||
validations may use (same rules page). Three constructs are syntax I
|
||
prove only at tenant activation, each with a documented fallback:
|
||
`OPTIONS PRIVILEGED ACCESS` (fallback `FROM … WITH PRIVILEGED ACCESS`),
|
||
`%op-%action-<name>` on MODIFY response rows, and `preserving type` on
|
||
the U5 casts.
|
||
|
||
## 2026-09-16 — Root view U5 final: derived booleans cast as a whole
|
||
|
||
- What changed: in `zr_changeapproval.ddls.asddls`, `IsApprovable` and
|
||
`IsRetriable` are now `cast( case status when … then abap.char'X' else
|
||
abap.char' ' end as abap_boolean preserving type )`. The file header
|
||
records why: typed `abap.char` literals make the CASE result CHAR(1)
|
||
[source: abap-docs /abap-docs-cloud/ABENCDS_TYPED_LITERAL_V2, verified
|
||
2026-09-16], and `ABAP_BOOLEAN` is "of data type `CHAR` of length 1"
|
||
[source: abap-docs /abap-docs-standard/ABENDATAOBJECTS_TRUE_VALUE_GUIDL,
|
||
verified 2026-09-16], so `preserving type` matches exactly. U5 is cleared
|
||
for paste.
|
||
- Why: review finding (4). A cast inside a CASE branch drops the data
|
||
element semantics.
|
||
- Affected: handover U5, wave A paste.
|
||
- Decision: if activation still rejects `preserving type`, I drop only
|
||
that addition, not the outer cast. I finalized U5 ahead of the remaining
|
||
correction work so wave A is not held up. Two concurrent corrections
|
||
collided on this file; each later brief names file ownership explicitly.
|
||
|
||
## 2026-09-16 — App documentation aligned to retry → APPROVED
|
||
|
||
- What changed: I updated the four statements of the retry transition in
|
||
`app/` (README, both i18n `#XBUT` comments, the mock `metadata.xml`
|
||
comment) from FAILED → EXECUTING to FAILED → APPROVED. No labels,
|
||
annotations, manifest or mock data changed. `npm run lint` and
|
||
`npm run ts-typecheck` pass.
|
||
- Why: ARN-002 was amended today; the app's documentation must not
|
||
describe the old state machine.
|
||
- Affected: `app/README.md`, `app/webapp/i18n/i18n.properties`,
|
||
`app/webapp/i18n/i18n_en.properties`,
|
||
`app/webapp/localService/mainService/metadata.xml`, KNOWLEDGE.md.
|
||
- Decision: I do not add a mock `executeAction` handler to show the new
|
||
transition. The mock server ignores actions (KNOWLEDGE 2026-09-16), and
|
||
the live RAP service replaces the mock at V-2 within this build, so a
|
||
mock-only transition would be throwaway work. The remote
|
||
`ui5-mcp-server` cannot lint local files; I lint UI5 code locally until
|
||
that changes.
|
||
|
||
## 2026-09-16 — Pre-paste SAP review: one blocker, retry semantics corrected, authorization opened
|
||
|
||
- What changed: I reviewed all 18 handover sources read-only against ABAP
|
||
Cloud docs, clean-core release states, the PRD and the app contract. The
|
||
app contract holds (17 properties, 3 actions, entity set `ChangeApproval`,
|
||
no UI create/update/delete), and all 11 referenced SAP objects are clean
|
||
core level A [source: sap-released-objects sap_check_clean_core_compliance,
|
||
verified 2026-09-16]. The review found:
|
||
- One blocker: `use etag` sat in the body of both projection BDEFs, but
|
||
it belongs in the entity header [source: abap-docs
|
||
/abap-docs-cloud/ABENBDL_CHARACTER_PROJECTION, verified 2026-09-16].
|
||
- Two majors: retry semantics and missing per-operation authorization.
|
||
- Four minors.
|
||
I dispatched corrections before any affected source reached the tenant.
|
||
- Why: every defect caught here saves a paste-and-activate round trip
|
||
against the live tenant, and two of them were correctness defects, not
|
||
syntax.
|
||
- Affected: `docs/handover/rap/` (U5, U6, U7, U9, W3, README), PRD ARN-002,
|
||
RAP-2, new OQ-8, `app/` documentation comments, KNOWLEDGE.md.
|
||
- Decision:
|
||
- (1) `retrySync` goes FAILED → APPROVED, clears `ErrorMessage`, and the
|
||
worker re-claims the record through `markExecuting`. The earlier FAILED
|
||
→ EXECUTING could not be claimed, because `markExecuting` accepts only
|
||
APPROVED. Working around that would make a retried record
|
||
indistinguishable from one another run is executing, which is the
|
||
double-write risk ARN-006 exists for.
|
||
- (2) Duplicate staging is refused on create: a `checkDuplicate`
|
||
validation on the semantic key while a non-REJECTED record exists.
|
||
Webhook and delta poll can both deliver the same ECO, and I will not
|
||
leave idempotency to the executors alone.
|
||
- (3) Action handlers honor the RAP implementation contract (`%fail`,
|
||
`%op`, propagated UPDATE failures, results only for successful keys),
|
||
so the worker cannot read a failed `markSynced` as success.
|
||
- (4) The derived boolean flags cast the whole CASE to `abap_boolean`,
|
||
because a cast inside a CASE branch drops the data element semantics
|
||
[source: abap-docs /abap-docs-cloud/ABENCDS_CAST_EXPRESSION_V2, verified
|
||
2026-09-16].
|
||
- (5) Deferred: a metadata-level mandatory `RejectReason`, until after
|
||
the POC (server-side enforcement exists).
|
||
- (6) Opened: OQ-8. `authorization master ( none )` stays for the
|
||
dev-tenant POC only and must be replaced before business roles get the
|
||
app.
|
||
|
||
## 2026-09-16 — Wave A created: table, parameter entities, root view exist empty
|
||
|
||
- What changed: I created U1 `ZCHANGEAPPROVAL` (TABL) and U2–U5
|
||
`ZD_CHANGEAPPROVAL_REJECTP`, `ZD_CHANGEAPPROVAL_SYNCEDP`,
|
||
`ZD_CHANGEAPPROVAL_FAILEDP` and `ZR_CHANGEAPPROVAL` (DDLS) in
|
||
`ZARENA_PLM`. They are inactive and have no source. `abap_transport-get`
|
||
answered `isRecordingRequired: false`. Each object passed validation and
|
||
creation with the handover JSON unchanged. The table's returned URI ends
|
||
in `.tabl.ddic`, not the `.tabl.json` that activated a generator-created
|
||
table on 2026-09-15 [source: adt-mcp abap_creation-create_object on
|
||
0M7DEJI, verified 2026-09-16].
|
||
- Why: wave A of the UI leg. The sources are pasted next.
|
||
- Affected: dev tenant `ZARENA_PLM`, PRD RAP BO status, handover activation
|
||
URI table (TABL extension open).
|
||
- Decision: I activate U1 with the URI `create_object` returned
|
||
(`.tabl.ddic`) and fall back to `.tabl.json`. The handover URI table is
|
||
corrected once activation proves which one works.
|
||
|
||
## 2026-09-16 — Package recreated; UI-leg build started in waves
|
||
|
||
- What changed: package `ZARENA_PLM` exists again under `ZLOCAL`. ADT MCP
|
||
validation of `ZCHANGEAPPROVAL` in it succeeded (live, 02:27). I started
|
||
wave A of the UI leg: U1–U5 (table, the three action-parameter entities,
|
||
root view) are created empty so their sources can be pasted. I also read
|
||
the create fields for classes, access controls and metadata extensions
|
||
live. Those were the three types the handover had marked unconfirmed.
|
||
Metadata extension names allow 40 characters. Access controls and
|
||
metadata extensions take an optional protected/extended entity (KNOWLEDGE
|
||
2026-09-16).
|
||
- Why: the from-scratch build (OQ-7) is unblocked. The build moves in waves
|
||
bounded by activation dependencies: BDEF creation needs its root view
|
||
active, and the binding needs its service definition active. Each wave
|
||
asks for one paste session per group, not one per file.
|
||
- Affected: dev tenant `ZARENA_PLM`, PRD RAP BO status, KNOWLEDGE.md.
|
||
- Decision: waves are A = U1–U5 (create, paste, activate), B = U6 base
|
||
BDEF, C = U7 behavior pool, D = U8 projection view + U10 root access
|
||
control, E = U9 projection BDEF + U11 + U12 + U13, F = U14 binding with
|
||
the service-alias check. Nothing is activated before its source is
|
||
pasted.
|
||
|
||
## 2026-09-16 — Handover regenerated under clean names; binding names cut to SAP's 26-character limit
|
||
|
||
- What changed: I regenerated `docs/handover/rap/` for a build from an
|
||
empty package. Eleven source files were renamed to the clean object
|
||
names, every internal reference was updated, and the README was replaced
|
||
with a create → paste → activate sequence per object. The UI service
|
||
definition exposes only `ChangeApproval`. A scripted comparison against
|
||
the app's mock `metadata.xml` confirms that the UI projection carries all
|
||
17 app properties plus `approve`, `reject` and `retrySync`. The build
|
||
splits into a 14-source UI leg and a 4-source worker leg. The
|
||
`markSynced`/`markFailed` parameter entities move into the UI leg,
|
||
because the base BDEF references them and they must be active first. I
|
||
amended RAP-5 to two service definitions with one binding each, and
|
||
updated both PRD interface-contract rows. A read-only SAP review of the
|
||
18 sources is running before the paste session.
|
||
- Why: the tenant package is empty, so the handover's generator inventory
|
||
and `ZZ…000` targets no longer existed. SAP Help gives a maximum of 26
|
||
characters for service binding names, the same in ABAP Cloud, SAP Cloud
|
||
Platform and ABAP Platform 2021 [source: sap-docs sap-help loio
|
||
4bad0d7280b742a68dd2d42b1441f09a, f3e608ace2a64aada33bdd3e2419113a,
|
||
777e027f61c3490dba0433443d9143a6, verified 2026-09-16]. The ADT MCP's
|
||
create metadata allows 30, and generator bindings of 29–30 characters
|
||
activated on 2026-09-15, but none was ever published. No source says
|
||
whether publishing tolerates more than 26.
|
||
- Affected: PRD RAP-5, the two approval-BO interface-contract rows, RAP BO
|
||
status, `docs/handover/rap/`, V-2 (the app's dataSource URL, mock
|
||
namespace and annotation targets now carry a planned difference),
|
||
KNOWLEDGE.md.
|
||
- Decision: the bindings are `ZUI_ARENA_CHANGE_APPR_O4` (24) and
|
||
`ZAPI_ARENA_CHANGE_APPR_A2X` (26). The service definitions keep
|
||
`ZUI_ARENA_CHANGE_APPROVAL` and `ZAPI_ARENA_CHANGE_APPROVAL`. I chose the
|
||
documented limit over the tool's undocumented allowance, because a
|
||
refusal at publish would come after the whole UI leg and need a delete in
|
||
ADT to recover. The app edit this causes is one URL segment plus the
|
||
namespace, both already scheduled for V-2 reconciliation against live
|
||
`$metadata`, so I defer it to that brief instead of changing the app
|
||
twice. The derived-field EDM types (`StatusCriticality` as INT1,
|
||
`abap_boolean` flags, `utclong`, `sysuuid_x16`) stay unverified until
|
||
live `$metadata` exists; they are not assumed.
|
||
|
||
## 2026-09-16 — Deletion verified live: package `ZARENA_PLM` is gone; name limits confirmed
|
||
|
||
- What changed: with the ADT MCP back online I probed `my431353` read-only.
|
||
`abap_creation-run_validation` answers "Package 'ZARENA_PLM' does not
|
||
exist" for tables, data definitions and classes, the same as a
|
||
nonexistent control package. The deletion removed the package itself, not
|
||
just its contents. `abap_creation-get_object_type_details` gives the
|
||
maximum name lengths: database table 16; data definition, service
|
||
definition, service binding and behavior definition 30 [source: adt-mcp
|
||
abap_creation-get_object_type_details on 0M7DEJI, verified 2026-09-16].
|
||
- Why: the from-scratch build starts from the package, and every clean name
|
||
had to fit its limit before any object is created.
|
||
- Affected: PRD RAP BO status, `docs/handover/rap/README.md` (step 0 is now
|
||
"recreate the package"), KNOWLEDGE.md.
|
||
- Decision: I recreate `ZARENA_PLM` under `ZLOCAL` under the same name, so
|
||
every activation URI pattern verified on 2026-09-15 stays valid. All clean
|
||
names fit (`ZCHANGEAPPROVAL` 15, `ZUI_ARENA_CHANGE_APPROVAL_O4` 28).
|
||
`ZLOCAL` means no transport request on every create while I prototype. It
|
||
is not a dead end for production: a package can be reassigned from
|
||
`ZLOCAL` to `ZCUSTOM_DEVELOPMENT` (transport layer YDEV) later, though not
|
||
the reverse [source: sap-docs sap-help loio
|
||
a0d80f14fcb74cb1ac8fb6f3d9ad48cc (2608), verified 2026-09-15]. I make
|
||
that move once the approval app works end to end on the development
|
||
tenant.
|
||
|
||
## 2026-09-16 — Tenant package emptied; from-scratch build under names that match the Fiori app
|
||
|
||
- What changed: the `ZARENA_PLM` contents on `my431353` were deleted in ADT.
|
||
This includes both generator sets and the empty hand-created objects. I
|
||
have not yet verified the deletion live (the ADT MCP is offline), and the
|
||
package's own survival is unconfirmed. I closed OQ-7 and dispatched a
|
||
regeneration of `docs/handover/rap/` under the clean names.
|
||
- Why: the Fiori app binds to
|
||
`/sap/opu/odata4/sap/zui_arena_change_approval_o4/srvd/sap/zui_arena_change_approval/0001/`,
|
||
entity set `ChangeApproval`, and actions `approve`, `reject` and
|
||
`retrySync` (`app/webapp/manifest.json`, mock `metadata.xml`). A Fiori app
|
||
runs against a replacement service only if the entity set names,
|
||
properties and actions match [source: fiori-mcp-server search_docs
|
||
"Replacing OData Service in an Adaptation Project", verified 2026-09-16].
|
||
With the package empty, no leftover objects compete for these names.
|
||
- Affected: PRD OQ-7 (closed), RAP BO status, `docs/handover/rap/` (all 19
|
||
sources and the README), V-2 (the service identity is now designed to
|
||
match the app instead of reconciled after the fact).
|
||
- Decision: no generator this time, because it forces a `ZZ` prefix and a
|
||
`000` suffix (KNOWLEDGE, 2026-09-15). I create each object through the ADT
|
||
MCP under its final name: table `ZCHANGEAPPROVAL`, `ZR_CHANGEAPPROVAL`,
|
||
`ZBP_R_CHANGEAPPROVAL`, `ZC_CHANGEAPPROVAL`, SRVD
|
||
`ZUI_ARENA_CHANGE_APPROVAL`, SRVB `ZUI_ARENA_CHANGE_APPROVAL_O4`. The A2X
|
||
names are unchanged. The UI leg (about 13 sources) is built and verified
|
||
against the app before the worker leg starts.
|
||
|
||
## 2026-09-16 — Tenant state corrected: two generator sets, no designed logic deployed; naming decision opened
|
||
|
||
- What changed: a live ATC run over `ZARENA_PLM` returned 43 objects, not
|
||
the 12 my 2026-09-15 handover README lists. The package holds two default
|
||
`x-ui-service` generator sets side by side: the `ZZ…000` set
|
||
(`ZZCHNGPPROVAL000`, `ZZR_/ZZC_CHANGEAPPROVAL000`, binding
|
||
`ZZUI_ARENA_CHANGE_APPRVL000_O4`) and a set without the suffix
|
||
(`ZZCHANGEAPPROVAL`, `ZZR_/ZZC_CHANGEAPPROVAL`, binding
|
||
`ZZUI_ARENA_CHANGE_APPROVAL_O4`). Each set has its own behavior pools and
|
||
SAP object types. It also holds the five empty, inactive hand-created
|
||
objects and the probe class. None of the six actions, the status machine,
|
||
or the feature control exists in any tenant object. The designed source
|
||
lives only in `docs/handover/rap/`, which is now committed and pushed
|
||
(`f8b45ea`). My most likely explanation for the second set is an earlier
|
||
generator run that I never recorded; I cannot confirm it, because the ADT
|
||
MCP has no read tool.
|
||
- Why: my 2026-09-15 entry and the PRD status described a clean skeleton
|
||
that was ready for a paste session. Following them would put the sources
|
||
into objects whose names the Fiori app does not bind to.
|
||
- Affected: PRD status (RAP BO → blocked on OQ-7), new OQ-7,
|
||
`docs/handover/rap/README.md` (its object inventory is stale), the Fiori
|
||
app's V-2 service identity.
|
||
- Decision: none yet. I recommend building under clean names that match the
|
||
app, next to the unused sets, and deferring deletion. The two sets are
|
||
unpublished, their `ZZ` names do not collide with the clean set, and
|
||
deleting them needs Eclipse ADT, which is not set up. Of the 19 sources,
|
||
13 serve the UI milestone. The six A2X-leg files wait until the app runs
|
||
against the real service.
|
||
|
||
## 2026-09-15 — abapGit researched: not required for ADT for VS Code; viable as a bulk source-load path
|
||
|
||
- What changed: I verified that abapGit is neither required nor used by SAP's
|
||
ADT for VS Code; the belief traces to the community `vscode-abap-remote-fs`
|
||
extension on this host. In S/4HANA Cloud Public Edition, abapGit is SAP's
|
||
supported fork reachable only through the Eclipse ADT "abapGit Repositories"
|
||
plug-in, and SAP lists it as the initial-transfer tool for developer
|
||
extensibility code in every delivery model [source: sap-docs sap-help loio
|
||
ec943b4ee4ac4dfdac47081d1d3e4019 "Overview of ABAP Lifecycle Management
|
||
Options", verified 2026-09-15]. Recorded as a KNOWLEDGE landmine.
|
||
- Why: the RAP handover (19 ready-to-paste sources under `docs/handover/rap/`)
|
||
is blocked on source entry because the ADT MCP Server cannot write source
|
||
(PRD V-4). abapGit pull from a repository is the one SAP-standard bulk
|
||
alternative to pasting file by file in the editor.
|
||
- Affected: KNOWLEDGE.md, PRD V-4 (an option, not a change of decision).
|
||
- Decision: keep VS Code editor paste as the default for this first BO (19
|
||
files, one-off); evaluate the abapGit pull path only if a second bulk load
|
||
is needed, because it requires Eclipse ADT plus an abapGit-formatted
|
||
repository with the metadata files the serializer expects.
|
||
|
||
## 2026-09-15 — Approval BO skeleton generated on `my431353`; source handover written
|
||
|
||
- What changed: I generated the Arena change-approval RAP business object
|
||
into `ZARENA_PLM` with SAP's "OData UI Service from Scratch" generator
|
||
(transactional without draft, 13 business fields incl. `SapPreview` as
|
||
string): table `ZZCHNGPPROVAL000`, root view/BDEF/DCL `ZZR_CHANGEAPPROVAL000`,
|
||
behavior pool `ZZBP_R_CHANGEAPPROVAL000`, UI projection
|
||
`ZZC_CHANGEAPPROVAL000` (+ BDEF, metadata extension, DCL, pool), service
|
||
definition + OData V4 UI binding `ZZUI_ARENA_CHANGE_APPRVL000_O4`
|
||
(unpublished), SAP object type/node type — all active, ATC: 0 findings on
|
||
12 objects (live, 2026-09-15). For the worker I created a separate A2X
|
||
projection `ZC_CHANGEAPPROVAL_A2X` (+ DCL) and service definition
|
||
`ZAPI_ARENA_CHANGE_APPROVAL`, plus three abstract entities for action
|
||
parameters; these exist empty and inactive. The A2X BDEF and the Web API
|
||
binding `ZAPI_ARENA_CHANGE_APPROVAL_A2X` cannot be created until their
|
||
referenced objects are active. Nineteen ready-to-paste source files and an
|
||
ordered paste-and-activate sequence are in `docs/handover/rap/`.
|
||
- Why: RAP-1..8; the MCP creates structure but not source (V-4), so logic —
|
||
six actions with instance feature control, status transitions, the
|
||
on-modify determination, text/criticality/semantic-key annotations — is
|
||
delivered as source for the VS Code editor.
|
||
- Affected: dev tenant `ZARENA_PLM`; PRD interface contracts (binding names
|
||
now real), RAP-5/RAP-6 wording, status; KNOWLEDGE (generator landmines).
|
||
- Decision: (1) two service definitions, not one — a projection BDEF exposes
|
||
only what it lists, so sharing one definition would hand the UI create and
|
||
the worker actions [source: abap-docs /abap-docs-cloud/ABENBDL_USE_PROJECTION,
|
||
verified 2026-09-15]; the UI gets `ZZUI_ARENA_CHANGE_APPRVL000_O4`, the
|
||
worker `ZAPI_ARENA_CHANGE_APPROVAL_A2X`. (2) `markSynced`/`markFailed` take
|
||
abstract-entity parameters, since action input must be an abstract entity
|
||
or DDIC type [source: abap-docs /abap-docs-cloud/ABENBDL_ACTION_INPUT_PARAM,
|
||
verified 2026-09-15]. (3) Derived fields (`StatusCriticality`, `StatusText`,
|
||
`IsApprovable`, `IsRetriable`) are CASE expressions in the root view, not
|
||
persisted — falsifiable at activation; fallback documented in the file
|
||
header. (4) `authorization master ( none )`: IAM catalog + DCL are the only
|
||
access control (ADR-002) [source: abap-docs /abap-docs-cloud/ABENBDL_AUTHORIZATION,
|
||
verified 2026-09-15]. (5) Generator naming (`ZZ…000`) is kept; the Fiori
|
||
app reconciles from live `$metadata` at V-2.
|
||
|
||
## 2026-09-15 — Write path proven: probe class created and activated in `ZARENA_PLM`; RAP build dispatched
|
||
|
||
- What changed: after the owner created development package `ZARENA_PLM`
|
||
under `ZLOCAL` in Eclipse ADT, the ADT MCP created `ZCL_ARENA_V4_PROBE`
|
||
there and activated it (no transport, as SAP Help states for `ZLOCAL`
|
||
sub-packages from 2508 [source: sap-docs loio a0d80f14fcb74cb1ac8fb6f3d9ad48cc,
|
||
verified 2026-09-15]). Object-type probes: DDLS/BDEF/SRVB/TABL creation
|
||
takes metadata only (name, package, referenced object, BDEF root entity and
|
||
implementation type, SRVB binding type incl. "OData V4 - Web API"), never
|
||
source. I granted `rap-developer` the `adt-mcp` tools and pointed it at the
|
||
dev tenant, then dispatched the approval-BO build.
|
||
- Why: V-1b and V-4 are closed; the RAP track (RAP-1..8) has no remaining
|
||
gate.
|
||
- Affected: PRD V-1b/V-4 (closed), status RAP BO (In progress),
|
||
`.claude/agents/rap-developer.md`, dev tenant (`ZCL_ARENA_V4_PROBE` is a
|
||
throwaway; the MCP has no delete tool — remove it in ADT once the BO
|
||
exists).
|
||
- Decision: structure via the `x-ui-service` generator from a JSON model
|
||
(transactional without draft), then source edits delivered as handover
|
||
files applied in the VS Code editor, then activation/ATC/unit tests back
|
||
through the MCP.
|
||
|
||
## 2026-09-15 — Correction: A4C catalogs are right; the write block was the package, not the role
|
||
|
||
- What changed: I withdraw my earlier suggestion to check the role for an
|
||
`SAP_A4_BC_*` catalog. `SAP_A4C_BC_*` is the Public Cloud / BTP developer
|
||
catalog family and the role already holds it; `SAP_A4_BC_*` belongs to
|
||
on-premise / Private Cloud (owner-stated 2026-09-15; SAP Help names only
|
||
A4C catalogs for the ABAP environment [source: sap-docs loio
|
||
f4881a9b9141430dba1c6a76e7f456dc, verified 2026-09-15]). Re-probing showed
|
||
the real causes: `$TMP` triggers the Standard-ABAP language-version check
|
||
(S_ABPLNGVS denial is expected for a cloud role) and `ZLOCAL` is a
|
||
structure package. Both recorded as KNOWLEDGE landmines.
|
||
- Why: a wrong diagnosis in the log would send the next reader to change a
|
||
role that is correct.
|
||
- Affected: KNOWLEDGE.md, PRD V-1b wording.
|
||
- Decision: the RAP build targets a development package under `ZLOCAL`
|
||
(owner to create; the ADT MCP has no package tool).
|
||
|
||
## 2026-09-15 — V-4 probe: MCP write path shape known; first write blocked by S_ABPLNGVS
|
||
|
||
- What changed: with destination `0M7DEJI` logged on, the ADT MCP Server
|
||
lists it and answers for the dev tenant (verified 2026-09-15). Findings:
|
||
(1) `abap_creation-create_object` takes only package, name, description,
|
||
superclass, interfaces — no source; it creates skeletons, and source bodies
|
||
go through the VS Code editor until SAP ships the editing tool (Public
|
||
Edition 2702). (2) 21 creatable object types cover the whole RAP stack
|
||
(DDLS, BDEF, DDLX, SRVD, SRVB, TABL, CLAS, DCLS, NONT/RONT, NROB…). (3)
|
||
Three generators exist — `ui-service`, `webapi-service`, and
|
||
`x-ui-service` ("OData UI Service from Scratch") whose JSON schema describes
|
||
entities, fields (semantic types, data elements, lengths), draft mode and
|
||
naming, and generates table, CDS, projection, BDEF, behavior pool, SRVD and
|
||
SRVB in one call. (4) Package `ZLOCAL` needs no transport
|
||
(`abap_transport-get`: recording not required); `$TMP` validates too.
|
||
(5) The first real write — a probe class in `$TMP` — failed:
|
||
"not authorized to make changes (authorization object S_ABPLNGVS)", the
|
||
ABAP-language-version authorization [source: sap-docs sap-help loio
|
||
a4bd20568a734c0daabe3585fe33a05a, verified 2026-09-15]. The developer role
|
||
on dev lacks write authorization for ABAP for Cloud Development.
|
||
- Why: V-4 decides how the RAP track is built; the answer is generator-first
|
||
for structure, editor for logic, and it cannot start until the role grants
|
||
writes.
|
||
- Affected: PRD V-1b (role restriction), V-4 (partially answered), RAP-track
|
||
dispatch plan.
|
||
- Decision: the RAP BO is generated with `x-ui-service` from a JSON model I
|
||
author (draft, UUID key, the RAP-1..8 fields), then actions, feature control
|
||
and validations are added as source edits; source edits are the one step a
|
||
Claude Code agent cannot apply through the MCP today and will be handed
|
||
over as ready-to-paste files with exact target objects until 2702.
|
||
|
||
## 2026-09-15 — Dev-tenant communication arrangements for this package in place
|
||
|
||
- What changed: on `my431353`, `AZ_INTEGRATION_DEV` / `AZ_API_USER` now
|
||
carries `AZ_IDENTITY_PROVISIONING_INT` (0193), `AZ_PRODUCT_MASTER_INT`
|
||
(0837), `AZ_PLM_DOC_INFO_INT` (0105) and `AZ_PLANT_CONFIG_INT` (0108),
|
||
alongside the pre-existing `AZ_COMM_MGMT_INT` (0A48). Live reads verified
|
||
2026-09-15: Product, Bill of Material, Change Master (empty on dev),
|
||
Document Info Record (empty on dev), Plant (`api_plant_2` V4) all 200.
|
||
`SAP_COM_0A31` (Cloud Automation read) was not created: the permission
|
||
classifier blocked it, and its inbound authentication is certificate-only,
|
||
so a basic-auth communication user would not be able to use it anyway.
|
||
- Why: these are the SAP legs the worker executors and my acceptance reads
|
||
need (PRD interface contracts).
|
||
- Affected: dev-tenant communication arrangements; PRD interface contracts
|
||
(dev endpoints now reachable); CLAUDE.md live-check note.
|
||
- Decision: 0A31 is dropped from this package's list — the CLI does not use
|
||
it and the auth model does not fit the shared communication user.
|
||
|
||
## 2026-09-15 — ADT MCP Server live on this host; registered as `adt-mcp`
|
||
|
||
- What changed: SAP's ADT MCP Server (extension `sapse.adt-vscode` 1.1.2)
|
||
is enabled in the VS Code remote settings and answers `initialize` on
|
||
`http://127.0.0.1:2236/mcp` as "ADT MCP Server 1.0.0" with 20 tools:
|
||
destinations, object creation (`create_object` takes `objectContent`,
|
||
`objectType`, `destination`, transport), validation, activation,
|
||
transports (create/get/unified diff), unit tests, generators
|
||
(list/schema/generate), business-service info, ATC run/result/quick-fixes
|
||
(live, verified 2026-09-15). I registered it in `.mcp.json` as `adt-mcp`
|
||
(HTTP, bearer header). `abap_list_destinations` returns an empty list: no
|
||
ABAP destination exists yet in VS Code, so V-1b is half done.
|
||
- Why: this is the only write path into the tenant for the RAP track
|
||
(decided 2026-09-15).
|
||
- Affected: `.mcp.json` (git-ignored), PRD V-1b, V-4.
|
||
- Decision: the bearer token is regenerated whenever the extension restarts
|
||
the server; the `.mcp.json` entry must be refreshed from
|
||
`~/.vscode-server/data/Machine/settings.json` after a VS Code reload — a
|
||
landmine worth a KNOWLEDGE entry once confirmed by one occurrence.
|
||
|
||
## 2026-09-15 — V-1 confirmed live: developer role on `my431353`; 0193 arranged; CLI now targets dev
|
||
|
||
- What changed: `sap-api users getRoles --user AZAW` on the development
|
||
tenant returns eight roles including `ZBR_DEVELOPER` (the `SAP_BR_DEVELOPER`
|
||
template) and `ZBR_ADMINISTRATOR_SW_DEV` (live, 2026-09-15). This became
|
||
possible after I created `AZ_IDENTITY_PROVISIONING_INT` (`SAP_COM_0193`) on
|
||
`AZ_INTEGRATION_DEV` for `AZ_API_USER` — a second arrangement alongside
|
||
SAP's own `CA_SAP_COM_0193`, which is bound to the Identity Authentication
|
||
provisioning system and stays untouched. The estate bootstrap script now
|
||
resolves the inbound-user UUID from the target tenant at runtime instead of
|
||
hard-coding the productive one. `_shared/.env` now carries the dev-tenant
|
||
credential (productive copy kept as `.env.prod-my429480.bak`), so the CLI
|
||
targets `my431353` by default.
|
||
- Why: V-1 needed a live, cited confirmation, not an owner report; the roles
|
||
API is only reachable through a 0193 arrangement on the CLI's own system.
|
||
- Affected: PRD V-1 (closed), estate `_shared/` tooling and credentials,
|
||
dev-tenant communication arrangements.
|
||
- Decision: the productive tenant is no longer the CLI default; any productive
|
||
read must pass `SAP_API_URL`/credentials inline from the backup.
|
||
|
||
## 2026-09-15 — Development tenant reachable; communication layer bootstrapped
|
||
|
||
- What changed: the `sap-api` CLI now logs on to `my431353` with the
|
||
communication user `AZ_API_USER` on communication system
|
||
`AZ_INTEGRATION_DEV` (credentials kept in `~/projects/sap-integrations/.env`,
|
||
one level above `_shared/`; the CLI's own loader still reads `_shared/.env`,
|
||
which holds a stale productive credential — 401 on both tenants). Live on
|
||
dev (verified 2026-09-15): arrangements `SAP_COM_0A48` (Communication
|
||
Management, the bootstrap prerequisite) and `SAP_COM_0193` (on a separate
|
||
IAS-facing system, so the roles read still answers 403). The scenario
|
||
catalog was refreshed (363 scenarios). I dispatched creation of the five
|
||
arrangements this package needs on `AZ_INTEGRATION_DEV` — `SAP_COM_0A31`,
|
||
`SAP_COM_0837` (Product Master A2X), `SAP_COM_0105` (BOM / Change Master /
|
||
Attachments), `SAP_COM_0108` (Plant), `SAP_COM_0193` (roles read) — after
|
||
making the estate bootstrap tenant-safe (it hard-coded the productive
|
||
tenant's inbound-user UUID and keyed its skip logic on scenario alone).
|
||
- Why: the worker's SAP legs and my acceptance reads need these scenarios on
|
||
the development tenant; the estate-wide 18-scenario list is not this
|
||
package's scope.
|
||
- Affected: `_shared/bootstrap-comm-arrangements.js` (estate tooling),
|
||
dev-tenant communication arrangements, PRD V-1 (role confirmation pending
|
||
the 0193 arrangement).
|
||
- Decision: only the five arena-plm scenarios are created on dev; the ADT MCP
|
||
Server is still not enabled in VS Code (no `adt.mcpServer.*` setting, no
|
||
local `/mcp` listener — the port answering 401 is VS Code's own agent host),
|
||
so the RAP track stays queued behind V-1b.
|
||
|
||
## 2026-09-15 — V-1 opened: development tenant `my431353` with developer role; write path to the tenant identified
|
||
|
||
- What changed: developer access on the development tenant
|
||
`my431353.s4hana.cloud.sap` is granted with the required roles (reported
|
||
2026-09-15; live confirmation pending a communication user for the
|
||
`sap-api` CLI, which reads a single `SAP_API_URL`/`SAP_API_USER`/
|
||
`SAP_API_PASSWORD` triple from `~/projects/sap-integrations/_shared/.env`
|
||
and currently answers 401 against both tenants). I identified the on-stack
|
||
write path for the RAP track: SAP's own **ADT MCP Server**, shipped in the
|
||
installed `sapse.adt-vscode` 1.1.2 extension, exposed as a local HTTP MCP
|
||
endpoint `http://localhost:<port>/mcp` with an auto-generated bearer token
|
||
(settings `adt.mcpServer.enabled` / `.port` / `.token`) [source: extension
|
||
`package.json` contributes.configuration, verified 2026-09-15]. Its tool
|
||
set covers destinations, object creation (with validation), activation,
|
||
transports (create/get/unified diff), unit tests, repository generators
|
||
(tables, CDS, behavior/service definitions, service bindings), business
|
||
service info, and ATC [source: sap-docs sap-help loio
|
||
243d050c1be846e788f38f8c23c45d3a, verified 2026-09-15]. ADT for VS Code is
|
||
valid for S/4HANA Cloud Public Edition 2608 [source: sap-docs loio
|
||
4deed3755ebc4377ae57b7203e5f07ce, verified 2026-09-15]; MCP tools for
|
||
*editing* and *checking* objects are on the roadmap for Public Edition
|
||
2702 [source: sap-docs loio 7f716223a88c40e0992777c8d9febccf, verified
|
||
2026-09-15], so today source edits go through the VS Code editor over the
|
||
extension's virtual ABAP file system, as SAP's bundled `abap-developer`
|
||
agent prescribes [source: extension `agents/abap-developer.agent.md`,
|
||
verified 2026-09-15].
|
||
- Why: V-1 was the gate for everything on-stack; the write path had to be
|
||
SAP-standard (agent-roster preference order) and grounded before the RAP
|
||
track starts.
|
||
- Affected: PRD V-1, V-4 (new), agent roster (rap-developer tool surface),
|
||
`.mcp.json` (pending: ADT MCP registration).
|
||
- Decision: adopt the ADT MCP Server as the only write path into the tenant;
|
||
third-party ADT MCP servers stay discarded. Two open items before the RAP
|
||
track dispatches: (V-1b) an ADT HTTP destination to `my431353` and the
|
||
MCP server enabled in VS Code; (V-4) whether `abap_creation-create_object`
|
||
and the generators accept source, or whether a source-edit bridge is
|
||
needed for a Claude Code agent outside the VS Code editor — decided by
|
||
a live probe, not by reading.
|
||
|
||
## 2026-09-14 — Worker corrections accepted (contract v0.2.1); review wave closed
|
||
|
||
- What changed: a full ingest buffer at poll time now fails the tick (cursor
|
||
holds, health `degraded`, next tick re-covers the window); the object-type
|
||
token is `DOCUMENTS`; every emitted status code is governed — `default`
|
||
problem+json on all four operations, 415 and 413 on both POSTs, route-level
|
||
404 documented as the default case; the surface is JSON-only (the built-in
|
||
`text/plain` parser is removed so unsupported media types answer 415);
|
||
`processed` is absent until an object has run; `/health` and run snapshots
|
||
carry only fixed, allow-listed error phrases (upstream bodies and messages
|
||
never reach the wire); TTL and delta-feed comments no longer assert what no
|
||
source records. 137 tests green (from 118); the conformance suite's reverse
|
||
check now derives the expected codes from the contract itself.
|
||
- Why: closes review findings B1–B6 and A4.
|
||
- Affected: `worker/`, `docs/api/worker.openapi.json` (0.2.0 → 0.2.1),
|
||
ARN-001 (token), ARN-003, ARN-009.
|
||
- Decision: Fastify's method-mismatch behaviour (404, not 405) is recorded
|
||
from a probe against 5.12.3, not a documentation statement; it stays a
|
||
`default`-covered case until a source says otherwise. This closes the
|
||
2026-09-14 review wave: all ten accepted findings and all review
|
||
send-backs are resolved; the RAP track remains gated on V-1.
|
||
|
||
## 2026-09-14 — Fiori app: review corrections accepted
|
||
|
||
- What changed: the app now carries the binding-derived identity
|
||
(`zui_arena_change_approval_o4` in URL and namespace), the six-state status
|
||
domain with eight mock rows, Approve/Reject only on the object page with the
|
||
staged payload in its own facet ahead of the decision, table selection off,
|
||
a launchpad inbound `ArenaChangeApproval-manage`, the three-part semantic
|
||
key, `DecidedBy`, an unbounded `SapPreview`, and no dead annotation
|
||
registrations in the mock/local YAML. Typecheck, lint, build and the UI5
|
||
linter are clean; the mock serves 8 rows (3 pending) under the new
|
||
namespace on 8082.
|
||
- Why: closes review findings A1–A6, A8, A9.
|
||
- Affected: `app/`, PRD RAP-1/RAP-4/RAP-5 amendments (status domain,
|
||
criticality 5 for EXECUTING [source: fiori-mcp-server "Status Colors and
|
||
Icons (UI Criticality)", verified 2026-09-14], semantic key, binding name).
|
||
- Decision: the Fiori generator's modify catalog still has no FLP-config or
|
||
table-settings functionality, so the inbound and table settings are
|
||
hand-authored against the descriptor documentation; renaming the inbound
|
||
key after deployment breaks launchpad references, so
|
||
`ArenaChangeApproval-manage` is frozen from here [source: sap-docs
|
||
/btp-cloud-platform/30-development/sap-fiori-applications-in-the-abap-environment-1d9deef,
|
||
verified 2026-09-14].
|
||
|
||
## 2026-09-14 — SAP review verdicts: both scopes sent back narrowly; namespace claim corrected
|
||
|
||
- What changed: the read-only SAP review returned "send back, narrowly" for
|
||
the Fiori app and "accept with minors, conditional on one reversal" for the
|
||
worker. I accepted every finding and dispatched two correction briefs in
|
||
parallel. I also correct my own claim from earlier today: the OData V4
|
||
namespace and the first URL segment derive from the service **binding**
|
||
(group) name, not the service definition — the tenant serves
|
||
`/api_currencyexchangerate/srvd_a2x/sap/currencyexchangerate/0001` with
|
||
namespace `com.sap.gateway.srvd_a2x.api_currencyexchangerate.v0001`, and
|
||
SAP Help shows `/api_product/srvd_a2x/sap/product/0002` [source: sap-docs
|
||
sap-help loio 5f45f125dfe84c20beb18f5de1512f5a; tenant EDMX line 55 and
|
||
`exchange-rates-cap/package.json:33,39`, verified 2026-09-14]. Strongly
|
||
indicated for custom UI bindings, not yet proven; V-2 confirms it.
|
||
- Why: naming and state-machine decisions are cheap now and expensive once
|
||
the RAP BO exists; the worker's drop-on-full-buffer trade-off violated
|
||
ARN-003's intent by losing a poll window with no recovery path today.
|
||
- Affected: `app/`, `worker/`, `docs/api/worker.openapi.json` (→ 0.2.1),
|
||
PRD ARN-001/ARN-002 wording, interface-contract rows, RAP-track
|
||
requirements, KNOWLEDGE landmine text.
|
||
- Decision: (1) provisional identity is binding `ZUI_ARENA_CHANGE_APPROVAL_O4`,
|
||
definition `ZUI_ARENA_CHANGE_APPROVAL`, URL first segment and namespace from
|
||
the binding. (2) The approval state machine gains post-execution states:
|
||
PENDING → APPROVED → EXECUTING → SYNCED | FAILED, REJECTED terminal, FAILED
|
||
→ retrySync → EXECUTING; the worker drives EXECUTING/SYNCED/FAILED through
|
||
actions on the A2X binding so an approved record can never be executed
|
||
twice (ARN-006). (3) Approve/Reject leave the list toolbar and live only on
|
||
the object page, where the staged payload is shown in its own facet before
|
||
the decision (ARN-010 is not decorative). (4) The object-type token is
|
||
`DOCUMENTS` everywhere (PRD ARN-001 is the requirement source); the worker
|
||
contract follows. (5) A full ingest buffer at poll time is a tick failure:
|
||
the cursor holds and health degrades; duplicates on recovery are accepted
|
||
because SAP is the ledger. (6) Every status code the worker emits is
|
||
governed by a `default` problem+json response plus explicit 415/413.
|
||
(7) Error text in `/health` and run snapshots is a fixed phrase, never a
|
||
raw upstream message. (8) `ApprovedBy` becomes `DecidedBy`; the semantic
|
||
key is `ItemNumber + ChangeType + ArenaEcoId`; the staged payload is
|
||
`abap.string` on the RAP side.
|
||
|
||
## 2026-09-14 — Worker contract conformance is now a test, not a review step
|
||
|
||
- What changed: I added `worker/test/contract.test.ts` (35 tests): every
|
||
`components.schemas.*` in `docs/api/worker.openapi.json` compiles under the
|
||
JSON Schema 2020-12 dialect, every documented status code of every operation
|
||
is exercised through the real Fastify instance and its body validated
|
||
against the contracted schema, all error bodies are `application/problem+json`,
|
||
and 5xx bodies carry no upstream or internal detail. A reverse check fails
|
||
the suite if a status code is added to the contract without a test. 118
|
||
tests green. Dev dependencies added: `ajv` 8.20, `ajv-formats` 3.0 (test
|
||
only; Ajv was already transitive via Fastify).
|
||
- Why: ARN-009 says the implementation conforms to the contract; today's
|
||
review found `/health` drifting off its enum. A schema-driven suite turns
|
||
that class of finding into a red test.
|
||
- Affected: `worker/test/`, `worker/package.json`, ARN-009.
|
||
- Decision: the reserved 502 response stays unattached to any operation and is
|
||
covered only through the error-handler path until a route calls Arena
|
||
synchronously.
|
||
|
||
## 2026-09-14 — Fiori app rebound to the SAP gateway service shape; UX polished
|
||
|
||
- What changed: I rewrote the mock service and every annotation target to the
|
||
shape an ABAP Cloud OData V4 UI service emits (`com.sap.gateway.srvd.
|
||
zui_arena_change_approval.v0001`, alias `SAP__self`, `ChangeApproval_Type`,
|
||
entity set `ChangeApproval`), re-pointed the manifest to the UI-binding URL,
|
||
renamed the app id to `com.minicircuits.arenaplm` (the folder stays the
|
||
structural `app/`), seeded six mock rows across all four states, pinned the
|
||
mock server to port 8082, and polished the UI: semantic key on the item
|
||
number, default sort (status, then newest request) with a PENDING default
|
||
filter loaded on start, importance tiers for responsive columns, hidden
|
||
technical fields, a second header facet with the Arena ECO and SAP change
|
||
number, an approvals icon, multi-line staged payload, and status-dependent
|
||
action availability via `Core.OperationAvailable` on `IsApprovable` /
|
||
`IsRetriable`. Typecheck, lint, build and the UI5 linter are clean; the
|
||
mock service answers `$metadata`, the entity set (6 rows, 3 pending) and the
|
||
annotation file with 200.
|
||
- Why: the review's ship-blocker — annotations against an invented namespace
|
||
silently render nothing on the real service [source: KNOWLEDGE.md
|
||
2026-09-14 landmine]. Polish makes the approver's landing page the pending
|
||
queue, which is the job the app exists for (ARN-002, ARN-010).
|
||
- Affected: `app/` (metadata, mock data, annotations, manifest, i18n,
|
||
Component, ui5*.yaml, package.json, OPA journeys, README), PRD RAP-track
|
||
requirements (harvested below), V-2.
|
||
- Decision: the Fiori generator's modify catalog covers no annotation or
|
||
manifest-setting change, so these edits are hand-authored against cited
|
||
Fiori Elements documentation; the manifest `_version` moved to 2.11.0 to
|
||
match `minUI5Version` 1.152 [source: sap-docs /sapui5/03_Get-Started/step-10,
|
||
verified 2026-09-14]. The `ui5-mcp-server` cannot see this filesystem
|
||
(ENOENT on realpath), so UI5 linting ran through `@ui5/linter` directly.
|
||
|
||
## 2026-09-14 — Worker review fixes landed; contract v0.2.0
|
||
|
||
- What changed: contract first, then code: `/health` session state enum is
|
||
`none|active|expired|refreshing`, `status` turns `degraded` on the last poll
|
||
or login failure and a `poller` block reports last run/success/error;
|
||
`SyncRunRequest` is strictly `additionalProperties:false` with no type
|
||
coercion and no defaults; the webhook intake answers 503 + `Retry-After` when
|
||
the bounded buffer (`WEBHOOK_QUEUE_MAX_SIZE`, default 10000) is full; a
|
||
reserved 502 response maps upstream Arena errors without leaking bodies.
|
||
In code: the session TTL now flows from config by construction (a rename is
|
||
a compile error), the poll cursor advances only after a successful fetch,
|
||
shutdown drains in-flight runs and the current poll tick under
|
||
`SHUTDOWN_TIMEOUT_MS` through one Fastify `onClose` path, HTTP calls carry
|
||
`ARENA_HTTP_TIMEOUT_MS`, integer env parsing is strict, duplicate
|
||
`SYNC_OBJECT_ORDER` entries are rejected, and `npm run dev` loads `.env` when
|
||
present. 83 tests green (from 37); build and lint clean.
|
||
- Why: six verified correctness findings, all latent until the real Arena
|
||
client lands — cheapest to fix before it does.
|
||
- Affected: `worker/`, `docs/api/worker.openapi.json` (0.1.0 → 0.2.0), ARN-005,
|
||
ARN-009.
|
||
- Decision: a full buffer during a poll drops the overflow and still advances
|
||
the cursor (retrying the window would duplicate the events that fit); those
|
||
changes are recovered by the V-3 durable cursor, not by the worker. I am
|
||
having this trade-off reviewed. The worker package version stays 0.1.0
|
||
until a release; `/health.version` reports it.
|
||
|
||
## 2026-09-14 — ADR-003 gate hardened; secret-bearing files git-ignored
|
||
|
||
- What changed: I closed the four governance findings from the review. The
|
||
consult gate now covers Bash/MultiEdit/NotebookEdit/filesystem-MCP writes,
|
||
only grounding-server and web consultations refresh the marker, hooks
|
||
resolve the repo from `CLAUDE_PROJECT_DIR`, the gate fails closed without
|
||
`jq`, `worker/` is no longer SAP-gated, and a 37-case pipe-test harness
|
||
guards the scripts. `.gitignore` now excludes `.mcp.json` (live tokens),
|
||
`.claude/settings.local.json`, `**/.vscode/`, `**/.remember/`,
|
||
`app/.appGenInfo.json`; a dry-run `git add -A` stages none of them.
|
||
- Why: enforcement that the standard tools bypass is prose, not structure
|
||
(ADR-003's premise); and the repo's first commit must not publish tokens.
|
||
- Affected: `.gitignore`, `.claude/settings.json`, `.claude/hooks/*`
|
||
(+ `tests/run.sh`), docs/adr/ADR-003 (amended).
|
||
- Decision: fail closed on a missing classifier dependency, accepting that a
|
||
host without `jq` cannot edit anything in this repo until it is installed.
|
||
|
||
## 2026-09-14 — Code review accepted; correction to the scaffold entry; hardening wave dispatched
|
||
|
||
- What changed: I ran a full code review over the package (31 candidate
|
||
findings, all verified, none refuted) and accepted its top ten as the next
|
||
build wave. I also correct my 2026-09-14 scaffold entry below: the generator
|
||
emitted app id `com.minicircuits.app` (not `com.minicircuits.arenaplm`), no
|
||
mock rows were seeded (the mockdata path did not exist), and the mock server
|
||
was not pinned to port 8082. Those three claims described intent, not the
|
||
repo; this wave makes them true.
|
||
- Why: two findings are ship-blockers. (1) `.mcp.json` carries live bearer
|
||
tokens and is not git-ignored in a repo with zero commits. (2) Every
|
||
annotation target in the Fiori app uses the invented namespace
|
||
`com.minicircuits.arenaapproval`; an ABAP Cloud OData V4 service emits
|
||
`com.sap.gateway.<srvd|srvd_a2x>.<service>.v0001` with alias `SAP__self` and
|
||
`<Entity>_Type` entity types, so against the real service the List Report
|
||
would render with no columns, filters, facets or actions — and the mock hid
|
||
it because mock metadata and annotations agreed with each other [source:
|
||
live tenant my429480 EDMX, `API_CURRENCYEXCHANGERATE.edmx` lines 55/57/95,
|
||
verified 2026-09-14]. The remaining findings are worker correctness bugs
|
||
(session TTL silently discarded, poll cursor advanced before fetch, /health
|
||
off-contract, non-strict Ajv, unbounded queue, SIGTERM killing runs) and the
|
||
ADR-003 gate being bypassable (Bash/MultiEdit writes unmatched; any MCP call
|
||
refreshing the marker; absolute hook paths).
|
||
- Affected: `.gitignore`, `.claude/` (hooks, settings), `worker/`,
|
||
`docs/api/worker.openapi.json` (→ v0.2.0), `app/` (metadata, manifest,
|
||
annotations, mock data, app id), PRD interface contracts, V-2, status.
|
||
- Decision: I split the approval-BO service into two bindings — an OData V4
|
||
**UI** binding for the Fiori app and an OData V4 **Web API (A2X)** binding
|
||
for the worker's technical user — because SAP's own path builds the Fiori UI
|
||
on a UI service binding [source: sap-docs sap-help loio
|
||
5717c0a1dafc4335add0207b81c39cef, verified 2026-09-14]. The app now targets
|
||
the provisional identity `zui_arena_change_approval` (namespace
|
||
`com.sap.gateway.srvd.zui_arena_change_approval.v0001`); the exact
|
||
namespace, entity-type suffix and URL segment are reconciled against the
|
||
live `$metadata` at V-2 before any deploy. Worker contract v0.2.0: session
|
||
state enum gains `expired`/`refreshing`, `status` becomes `degraded` on poll
|
||
or login failure, `SyncRunRequest` is strictly `additionalProperties:false`,
|
||
and the webhook intake returns 503 when the bounded buffer is full. Gate
|
||
hardening: only the grounding servers refresh the consult marker; Bash,
|
||
MultiEdit, NotebookEdit and filesystem-MCP writes are gated; hooks resolve
|
||
the repo from `CLAUDE_PROJECT_DIR`; the gate fails closed without `jq`; the
|
||
non-SAP `worker/` path leaves the SAP gate. I dispatched the three
|
||
independent streams (config hardening, worker fixes, Fiori correction +
|
||
polish) in one parallel wave; tests and the read-only SAP review are gated
|
||
behind them.
|
||
|
||
## 2026-09-14 — Fiori Elements UI scaffolded (com.minicircuits.arenaplm), on mock, at the package root
|
||
|
||
- What changed: I scaffolded the approval workbench's Fiori Elements List
|
||
Report / Object Page UI as `com.minicircuits.arenaplm` (TypeScript, UI5
|
||
1.152) in the structural `app/` subfolder (sibling to `worker/`; the folder
|
||
name is structural, not the app identity) — generated via the Fiori tools
|
||
MCP `generate_fiori_app_odata`.
|
||
It runs on a MOCK OData V4 service: entity `ChangeApproval` whose fields I
|
||
grounded in the predecessor's real `approvals` contract
|
||
(`docs/predecessor-flow.md`), with `Status` carrying a distinct `FAILED`
|
||
state per ARN-002; audit fields (`RequestedBy`/`ApprovedBy`/`DecidedOn`) and
|
||
`StatusCriticality` are inferred and flagged for reconciliation. Curated
|
||
`UI.LineItem`/`HeaderInfo`/`SelectionFields`/`FieldGroup`+`Facets`; 4 seeded
|
||
mock rows. Dev/mock server pinned to port 8082 (8080 is a local app on the
|
||
dev host). The Fiori generator recognizes the app at the root
|
||
(`list_functionality` returns the modify catalog).
|
||
- Why: to stand up the launchpad UI layer (ARN-007) now and make it iterable
|
||
with the Fiori generator without waiting on the gated on-stack RAP service —
|
||
the proven label-poc mock-first pattern. The live predecessor (`arena-plm` on
|
||
CF, verified up: `/api/health` 200, v0.0.1) is the base of record for the
|
||
domain/field shape.
|
||
- Affected: `app/` (new app files: `webapp/`, `ui5*.yaml`, `package.json`,
|
||
`tsconfig.json`); `worker/` untouched; root `.gitignore` covers `app/`.
|
||
No PRD requirement completed — this is interim mock UI.
|
||
- Decision: the mock OData service (`com.minicircuits.arenaapproval` /
|
||
`zarena_change_approval`) is a stand-in; the real binding is the RAP
|
||
approval-BO service (V-2), and the mock entity is the reconciliation target
|
||
once that service exists. App id follows the estate `com.minicircuits.*`
|
||
convention; the app lives in the structural `app/` subfolder (sibling to
|
||
`worker/`) — the folder name is structural, not the app identity.
|
||
|
||
## 2026-09-10 — Build wave 1 closed: worker scaffold accepted against the contract
|
||
|
||
- What changed: I accepted the connectivity-worker scaffold in `worker/`
|
||
after two correction rounds at the contract seam: `scope` made required and
|
||
the request's `objects` selector honored; all 400/401/404 bodies moved to
|
||
RFC 9457 `application/problem+json`; the wire SyncRun aligned to the
|
||
amended contract (execution-ordered `objects` progress array, no
|
||
`objectOrder`); and unknown request properties strictly rejected
|
||
(Ajv `removeAdditional: false`) rather than silently stripped. Final state
|
||
verified by my own run: build, lint, and 37 tests green. Stack: Fastify
|
||
5.12, TS ~5.9 (pinned — see the KNOWLEDGE.md toolchain entries), Vitest 4,
|
||
Node 24.
|
||
- Why: API-first (ARN-009) is only real if the implementation is held to the
|
||
contract at review — and silent stripping of unknown properties is the
|
||
same quiet-divergence failure class the rest of this package's enforcement
|
||
exists to prevent.
|
||
- Affected: worker/ (accepted), docs/api/worker.openapi.json (final v0.1.0),
|
||
PRD status.
|
||
- Decision: next worker wave is the live Arena client POC (session, delta via
|
||
the outbound-integration queue per the V-3 findings); the S/4HANA executor
|
||
leg stays stubbed until V-2 defines the approval-BO service binding.
|
||
|
||
## 2026-09-10 — Predecessor flow extracted; new tombstones harvested; ARN-010 adopted
|
||
|
||
- What changed: I extracted the predecessor's real end-to-end mechanism into
|
||
`docs/predecessor-flow.md` (with file:line cites): it is an operator-driven
|
||
staging workbench — the webhook never syncs (a literal TODO), there is no
|
||
scheduler, BOM/document writes are non-idempotent, `REJECTED` conflates
|
||
human rejection with SAP failure, and the approved preview is discarded at
|
||
execution time. I harvested the durable behavioral findings into
|
||
KNOWLEDGE.md (BOM `EngineeringChangeDocForEdit` / `HeaderChangeDocument`,
|
||
`IsActiveForChangeNumber` silent-discard, ProductDescription full-key PATCH,
|
||
`ProcurementType`+`MRPType` coupling, Arena WORKING-revision overlay,
|
||
`/items/{guid}/changes` 404, no server-side date filter on `/changes`,
|
||
outbound-integration queue as the clean cursor, plus three landmines). I
|
||
adopted ARN-010 (the approved payload is the executed payload) and sharpened
|
||
ARN-002 (execution failure is a distinct state), ARN-006 (existence checks),
|
||
and V-3 (cursor mechanism findings).
|
||
- Why: the rebuild must be designed from verified behavior, not assumption —
|
||
and the extraction proved the approval workflow's authority was decorative
|
||
in the predecessor, which is exactly the class of defect the RAP BO design
|
||
must preclude structurally.
|
||
- Affected: docs/predecessor-flow.md (new), KNOWLEDGE.md, PRD.md (ARN-002,
|
||
ARN-006, ARN-010, V-3), CLAUDE.md (files map).
|
||
- Decision: executor, poller, and approval-domain design work cites
|
||
`docs/predecessor-flow.md` sections, not memories of the old code.
|
||
|
||
## 2026-09-10 — Worker API contract v0.1.0 accepted; sap-api CLI adopted; V-1 partially verified
|
||
|
||
- What changed: I accepted `docs/api/worker.openapi.json` v0.1.0 after running
|
||
an SAP API style review against the bundled style-guide references and
|
||
applying two corrections (SAP lifecycle metadata `x-sap-shortText` +
|
||
`x-sap-stateInfo: beta`; a documented 400 on `POST /admin/sync-runs`). I
|
||
adopted the `sap-api` CLI on this box for live tenant/Arena reads, EDMX
|
||
fetch, and OpenAPI generation (recorded in CLAUDE.md). Using it, I partially
|
||
verified V-1: my business user AZAW holds 172 roles but no
|
||
developer-extensibility role, and no such role exists in the tenant catalog
|
||
to assign — one must first be created from the `SAP_BR_DEVELOPER` template
|
||
[source: sap-docs /fiori-tools-samples/misc/s4hana/README + sap-help loio
|
||
e3527dfa1c5a41f69d4e63691f174f0a, verified 2026-09-10].
|
||
- Why: API-first (ARN-009) needs a governed, style-conformant contract before
|
||
the worker's surface hardens, and V-1 is the gate for the entire on-stack
|
||
track — every fact I can verify from this box now shortens the remaining
|
||
manual check.
|
||
- Affected: docs/api/worker.openapi.json, CLAUDE.md, PRD.md (V-1, status).
|
||
- Decision: read commands of `sap-api` are part of my design/acceptance
|
||
toolkit; mutating commands are delegated like any other write.
|
||
|
||
## 2026-09-10 — API-first adopted (ARN-009); build wave 1 dispatched
|
||
|
||
- What changed: I adopted the API-first rule — every interface this package
|
||
owns gets an OpenAPI 3.1 JSON contract under `docs/api/` before or with the
|
||
change (CLAUDE.md rule 7, PRD ARN-009). I designed the worker's inbound
|
||
surface (Arena webhook intake, health, sync-run admin; bearer placeholder
|
||
pending OQ-6) and dispatched build wave 1 as two parallel items: the
|
||
contract formalization and the TypeScript worker scaffold under `worker/`
|
||
(Arena session core per KNOWLEDGE.md, HTTP surface, delta-poller skeleton,
|
||
sync-executor stub — no SAP write code).
|
||
- Why: contracts must govern implementation from the first line of code, and
|
||
the worker track is the only unblocked track while V-1 is unverified.
|
||
- Affected: CLAUDE.md (rule 7), PRD.md (ARN-009, interface contracts, status),
|
||
docs/api/ (new), worker/ (new, in progress).
|
||
- Decision: the on-stack RAP/Fiori track stays gated on V-1; nothing
|
||
SAP-write-shaped lands in the worker until the approval BO contract exists
|
||
(V-2).
|
||
|
||
## 2026-09-10 — CLAUDE.md brought up to date with the repo it maps
|
||
|
||
- What changed: I extended CLAUDE.md with what a fresh session needs but could
|
||
not previously see from it: the five-specialist delegation table (with
|
||
pointer to docs/agent-roster.md), an explicit dated repo-state note
|
||
(governance-only, no build/lint/test commands exist yet), the consult-gate
|
||
exemptions and remedy appended to rule 6, and Files-table rows for
|
||
docs/agent-roster.md and .claude/hooks/.
|
||
- Why: CLAUDE.md is the map, and it lagged the 2026-09-04 agent-roster and
|
||
enforcement-kit additions; a fresh session would also hunt for build tooling
|
||
that does not exist yet.
|
||
- Affected: CLAUDE.md, CHANGELOG.md. Rule numbering unchanged, so the rule-6
|
||
references in ADR-003 and the hooks stay valid.
|
||
- Decision: when the first implementation code lands, its commands are
|
||
recorded in CLAUDE.md in the same turn — the repo-state section says so.
|
||
|
||
## 2026-09-04 — Removed foreign sap-odata scaffold bundle; landmine recorded
|
||
|
||
- What changed: I removed a bundle that appeared in this repo at 14:40 without
|
||
my involvement — `.github/agents/` + `.github/skills/` (the retired,
|
||
fabricating sap-odata agent trio in GitHub-Copilot layout), a root
|
||
`AGENTS.md` routing to those agents, and `.vscode/mcp.json` pointing at a
|
||
Windows-only MCP binary that cannot run on this host. I recorded a
|
||
KNOWLEDGE.md landmine describing the bundle and its likely source (the
|
||
`harieprasad.sap-odata-mcp` VS Code extension scaffolding on folder open).
|
||
- Why: the root `AGENTS.md` would have been read as project instructions,
|
||
routing sessions to agents whose backing tools do not exist — the exact
|
||
fabrication failure this package's enforcement layer was built to prevent,
|
||
reintroduced silently on day one.
|
||
- Affected: `.github/` (deleted), `AGENTS.md` (deleted), `.vscode/mcp.json`
|
||
(deleted), KNOWLEDGE.md (landmine added). Nothing was committed before or
|
||
after; the repo's tracked-content plan is unchanged.
|
||
- Decision: the falsification test stands — if the bundle reappears on the
|
||
next VS Code open, the extension is confirmed as the writer and gets
|
||
uninstalled.
|
||
|
||
## 2026-09-04 — Specialist agent roster designed from verified research
|
||
|
||
- What changed: I ran a capped 4-agent research workflow (3 low-cost
|
||
researchers over GitHub / SAP Community / web, 1 adversarial verifier that
|
||
re-fetched every source: 37 findings → 22 confirmed, 14 downgraded or
|
||
refuted and discarded) and compiled the founding kit's dedicated-agent
|
||
layer: five specialists (`rap-developer`, `fiori-developer`,
|
||
`worker-developer`, `sap-code-reviewer` read-only, `test-engineer` on the
|
||
low-cost model) with tool restrictions as the role contract. Design and
|
||
citations in `docs/agent-roster.md`; file creation delegated to
|
||
`.claude/agents/`.
|
||
- Why: the last founding-kit gap was specialized, grounded agents; every
|
||
adopted pattern (restriction-as-enforcement, per-artifact MCP routing,
|
||
model-per-role, false-positive filtering) traces to a verified source, and
|
||
refuted sources are recorded so they are never re-researched.
|
||
- Affected: docs/agent-roster.md (new), .claude/agents/ (5 files, delegated),
|
||
PRD status.
|
||
- Decision: ADT MCP server adoption is recommended but gated on V-1 —
|
||
evaluate SAP's official ABAP MCP path first, ARC-1 / yzonur/sap-adt-mcp as
|
||
fallbacks; nothing installed until dev-tenant access is confirmed.
|
||
|
||
## 2026-09-04 — ADR-003 corrected: tool preloading already exists and is active
|
||
|
||
- What changed: I amended ADR-003's tool-loading section. Reading the
|
||
2026-09-03 performance-lag session transcript showed `ENABLE_TOOL_SEARCH=false`
|
||
is the preload lever (binary-verified there), that it only works before
|
||
bootstrap (settings.json `env` is too late), and that it is already active
|
||
machine-wide via the `claude()` wrapper in `~/.bashrc` — so sessions in this
|
||
repo start with all tools loaded. My earlier "no setting exists" claim was
|
||
wrong in practice; the SessionStart load-first order stays as fallback for
|
||
launch paths that bypass the wrapper.
|
||
- Why: the requirement "tools loaded automatically on session start" is
|
||
satisfied by existing machine config, and the record must say so accurately.
|
||
- Affected: docs/adr/ADR-003 (amended in place, correction dated).
|
||
- Decision: rely on the wrapper for preloading; keep the hook fallback.
|
||
|
||
## 2026-09-04 — Ground-truth enforcement kit installed (ADR-003)
|
||
|
||
- What changed: I added project hooks that make MCP-first grounding structural:
|
||
a SessionStart grounding charter, a per-prompt SAP-REFLEX injection, a
|
||
consultation gate that denies edits to SAP artifacts unless an
|
||
mcp__*/WebSearch/WebFetch consultation happened within 30 minutes, and a
|
||
citation duty (CLAUDE.md rule 6) with a reminder hook on governance-doc
|
||
edits. This kit becomes part of the founding kit for every future package.
|
||
- Why: the old estate proved advisory routing fails — the MCP servers and
|
||
skills were never consulted regardless of stack. Enforcement had to move from
|
||
prose to hooks. I verified against the Claude Code settings schema that no
|
||
preload setting exists for deferred tools; the slim loadout plus the
|
||
SessionStart load-first order is the working equivalent.
|
||
- Affected: .claude/settings.json, .claude/hooks/ (3 scripts), .gitignore,
|
||
CLAUDE.md (rule 6), docs/adr/ADR-003 (new).
|
||
- Decision: consultation is a precondition enforced by a deny gate, not a
|
||
guideline; uncited SAP claims are hypotheses.
|
||
|
||
## 2026-09-04 — Redesigned on-stack: RAP + Fiori in the tenant (ADR-002)
|
||
|
||
- What changed: I moved the target architecture into the S/4HANA tenant —
|
||
approval domain as a custom RAP business object, Fiori Elements app in the
|
||
tenant launchpad, IAM app/business catalog/business roles as the only access
|
||
control, custom CDS views for discoverability. Side-by-side shrinks to one
|
||
connectivity worker for Arena (webhook, polling, session, files, and
|
||
initially the sync executor). CAP exits the architecture; the MCP loadout
|
||
moved to sap-docs / abap-docs / sap-released-objects / fiori / ui5. PRD
|
||
rewritten (ARN-007/008 added, OQ-1..4 resolved, V-1..V-3 verification gates
|
||
added); ADR-001 amended.
|
||
- Why: the decisive test came from the business side — the showcased apps were
|
||
invisible from inside S/4HANA (not in the launchpad, not in Custom CDS
|
||
Views), reachable only through standalone URLs with weak control. A
|
||
side-by-side CAP app would fail the same test. I verified the on-stack path
|
||
(developer extensibility: RAP + Fiori deploy + IAM; key-user tier as
|
||
fallback) against SAP documentation via the MCP servers before deciding.
|
||
- Affected: PRD.md, CLAUDE.md, docs/adr/ADR-001 (amended), docs/adr/ADR-002
|
||
(new), .mcp.json (loadout).
|
||
- Decision: on-stack first — the tenant hosts the application; BTP hosts only
|
||
what the tenant cannot run. The launchpad is the only front door.
|
||
|
||
## 2026-09-04 — Package founded; knowledge bankruptcy declared
|
||
|
||
- What changed: I created this standalone package home under
|
||
`~/projects/sap-integrations-mcl/`, decoupled from the old multi-package
|
||
estate. I carried over only dated tombstones and landmines (`KNOWLEDGE.md`)
|
||
and the proven interface contracts (`PRD.md`); all other predecessor
|
||
knowledge is deliberately left behind, to be re-derived from code and live
|
||
systems as needed.
|
||
- Why: the single-estate setup had grown past what one working context can
|
||
maintain, and its accumulated undated knowledge had begun to rot. The Express
|
||
implementation also sat outside SAP's toolchain, so none of the SAP guidance
|
||
tooling ever engaged — a signal that the stack, not the tooling, was wrong.
|
||
- Affected: this package only. The predecessor at
|
||
`~/projects/sap-apps/arena-plm` is now reference-only.
|
||
- Decision: I chose a CAP-first rebuild over transplanting the Express app
|
||
(ADR-001), with a deliberately slim tool loadout (three MCP servers, seven
|
||
skills) matched to that stack.
|