Files
arena-plm-fiori/CHANGELOG.md
T
alexzandClaude Opus 5 ffd33f4ec0 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>
2026-09-29 10:33:29 -07:00

1514 lines
92 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CHANGELOG — arena-plm (standalone)
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/`
(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.