From ffd33f4ec0b1313e14d0b97c0db2e56f6d876d5c Mon Sep 17 00:00:00 2001 From: alexz Date: Tue, 29 Sep 2026 10:33:29 -0700 Subject: [PATCH] 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) --- .claude/agents/rap-developer.md | 6 +- CHANGELOG.md | 89 +++++++++++++++++++ CLAUDE.md | 92 ++++++++++++++------ KNOWLEDGE.md | 10 ++- PRD.md | 71 ++++++++++----- app/README.md | 7 +- docs/adr/ADR-002-on-stack-first.md | 9 +- docs/adr/ADR-004-back-out-of-on-stack-rap.md | 80 +++++++++++++++++ docs/handover/rap/README.md | 7 +- tools/adt-reentrance-login/README.md | 18 +++- 10 files changed, 332 insertions(+), 57 deletions(-) create mode 100644 docs/adr/ADR-004-back-out-of-on-stack-rap.md diff --git a/.claude/agents/rap-developer.md b/.claude/agents/rap-developer.md index 51307dd..bdf5b84 100644 --- a/.claude/agents/rap-developer.md +++ b/.claude/agents/rap-developer.md @@ -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, diff --git a/CHANGELOG.md b/CHANGELOG.md index f94fbf9..ee15697 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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/` diff --git a/CLAUDE.md b/CLAUDE.md index 2d71652..b8e5e85 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 | diff --git a/KNOWLEDGE.md b/KNOWLEDGE.md index 52d4b02..6dfacc4 100644 --- a/KNOWLEDGE.md +++ b/KNOWLEDGE.md @@ -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 diff --git a/PRD.md b/PRD.md index 09cab02..4c94f16 100644 --- a/PRD.md +++ b/PRD.md @@ -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 | diff --git a/app/README.md b/app/README.md index 82e39cc..1d4e44a 100644 --- a/app/README.md +++ b/app/README.md @@ -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 diff --git a/docs/adr/ADR-002-on-stack-first.md b/docs/adr/ADR-002-on-stack-first.md index dcdf56c..e803da4 100644 --- a/docs/adr/ADR-002-on-stack-first.md +++ b/docs/adr/ADR-002-on-stack-first.md @@ -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 diff --git a/docs/adr/ADR-004-back-out-of-on-stack-rap.md b/docs/adr/ADR-004-back-out-of-on-stack-rap.md new file mode 100644 index 0000000..84a56c8 --- /dev/null +++ b/docs/adr/ADR-004-back-out-of-on-stack-rap.md @@ -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. diff --git a/docs/handover/rap/README.md b/docs/handover/rap/README.md index 48e7fb2..ccef7b5 100644 --- a/docs/handover/rap/README.md +++ b/docs/handover/rap/README.md @@ -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 diff --git a/tools/adt-reentrance-login/README.md b/tools/adt-reentrance-login/README.md index b0d8733..b63ed60 100644 --- a/tools/adt-reentrance-login/README.md +++ b/tools/adt-reentrance-login/README.md @@ -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 ` | `https://my431353.s4hana.cloud.sap` | Tenant base URL. The UI host, not the `-api` host. | +| `--tenant ` | `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 ` | `42010` | Loopback port. Bound to `127.0.0.1` **only**; there is no flag to change the bind address. | | `--timeout ` | `300` | Give up and write nothing. | | `--out ` | `~/.abap-adt-mcp/ticket.json` | Output file, mode 0600 (directory created 0700). |