ADR-004: back out of on-stack RAP; retarget to starter customizing tenant

Both tenants belong to the same starter system: my429480 is its
customizing tenant (client 100, key-user extensibility only, no ABAP)
and my431353 is its development tenant (client 080). This package had
recorded my429480 as "productive" and ADR-002 had assumed it offered
developer extensibility; both were wrong.

- ADR-004 withdraws the on-stack RAP route and moves the application to
  a side-by-side runtime against released OData APIs. ADR-002 marked
  superseded.
- Development tenant my431353 parked: all 19 ZARENA_PLM objects left
  active, sources kept in docs/handover/rap/ as reference, so the route
  stays reversible.
- Replacement host left open as OQ-11 (key-user extensibility vs CAP
  side-by-side); recommendation recorded as CAP. No build starts until
  OQ-11 is closed.
- RAP-dependent items V-2, V-3, OQ-5, OQ-8, OQ-9, OQ-10 parked rather
  than closed.
- Tenant references corrected across CLAUDE.md, KNOWLEDGE.md,
  app/README.md, the RAP handover README, the rap-developer agent and
  the reentrance-login helper README.

No SAP tenant was modified.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-29 10:33:29 -07:00
co-authored by Claude Opus 5
parent 468729eb4e
commit ffd33f4ec0
10 changed files with 332 additions and 57 deletions
+5 -1
View File
@@ -8,7 +8,11 @@ tools: Read, Grep, Glob, Edit, Write, Bash, mcp__abap-docs__*, mcp__sap-docs__*,
## Role
Implements on-stack ABAP Cloud artifacts for S/4HANA Public Cloud developer
extensibility on the development tenant `my431353` (ADT destination `0M7DEJI`; productive tenant `my429480`; API-only: no RFC, no custom IDocs): RAP
extensibility on the starter system's development tenant `my431353` (client 080; ADT destination
`0M7DEJI`) — **parked as of 2026-09-29**, objects left in place, so this role is dormant until the
client 080 track resumes; the working target is the starter system's customizing tenant `my429480`
(client 100), which supports key-user extensibility only and no ABAP/RAP. Both tenants are
API-only: no RFC, no custom IDocs. Scope when active: RAP
business objects for the approval domain, CDS entities and views, behavior
definitions/implementations, service definitions and bindings, and IAM apps —
business catalog + business roles are the only access control (ADR-002,
+89
View File
@@ -2,6 +2,95 @@
Append-only decision log for this package.
## 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/`
+65 -27
View File
@@ -6,23 +6,50 @@
## What this is
Approval-gated sync of Arena PLM items into SAP S/4HANA Public Cloud
(`my429480.s4hana.cloud.sap` productive; development tenant `my431353.s4hana.cloud.sap` since 2026-09-15 — API-only tenants: no RFC, no custom IDocs):
materials, BOMs, change masters, documents. Standalone successor to the Express
Approval-gated sync of Arena PLM items into SAP S/4HANA Public Cloud:
materials, BOMs, change masters, documents.
Both tenants named in this repo belong to the **same starter system**. The
working target is the starter system's **customizing tenant**
`my429480.s4hana.cloud.sap` (client 100 — key-user extensibility and
configuration only; no ABAP, no RAP). The starter system's **development
tenant** `my431353.s4hana.cloud.sap` (client 080 — developer extensibility) is
**parked as of 2026-09-29**, with the objects I built there left in place. Both
tenants are API-only: no RFC, no custom IDocs.
Standalone successor to the Express
implementation at `~/projects/sap-apps/arena-plm`, which is **reference-only**
— consult it for behavior, never extend it.
## Architecture (ADR-002, 2026-09-04 — on-stack first)
## Architecture (ADR-004, 2026-09-29 — side-by-side against released APIs)
The application lives **in the tenant**: a custom RAP business object for the
approval domain, a Fiori Elements app in the tenant's Fiori launchpad, IAM
app / business catalog / business roles as the only access control, and custom
CDS views for discoverability. Side-by-side is reduced to one hardened
TypeScript **connectivity worker** (Arena webhook/poll/session/files + initial
sync executor) — machine-to-machine only, no UI, no user-facing URLs.
The on-stack RAP route of ADR-002 is **withdrawn and superseded**. The starter
system's customizing tenant `my429480` (client 100) supports key-user
extensibility only — no ABAP, no RAP — so the custom RAP business object ADR-002
called for has no home in the tenant I work in.
The acceptance test: a business user finds the app in the Fiori launchpad and
its data in the Custom CDS Views app. Anything that fails that test is not done.
The application therefore runs **side-by-side against released OData APIs**,
with the customizing tenant as the sync target and configuration home. The
replacement host is deliberately left **open as OQ-11**: key-user extensibility
in the customizing tenant (custom business object plus a low-code UI) versus a
CAP service side-by-side on BTP. My recommendation is **CAP** — the
connectivity worker has to live side-by-side whatever else happens, and one
runtime beats two. **No build starts until OQ-11 is closed.**
Kept, unchanged in value: the hardened TypeScript **connectivity worker**
(Arena webhook/poll/session/files + initial sync executor) — machine-to-machine
only, no UI, no user-facing URLs, and needed under either OQ-11 option — and
the Fiori Elements app in `app/`, which is repointable.
**Parked reference, not deleted:** the RAP approval business object I built on
the starter system's development tenant `my431353` (client 080). All 19
`ZARENA_PLM` objects are left active there and their sources stay in
`docs/handover/rap/`, so that route stays reversible at zero cost.
The acceptance test, as amended by ADR-004: a business user finds the
application from the S/4HANA launchpad and access is governed by business
roles. The "its data in the Custom CDS Views app" clause is withdrawn — it is
unreachable from client 100.
## Operating rules
@@ -59,20 +86,24 @@ its data in the Custom CDS Views app. Anything that fails that test is not done.
| RAP guides, extensibility docs, SAP Help / Community | `sap-docs` |
| Is this SAP object released for ABAP Cloud? Successors? | `sap-released-objects` |
| Fiori Elements, `@UI` annotations, manifest | `fiori-mcp-server` |
| Writing objects INTO the development tenant (create/activate/transport/ATC/unit tests) | `adt-mcp` — SAP ADT MCP Server from `sapse.adt-vscode`, `http://127.0.0.1:2236/mcp`; bearer token lives in `~/.vscode-server/data/Machine/settings.json` and changes on VS Code reload — refresh `.mcp.json` then |
| Writing objects INTO the starter system's development tenant (create/activate/transport/ATC/unit tests) — **parked 2026-09-29 with that tenant** | `adt-mcp` — SAP ADT MCP Server from `sapse.adt-vscode`, `http://127.0.0.1:2236/mcp`; bearer token lives in `~/.vscode-server/data/Machine/settings.json` and changes on VS Code reload — refresh `.mcp.json` then |
| UI5 controls/views (only if custom UI proves necessary) | `ui5-mcp-server` |
When MCP guidance conflicts with training knowledge, follow MCP.
Live system checks from this box (verified 2026-09-15): the `sap-api` CLI
(`/usr/local/bin/sap-api`) reaches the **development** tenant `my431353` by
default (credentials in `~/projects/sap-integrations/_shared/.env`; the
productive credential is `.env.prod-my429480.bak`) and Arena — API catalog search,
Live system checks from this box: as of 2026-09-29 the `sap-api` CLI
(`/usr/local/bin/sap-api`) reaches the starter system's **customizing tenant**
`my429480` by default (credentials in
`~/projects/sap-integrations/_shared/.env`; the parked development-tenant
credential is `.env.starter-dev-my431353.bak` and the customizing-tenant copy is
`.env.starter-cust-my429480.bak`, both in the same folder) and Arena — API catalog search,
EDMX fetch, OpenAPI generation (`sap-api apis generateOpenapi --service …`),
communication arrangements (`comm`), user/role admin (`users`), and read paths
for the released business APIs and Arena items. Read commands are fair game
for design and acceptance; mutating commands are delegated like any other
write.
write. The retarget is in place, but the `my429480` credential itself answered
HTTP 401 ("Anmeldung fehlgeschlagen") on 2026-09-29 — it needs refreshing before
any CLI call against that tenant succeeds.
## Delegation (project agents in `.claude/agents/`)
@@ -83,20 +114,27 @@ verified sources: `docs/agent-roster.md`.
| Work | Agent |
|---|---|
| On-stack ABAP Cloud: RAP BO, CDS, behavior, IAM artifacts | `rap-developer` |
| On-stack ABAP Cloud: RAP BO, CDS, behavior, IAM artifacts — **dormant** while the RAP route is parked (ADR-004) | `rap-developer` |
| Fiori Elements app, `@UI` annotations, manifest, launchpad | `fiori-developer` |
| TS connectivity worker: Arena API, Cloud SDK OData writes | `worker-developer` |
| Read-only SAP review: clean core, contracts, tombstones | `sap-code-reviewer` |
| Tests for worker + service layers | `test-engineer` |
## Repo state & commands (verified 2026-09-14)
## Repo state & commands (verified 2026-09-29)
Implementation so far: the TypeScript connectivity worker in `worker/`
(Fastify surface + Arena session core; sync executors are stubs until V-2).
The on-stack RAP track has no code yet — gated on V-1. The Fiori Elements app
(`app/`, TypeScript) is scaffolded against a **mock** OData V4 service:
`npm run start-mock` serves it on port 8082; its service identity is
provisional until reconciled with the live RAP UI binding at V-2.
Nothing in this package has ever been deployed or reached a business user, and
no build resumes until OQ-11 is closed. What exists:
- `worker/` — the TypeScript connectivity worker (Fastify surface + Arena
session core; sync executors are stubs). Built, 137 tests green, never
deployed. Needed under either OQ-11 option.
- `app/` — the Fiori Elements app (TypeScript), bound to a **mock** OData V4
service: `npm run start-mock` serves it on port 8082. Its service identity is
provisional; it gets repointed once OQ-11 names the host.
- `docs/handover/rap/` — the sources for the 19 `ZARENA_PLM` objects I
activated on the starter system's development tenant `my431353`, parked
2026-09-29 with the objects left in place. Reference and a reversible route,
not a live track.
In `worker/`: `npm run build` (tsc), `npm run lint` (eslint), `npm test`
(vitest), `npm run dev` (tsx watch). The worker's HTTP surface is governed by
@@ -109,7 +147,7 @@ In `worker/`: `npm run build` (tsc), `npm run lint` (eslint), `npm test`
| `PRD.md` | Living requirements, target architecture, contracts, verification items |
| `CHANGELOG.md` | Append-only decision log |
| `KNOWLEDGE.md` | Dated tombstones & landmines — the only knowledge carried from the predecessor; also check it when anything unexpected appears in the repo |
| `docs/adr/` | Architecture decision records (ADR-001 amended by ADR-002) |
| `docs/adr/` | Architecture decision records (ADR-004 supersedes ADR-002 and partly revives ADR-001) |
| `docs/agent-roster.md` | Specialist-agent design + verified sources |
| `docs/predecessor-flow.md` | How the Express predecessor actually works (extracted 2026-09-10) — read before designing executor, poller, or approval behavior |
| `.claude/hooks/` | ADR-003 enforcement scripts (grounding injections, consult gate, consult marker); `tests/run.sh` pipe-tests them — run it after any hook change |
+9 -1
View File
@@ -7,7 +7,15 @@ re-learn. Everything else was deliberately left behind to be re-derived from
ground truth. Every entry is dated; re-verify on first POC contact. Add new
entries the same way — dated and falsifiable.
## SAP S/4HANA (tenant `my429480`, Public Cloud, API-only)
**Tenant note (2026-09-29).** Both tenants named below are tenants of the same
starter system: the customizing tenant `my429480` (client 100, key-user
extensibility and configuration only) and the development tenant `my431353`
(client 080, developer extensibility). The development tenant is **parked as of
2026-09-29** and its objects are left in place, so every `my431353` entry here is
a historical finding from the client 080 track, not a statement about the current
working target. The working target is `my429480`.
## SAP S/4HANA (starter system customizing tenant `my429480`, client 100, Public Cloud, API-only)
- [2026-09-04, verified by predecessor in live use] **BOM items must be POSTed
sequentially** after the header POST. Parallel item POSTs fail SAP's
+49 -22
View File
@@ -15,39 +15,63 @@ Views app, and access is governed by business roles** — with the side-by-side
footprint reduced to the one thing that cannot run in the tenant: Arena
connectivity.
**Amended 2026-09-29.** I wrote that acceptance test assuming I could build
in the tenant. I cannot, in the tenant I am now working in: the starter
system's customizing tenant `my429480` (client 100) supports key-user
extensibility only, so "its data in the Custom CDS Views app" is not
reachable there and the RAP half of the test is withdrawn (ADR-004). What I
keep is the part that actually mattered: **a business user finds the
application from the S/4HANA launchpad and access is governed by business
roles.**
In scope: material, BOM, change-master, and document sync from Arena to
S/4HANA, gated by a human approval workflow. Out of scope: every other package
of the old estate — one package at a time.
## Target architecture (ADR-002, 2026-09-04)
## Target architecture (ADR-004, 2026-09-29 — supersedes ADR-002)
The starter system's **customizing** tenant `my429480` (client 100) supports
**key-user extensibility only** — no ABAP, no RAP. ABAP development requires
the starter system's **development** tenant `my431353` (client 080), which I
parked on 2026-09-29 [source: fiori-tools-samples `misc/s4hana/README`
"Tenant Types", verified 2026-09-29]. The on-stack RAP business object of
ADR-002 therefore has no home in the tenant I am now working in, and the
application moves back out to a side-by-side runtime consuming released APIs.
```
Arena PLM ──webhook + delta poll──▶ Connectivity worker (BTP CF, hardened TS)
│ no UI, no user URLs; technical user
reads approved / │ writes staged changes
executes sync ▼ ▼ via approval BO service binding
┌─ SAP S/4HANA Cloud Public (my429480) ─────────────────────────────────────┐
│ Z RAP BO "Arena Change Approval" ← staging + state machine + audit │
│ Fiori Elements List Report / Object Page ← in the tenant LAUNCHPAD │
│ IAM app → business catalog → business roles ← the only access control │
│ Custom CDS views over the BO (join I_Product, …) ← Custom CDS Views app │
│ Released OData APIs (Product/BOM/ChangeMaster/Attachment) ← sync targets │
│ built, 137 tests green, NOT deployed
▼
Approval store + state machine + audit
(side-by-side — host is the open call, OQ-11)
│
Fiori Elements List Report / Object Page
(`app/` — already built, service-repointable)
│ released OData APIs, mc-s4hana
┌─ Starter system · CUSTOMIZING tenant `my429480` (client 100) ─────────────┐
│ Product / BOM / ChangeMaster / Attachment released APIs ← sync targets │
│ Key-user extensibility + configuration only — no ABAP, no RAP │
│ Launchpad reachability for the app: decided with OQ-11 │
└───────────────────────────────────────────────────────────────────────────┘
parked 2026-09-29 ──▶ Starter system · DEVELOPMENT tenant `my431353` (080)
19 RAP objects live in ZARENA_PLM, left in place
```
**Build state (2026-09-14):** the Fiori Elements UI layer is scaffolded as
`com.minicircuits.arenaplm` (List Report / Object Page, TS) in the structural `app/` subfolder
(sibling to `worker/`), running on a **mock** OData V4 service — an interim, generator-iterable
stand-in. The real on-stack RAP BO + service binding (ARN-002, V-2) and
launchpad deployment (ARN-007) remain gated on developer extensibility (V-1).
The predecessor `arena-plm` on CF is verified live (`/api/health` 200) and is
the base of record for the domain/field shape until the RAP service exists.
**Build state (2026-09-29).** What exists: the Fiori Elements UI
`com.minicircuits.arenaplm` in `app/`, built and bound to a mock OData V4
service; the connectivity worker in `worker/`, built with 137 tests green and
never deployed (no deployment descriptor was ever written); and 19 activated
RAP objects on the parked development tenant, with their sources kept in
`docs/handover/rap/` as reference. Nothing from this package has ever been
deployed to Cloud Foundry or reached a business user.
## Systems & boundaries
| System | Role | Boundary |
|---|---|---|
| SAP S/4HANA Cloud Public (`my429480`) | **Application host** (RAP BO, Fiori app, CDS views) and sync target | Developer extensibility (ABAP Cloud via ADT); released APIs only |
| Starter system, **customizing** tenant (`my429480`, client 100) | **Sync target** and configuration home | Key-user extensibility only — no ABAP, no RAP; released OData APIs via `mc-s4hana` |
| Starter system, **development** tenant (`my431353`, client 080) | **Parked 2026-09-29** — former RAP application host | Developer extensibility; 19 objects left active in `ZARENA_PLM`, no transport recording |
| Arena PLM (`api.arenasolutions.com/v1`) | Source of items, BOMs, changes, files | REST; webhook + delta poll, handled by the worker |
| Connectivity worker (BTP CF) | Arena connectivity + initial sync executor | Machine-to-machine only; technical user via communication arrangement |
@@ -105,7 +129,8 @@ once V-1 opens the development tenant.
## Architecture decisions
- ADR-001 — toolchain-must-engage rebuild; Express predecessor reference-only. **Amended by ADR-002.**
- ADR-002 — on-stack first: RAP + Fiori Elements in the tenant; side-by-side reduced to a connectivity worker; CAP exits the architecture.
- ADR-002 — on-stack first: RAP + Fiori Elements in the tenant; side-by-side reduced to a connectivity worker; CAP exits the architecture. **Superseded by ADR-004.**
- ADR-004 (2026-09-29) — I withdraw the on-stack RAP route and move the application back to a side-by-side runtime against released APIs. Two facts force it: the customizing tenant `my429480` (client 100) supports key-user extensibility only, and I am no longer willing to carry an ABAP/RAP build for this package. I park the development tenant `my431353` (client 080) with its 19 activated objects in place rather than delete them, so the route stays reversible. The replacement host — key-user extensibility in the tenant versus a CAP service side-by-side — is OQ-11; my recommendation is CAP, because the connectivity worker must be side-by-side regardless and one runtime beats two.
## Verification items & open questions
@@ -121,6 +146,8 @@ once V-1 opens the development tenant.
| OQ-10 | Ownership of UI annotations: the backend metadata extension `ZC_CHANGEAPPROVAL` or the app's local `annotation.xml`. Today 35 of the 58 local annotations override a backend annotation with the same target, term and qualifier (layering rule [source: fiori-mcp-server "Visualizing and Managing Annotations with SAP Fiori Tools - Service Modeler", verified 2026-09-16]), so a DDLX change to those terms is invisible in the app. The local file adds i18n labels, action criticality, the `#Default` variants and the facet IDs the OPA journey relies on | Open (2026-09-16). Interim rule: a term defined locally is changed locally. I consolidate before launchpad deployment |
| OQ-8 | Per-operation authorization for the approval BO. Today it is `authorization master ( none )`: any holder of the UI app can approve, reject and retry, and any tenant ABAP code can create and mark* through EML. SAP Help calls `( none )` "not recommended in real-world scenarios". The target is `( global )` with a `FOR GLOBAL AUTHORIZATION` handler and `AUTHORITY-CHECK OBJECT` on a custom authorization object: decisions for business roles, create/mark* for the communication role. First verify that custom authorization objects can be created on `my431353` [source: abap-docs /abap-docs-cloud/ABENBDL_AUTHORIZATION, ABAPHANDLER_METH_GLOBAL_AUTH; sap-docs sap-help loio 673c05562e144702a080c574c3da2da3, verified 2026-09-16 by my review] | Open (2026-09-16): does not block the dev-tenant UI POC; must close before any business role other than the developer's gets the app (IAM brief) |
| OQ-7 | Tenant object naming and cleanup for the approval BO | **Closed 2026-09-16.** The package was deleted in ADT, contents and package itself (verified live through ADT MCP validation, 2026-09-16). I build from scratch, without the generator: table `ZCHANGEAPPROVAL`, `ZR_CHANGEAPPROVAL`, `ZBP_R_CHANGEAPPROVAL`, `ZC_CHANGEAPPROVAL`, SRVD `ZUI_ARENA_CHANGE_APPROVAL` with SRVB `ZUI_ARENA_CHANGE_APPR_O4`, and SRVD `ZAPI_ARENA_CHANGE_APPROVAL` with SRVB `ZAPI_ARENA_CHANGE_APPR_A2X`. Binding names follow SAP's 26-character limit (RAP-5). Entity set is `ChangeApproval`; the A2X projection and parameter entity names are unchanged |
| OQ-11 | Where the approval store, state machine and audit live now that ADR-004 withdrew the RAP BO. Option A: key-user extensibility in the customizing tenant (custom business object + low-code UI) — stays in the tenant and in the launchpad natively, but the Arena connectivity still needs an outside worker, so the application ends up with two homes, and key-user objects are transport-bound. Option B: a CAP service side-by-side on BTP CF — one runtime with the worker, matches the archetype the rest of my estate already runs, and `app/` repoints to it cheaply because 35 of its 58 annotations are already local (OQ-10); the cost is BTP runtime and launchpad reachability becomes a federation question. | Open (2026-09-29). I recommend Option B. Decide before any further build. |
| OQ-12 | The ABAP/RAP-dependent items V-2, V-3, OQ-5, OQ-8, OQ-9 and OQ-10 are all scoped to the parked development tenant. They are **parked with ADR-004**, not closed; each returns only if the RAP route is revived. | Parked (2026-09-29) |
## Status
@@ -130,8 +157,8 @@ once V-1 opens the development tenant.
| Developer environment | Done (2026-09-04); MCP loadout revised to ABAP/RAP set (done 2026-09-04) |
| Ground-truth enforcement kit (ADR-003 hooks) | Done (2026-09-04); hardened 2026-09-14 — Bash/MultiEdit/filesystem writes gated, grounding-only marker refresh, portable paths, fail-closed, 37 pipe-tests green |
| Specialist agent roster (5 agents, docs/agent-roster.md) | Done (2026-09-04; all 5 files YAML-verified in .claude/agents/) |
| V-1…V-3 verification POC | Planned — V-1 (ADT access on my429480) is the user-side gate for everything on-stack |
| Fiori Elements app (`app/`, mock-bound) | Done for the mock stage (2026-09-14) — gateway service shape (binding-derived identity), six-state domain, polished List Report/Object Page, launchpad inbound `ArenaChangeApproval-manage`; SAP review findings closed. Deploy gated on V-1/V-2 (live `$metadata` reconciliation) |
| RAP BO (approval domain) | In progress (2026-09-16): from-scratch build in package `ZARENA_PLM` (under `ZLOCAL`, no transport recording) under the clean names (OQ-7 closed). The handover in `docs/handover/rap/` has all pre-paste review fixes applied and was stable as of 02:45. Wave A (U1–U5: table, three parameter entities, root view) was created empty at 02:30. Its sources were pasted at 02:47, and all five activated at 02:49 with no errors, `preserving type` included. Wave B (U6 base BDEF, U10 root access control) was created empty at 02:50, its sources were pasted at 02:53, and both activated at 02:55 (BDEF through `.bdef.abdl`). Wave C (U7 behavior pool, U8 UI projection view) was pasted at ~03:00 and activated at 03:03 (U6 and U7 together, then U8), with no errors. It is not yet confirmed that the handler source sits in the class's Local Types include; until it is, activation does not prove the three flagged constructs. Wave D (U9 projection BDEF, U11 access control, U12 metadata extension, U13 UI service definition) was created empty at 03:05 and pasted at ~04:12. U9, U11 and U12 activated at 04:15. U13 activation failed, listing "Comments are not supported and will be deleted on save" (Ln 1) and "oData V4 services with no draft capability will be primarily READ-ONLY" (Ln 21, expected by design). After a comment-free re-save, U13 activated at 04:18. U14 binding `ZUI_ARENA_CHANGE_APPR_O4` (OData V4 UI) was created and activated. **The UI leg is active: all 14 objects; ATC 0 errors, 0 warnings, 43 infos.** **Published 2026-09-16 04:26** through the ADT Publish code lens: `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`, entity set `ChangeApproval` (`fetch_service_information`). The table is empty until the worker leg creates records, because the UI exposes no create. V-2 app reconciliation done. **Worker (A2X) leg ACTIVE 2026-09-16 06:37:** W1 view `ZC_CHANGEAPPROVAL_A2X`, W2 access control, W3 projection BDEF (create, markExecuting, markSynced, markFailed), W4 service definition `ZAPI_ARENA_CHANGE_APPROVAL` and W5 OData V4 Web API binding `ZAPI_ARENA_CHANGE_APPR_A2X` (unpublished, service `0001`). ATC on the 5 worker objects: 0 errors, 1 priority-3 warning (W607 on `ZC_CHANGEAPPROVAL_A2X`: `authorizationCheck: #CHECK` should be `#MANDATORY`), deferred to OQ-8. **The approval BO is complete on the development tenant (19 objects).** Next: expose W5 to the worker's communication user through a custom communication scenario (V-2 A2X half); IAM app, business catalog and role for the UI app (ARN-007); OQ-8 authorization before other business users. The table source goes into `.tabl.ddic`; `.tabl.json` holds only header metadata. (3) UI leg, 14 sources ending with binding `ZUI_ARENA_CHANGE_APPR_O4`: I create each object through the MCP, its source is pasted in the VS Code editor, and I activate it. The `markSynced`/`markFailed` parameter entities belong to this leg, because the base BDEF references them. (4) Publish the UI binding, then run V-2 reconciliation of the app against its live `$metadata`. (5) Worker (A2X) leg, 4 sources. Syntax proven only by tenant activation, still open: `OPTIONS PRIVILEGED ACCESS` in `checkDuplicate` (fallback `FROM … WITH PRIVILEGED ACCESS`), `%op-%action` on MODIFY response rows, `preserving type` on the U5 boolean casts |
| V-1…V-3 verification POC | V-1 **Closed 2026-09-15** on the development tenant. V-2/V-3 **parked 2026-09-29** with ADR-004. The old note that V-1 meant "ADT access on my429480" was wrong: `my429480` is the customizing tenant and grants no developer extensibility at all |
| Fiori Elements app (`app/`, mock-bound) | Done for the mock stage (2026-09-14) — gateway service shape (binding-derived identity), six-state domain, polished List Report/Object Page, launchpad inbound `ArenaChangeApproval-manage`; SAP review findings closed. Deploy gated on V-1/V-2 (live `$metadata` reconciliation) | **2026-09-29: still mock-bound and never deployed.** Its target service is now OQ-11, not the RAP UI binding |
| RAP BO (approval domain) | **Parked 2026-09-29 (ADR-004).** Complete and active on the development tenant `my431353`: 19 objects in `ZARENA_PLM`, ATC 0 errors, UI service published 2026-09-16 04:26, A2X binding unpublished. I leave every object in place and keep the sources in `docs/handover/rap/`. Never reached a business user: no IAM app, no business catalog, no business role (ARN-007 never started), and `authorization master ( none )` throughout |
| Connectivity worker | Review wave Done (2026-09-14) — TTL wiring, cursor-after-success, buffer-full = tick failure, health conformance, strict JSON-only validation, bounded buffer, graceful drain, HTTP timeout, fixed-phrase errors; 137 tests green incl. the schema-driven contract-conformance suite. Next: Arena client POC (live), executor leg gated on V-2. **Do not deploy the scaffold**: the ingest buffer has no consumer yet, so a long-running instance would answer 503 after `WEBHOOK_QUEUE_MAX_SIZE` events. Next: Arena client POC (live), executor leg gated on V-2 |
| Worker API contract (`docs/api/worker.openapi.json`) | v0.2.1 Done (2026-09-14) — health enums/`degraded`/`poller`, strict `SyncRunRequest`, webhook 503, 413/415 + `default` on every operation, reserved 502, `DOCUMENTS` token; `x-sap-stateInfo: beta`, provisional webhook schema pending Arena POC |
+5 -2
View File
@@ -53,8 +53,11 @@ Tools - Service Modeler", verified 2026-09-16].
**Backend for a non-mock run: not configured.** `ui5.yaml` and `ui5-local.yaml` carry
`fiori-tools-proxy` with `backend: []`, and `npm start` is a generator placeholder. When a live
preview is added, the backend is the **UI host** `https://my431353.s4hana.cloud.sap`, never the
`-api` host: a business-user call there is blocked by UCON (live 2026-09-16, `KNOWLEDGE.md`).
preview is added, the backend recorded for the client 080 track is the **UI host**
`https://my431353.s4hana.cloud.sap`, never the `-api` host: a business-user call there is blocked
by UCON (live 2026-09-16, `KNOWLEDGE.md`). That tenant — the starter system's development tenant —
is **parked as of 2026-09-29**, so this binding is a reference point, not a live target; the
working target is the starter system's customizing tenant `my429480` (client 100).
## Status model and actions
+8 -1
View File
@@ -1,6 +1,13 @@
# ADR-002 — On-stack first: RAP approval domain + Fiori app in the tenant; side-by-side reduced to a connectivity worker
Date: 2026-09-04 · Status: Accepted (amends ADR-001)
Date: 2026-09-04 · Status: **Superseded by ADR-004 (2026-09-29)** (amended ADR-001)
> **Superseded 2026-09-29.** The customizing tenant `my429480` (client 100)
> supports key-user extensibility only, so the RAP business object below has
> no home there; `my429480` and `my431353` are the starter system's
> customizing and development tenants, not a development and a productive
> system. V-1 below, "confirm developer-extensibility access on my429480",
> was unanswerable as written. See ADR-004.
## Context
@@ -0,0 +1,80 @@
# ADR-004 — Back out of on-stack RAP: side-by-side against released APIs
Date: 2026-09-29 · Status: Accepted (supersedes ADR-002; partly revives ADR-001)
## Context
ADR-002 moved this package on-stack: a RAP approval business object and a Fiori
Elements app inside the tenant, with side-by-side reduced to a connectivity
worker, and CAP written out of the architecture. I built that. On the starter
system's development tenant `my431353` (client 080) the approval business
object is complete and active — 19 objects in `ZARENA_PLM`, ATC clean, the UI
service published on 2026-09-16 — and the Fiori Elements app in `app/` is built
against a mock of it.
Two facts have since changed the ground under that decision.
**The tenant I work in cannot host it.** `my429480` and `my431353` are two
tenants of the same starter system: `my429480` is its **customizing** tenant
(client 100) and `my431353` is its **development** tenant (client 080). 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]. ADR-002 was written
believing `my429480` offered developer extensibility, and this package
compounded the error by recording `my429480` as "productive". Both readings
were wrong.
**I am not carrying the ABAP build.** The RAP route costs more than this
package can justify: every source has to be pasted into an editor by hand,
because no agent-side ABAP authoring path exists (V-4, answered 2026-09-15: no;
SAP's editing tool is planned for Public Edition 2702), and the one workaround
I tried — reentrance-ticket login for a community ADT server — was built,
tested and rejected on evidence (2026-09-18). Outside advice is that no ABAP is
needed for this integration. Nothing I built on-stack ever reached a business
user: ARN-007 (IAM app, business catalog, business role) was never started, and
the business object still runs `authorization master ( none )`.
## Decision
I withdraw the on-stack RAP route. The application moves back out to a
side-by-side runtime consuming released OData APIs, with the customizing tenant
`my429480` (client 100) as the sync target and configuration home.
I **park** the development tenant `my431353` rather than clean it: all 19
objects stay active in `ZARENA_PLM`, and their sources stay in
`docs/handover/rap/`. Parking costs nothing — the package carries no transport
recording and the tenant is non-productive — and it keeps the route reversible
if the constraint or the advice changes.
I do **not** decide the replacement host here. That is OQ-11: key-user
extensibility in the customizing tenant (custom business object plus a low-code
UI) versus a CAP service side-by-side on BTP. My recommendation is CAP, because
the connectivity worker has to live side-by-side whatever else happens, and one
runtime beats two. No build starts until OQ-11 is closed.
## Consequences
Kept, unchanged in value:
- the connectivity worker (`worker/`) — built, 137 tests green, never deployed;
it is the only encoding of the Arena session, delta-cursor and webhook logic
outside the Express predecessor, and it is needed under either OQ-11 option;
- the Fiori Elements app (`app/`) — repointable, because 35 of its 58
annotations are already local rather than backend-owned (OQ-10);
- the RAP sources and the live objects, as reference and as a reversible route.
Withdrawn or weakened:
- the acceptance test's "finds its data in the Custom CDS Views app" clause —
unreachable from client 100; what survives is launchpad reachability and
governance by business roles, and launchpad reachability now becomes a
federation question rather than a native one;
- ADR-002's claim that "CAP exits the architecture" — ADR-001's CAP-first
direction is, in effect, back on the table.
Parked with this decision, not closed: V-2, V-3, OQ-5, OQ-8, OQ-9, OQ-10 — all
scoped to the parked development tenant. Each returns only with the RAP route.
Unrelated to the decision but blocking any verification against the customizing
tenant: the only `AZ_API_USER` credential for `my429480` in my estate is
rejected (HTTP 401), the Cloud Foundry token is expired, and the client
certificate path has no certificates. One of those has to be restored before I
can read that tenant at all.
+6 -1
View File
@@ -1,6 +1,11 @@
# RAP handover: Arena change-approval BO, built from an empty package (rev. 2026-09-16, corrected after the UI leg went live)
Target: development tenant `my431353` (ADT destination `0M7DEJI`), package `ZARENA_PLM`, a
**Parked 2026-09-29.** This handover records the client 080 build as it was carried out. The
starter system's development tenant `my431353` is parked as of 2026-09-29 and its objects are left
in place; the working target is now the starter system's customizing tenant `my429480` (client 100,
key-user extensibility only — no ABAP/RAP). Keep this document as the build record and reference.
Target: the starter system's development tenant `my431353` (ADT destination `0M7DEJI`), package `ZARENA_PLM`, a
sub-package of `ZLOCAL` with no transport. No generator is used. Every object is created empty
through the ADT MCP `abap_creation-create_object`, filled by pasting a file from this folder into
the VS Code ADT editor, saved, and activated through `abap_activate_objects`. The ADT MCP cannot
+16 -2
View File
@@ -6,6 +6,15 @@ headless / SSH-only host — without a browser window on the server's desktop.
Node 24, standard library only, no dependencies, no install step.
> **Parked 2026-09-29.** `my431353` is the starter system's **development**
> tenant (client 080). I parked that tenant on 2026-09-29 together with the
> on-stack RAP route, leaving all of its objects active in place. I keep this
> helper only in case that route is revived — nothing in the current
> side-by-side architecture calls it. Every `my431353` reference below is the
> default this tool was built against, not a live target. The working target
> is the starter system's customizing tenant `my429480` (client 100), which
> supports key-user extensibility only and needs no ADT logon at all.
---
## Why this exists
@@ -37,7 +46,9 @@ on this host. This script is that listener.
## Run it
Three steps, three terminals-worth of context. Values below use the defaults
(tenant `my431353`, port `42010`, 300 s timeout).
(tenant `my431353`, port `42010`, 300 s timeout) — that tenant being the
development tenant parked on 2026-09-29, kept here as the default this tool
shipped with.
### 1. Start the helper on this host
@@ -69,6 +80,9 @@ redirects your browser to its own machine and nothing is captured.
https://my431353.s4hana.cloud.sap/sap/bc/adt/core/http/reentranceticket?redirect-url=http://localhost:42010/adt/redirect
```
That host is the parked development tenant (client 080, parked 2026-09-29);
point `--tenant` elsewhere if the revived route ever lands on another tenant.
(Or capture it programmatically: `node login.mjs --print-url-only`.)
After SSO the tab lands on "Ticket captured", the helper writes
@@ -88,7 +102,7 @@ fresh ticket, call the MCP `login` tool for the destination.
| Flag | Default | Meaning |
|---|---|---|
| `--tenant <url>` | `https://my431353.s4hana.cloud.sap` | Tenant base URL. The UI host, not the `-api` host. |
| `--tenant <url>` | `https://my431353.s4hana.cloud.sap` | Tenant base URL. The UI host, not the `-api` host. The default is the development tenant parked on 2026-09-29. |
| `--port <n>` | `42010` | Loopback port. Bound to `127.0.0.1` **only**; there is no flag to change the bind address. |
| `--timeout <seconds>` | `300` | Give up and write nothing. |
| `--out <path>` | `~/.abap-adt-mcp/ticket.json` | Output file, mode 0600 (directory created 0700). |