# CHANGELOG — arena-plm (standalone) Append-only decision log for this package. ## 2026-09-29 — ADR-005: OQ-11 closed. Integration Suite native — Arena ADK adapter + iFlows, approval in SAP Build Process Automation - What changed: I closed OQ-11 and wrote `docs/adr/ADR-005-integration-suite-native.md`. The integration becomes Integration Suite native: an Arena custom adapter built with the Adapter SDK (sender adapter carrying the webhook endpoint and the delta scheduler), iFlows for the movement to the released Product / BOM / ChangeMaster / Attachment APIs, and human approval in SAP Build Process Automation. Nothing runs on Cloud Foundry; nothing is written in ABAP. I rewrote the PRD's target architecture accordingly and added V-5 and V-6. - Why: both options I had framed for OQ-11 failed the criterion that actually decides this. The test is not build cost, it is whether the next person finds the thing inside the platform — and a CAP service or a hardened worker on Cloud Foundry is discoverable only to whoever already knows the route to it, which is ADR-002's original objection relocated rather than answered. Two findings then chose between the native options: - Every mechanism I hand-rolled in `worker/` has a first-class ADK facility: cluster lock for single-flight login, ADK persistency for the delta cursor, user credentials for Arena secrets, scheduler support, connection status, tracing, endpoint visualization, and versioning rules [source: SAP Help, *Adapter Development Process*, Cloud Integration, verified 2026-09-29]. The adapter does not merely present better; it deletes the infrastructure the worker existed to supply. - I had recorded the ADK's Java/Maven/OSGi toolchain as the cost of this route. It is not a cost in this estate: the AS/400 FetchAPI servlets on `mcl2000` are already Java, and Java developers can be staffed in-house. One language and one team span both ends, and the ADK covers the on-premise leg directly through *Accessing On-Premise Application using Cloud Connector* — which retires the deleted Cloud Foundry `fetchapi-bridge` pattern instead of rebuilding it. - Affected: PRD (target architecture, decisions, OQ-11 closed, V-5 and V-6 added), new ADR-005, ADR-004 narrowed. `worker/` is reclassified from deliverable to specification; `app/` has no target service under ADR-005 and is kept as reference, not repointed. No SAP tenant or BTP artifact was modified. - Decision: ADR-005. I also correct something I asserted too confidently earlier in the day: that SAP Build Process Automation tasks surface in the Fiori launchpad. That is now V-6, unverified — what I can state is that the service is entitled in the global account (`process-automation`, `process-automation-service`) and therefore needs assigning, not buying. First build is V-5: a minimal Arena sender adapter that logs in and holds the session under cluster lock. Nothing else starts before it. ## 2026-09-29 — Read access to the customizing tenant proven through `mc-s4hana`; the parked password is simply stale - What changed: nothing in the tenant — I established how to read it. Through the BTP destination `mc-s4hana`, three read-only GETs against `my429480` all answered 200: `API_BUSINESS_PARTNER/$metadata` (EDMX v1.0, 65 entity sets), `A_BusinessPartner?$top=1` (BusinessPartner `1710`), and `api_product/srvd_a2x/sap/product/0002/$metadata` (EDMX 4.0, 39 entity sets). I used the destination service instance `sap-apps-dest` and its existing service key `dest-anywhere-dest-key`; I created no key and no instance. - Why: after retargeting, direct basic auth to the customizing tenant returned 401, and I needed to know whether the tenant was refusing the user or the stored password was wrong. - Affected: no SAP object, no BTP artifact. Knowledge only. - Findings: - `mc-s4hana` authenticates as **`BasicAuthentication` with the same user, `AZ_API_USER`**, and succeeds. So the tenant accepts that user over basic auth: the 401 was neither a lockout nor a user problem. The password in `_shared/.env.starter-cust-my429480.bak` is stale, and the working value is already held by the destination. No credential reset is needed. - The destination's own description reads "SAP S/4HANA Public Cloud - MC Production" while its URL is the starter customizing tenant — the same mislabel this package carried, now visible in BTP as well. I left it alone; it is shared, and a description is not worth an unrequested change. - `default-env.json` alone does not work with SAP Cloud SDK v4: `@sap-cloud-sdk/connectivity` 4.6.0 resolves bindings through `@sap/xsenv`'s `filterServices()`, which reads `process.env.VCAP_SERVICES` and never loads the file. `require('@sap/xsenv').loadEnv()` must run ahead of the SDK requires (or `VCAP_SERVICES` be exported). The first attempt failed with "Could not find service binding of type 'destination'". - Decision: I will not copy the working password out of the destination into `.env`. The destination is the sanctioned path for this estate, so the fix is to make the shared CLI destination-aware rather than to hold a second copy of a credential. Until that is done, reads against the customizing tenant go through a destination-based call, not through `sap-api`. ## 2026-09-29 — Tooling retargeted to the starter customizing tenant; its credential is rejected - What changed: - I pointed the shared CLI at the starter system's customizing tenant. Both `_shared/.env` and the root `.env` now carry `SAP_API_URL`, `SAP_API_USER` and `SAP_API_PASSWORD` for `https://my429480-api.s4hana.cloud.sap`; the eight `CPI_*` and `ARENA_*` variables are untouched. - I renamed both parked credential files so neither name asserts something false: the client-080 credential is now `_shared/.env.starter-dev-my431353.bak`, and the client-100 credential is `_shared/.env.starter-cust-my429480.bak` (formerly `.env.prod-my429480.bak`, a name that wrongly called it productive). - I corrected the tenant references in `CLAUDE.md`, `KNOWLEDGE.md`, `app/README.md`, `docs/handover/rap/README.md` and `.claude/agents/rap-developer.md`: the customizing tenant is the working target, the development tenant is parked as of 2026-09-29 with its objects in place. No historical build record was deleted. - I wrote `docs/adr/ADR-004-back-out-of-on-stack-rap.md` and marked ADR-002 superseded in its own file, including the note that its gate "confirm developer-extensibility access on my429480" was unanswerable as written. - Verification: **the customizing-tenant credential is rejected.** Read-only GETs return HTTP 401 with SAP's logon-failed page (`Anmeldung fehlgeschlagen`); the host resolves and answers, so this is the credential, not reachability. I then checked every other way in and found none: the rejected password is the only copy of that credential anywhere in my estate; the Cloud Foundry token is expired, so the `mc-s4hana` destination is out of reach; and the client-certificate path in the shared client looks for `_shared/certs/az-api-user.crt` and `.key`, which do not exist. No writes of any kind were issued to any tenant. - Affected: `_shared/.env`, `.env`, both `.bak` files, five reference documents, ADR-002, new ADR-004. No SAP tenant was modified. - Decision: I left the retarget in place rather than rolling back to the development tenant, because reverting would only restore access to the tenant I am deliberately leaving. Restoring read access to the customizing tenant is now a prerequisite for any verification, and the cheapest route is a Cloud Foundry re-login — that reaches the tenant through the `mc-s4hana` destination and needs no password at all, which is also what my coding standard requires. ## 2026-09-29 — ADR-004: I withdraw the on-stack RAP route; development tenant parked - What changed: I corrected a tenant mislabel that had propagated through this package, and on the corrected facts I withdrew ADR-002. - Both `my429480` and `my431353` are tenants of the **starter system**. `my429480` is its **customizing** tenant (client 100); `my431353` is its **development** tenant (client 080). This package had `my429480` recorded as "productive" and treated `my431353` as a separate development system; both readings were wrong, and the parked credential file name (`.env.prod-my429480.bak`) encoded the same error. - The customizing tenant supports **key-user extensibility only** — no ABAP, no RAP; developer extensibility exists only on client 080 [source: fiori-tools-samples `misc/s4hana/README` "Tenant Types", verified 2026-09-29]. - I therefore parked the development tenant `my431353`, leaving all 19 activated `ZARENA_PLM` objects in place, and moved the application back to a side-by-side runtime against released APIs. - I rewrote the PRD accordingly: new target architecture, corrected Systems & boundaries rows, amended acceptance test, ADR-002 marked superseded, ADR-004 added, and the RAP-dependent verification items (V-2, V-3, OQ-5, OQ-8, OQ-9, OQ-10) parked rather than closed (OQ-12). - Why: I am not carrying an ABAP/RAP build for this package, and the tenant I am working in cannot host one even if I wanted to. Keeping a PRD that asserted an impossible architecture would have been worse than the rebuild. - Affected: PRD.md (vision, target architecture, systems, decisions, open questions, status), the parked tenant `my431353`, ADR-002. - Decision: ADR-004. I park rather than delete, so the RAP route stays reversible at zero cost. I left the replacement host open as OQ-11 — key-user extensibility in the tenant versus a CAP service side-by-side — and recorded my recommendation for CAP, because the connectivity worker has to be side-by-side regardless and one runtime beats two. I will not start building until OQ-11 is decided. ## 2026-09-29 — Outstanding sources committed and pushed - What changed: I committed the working-tree state that had sat uncommitted since the initial `upload current sources` commit, and pushed it: `468729e`, 42 files, 4614 insertions, 1697 deletions, fast-forward onto `origin/main`. It carries the renamed RAP handover sources (the 11 generator-suffixed `zz*000` names replaced by the clean object names actually built on the tenant), the `app/` rebind edits, the build record through 2026-09-19, the retained reentrance-login helper and the captured live `$metadata`. It drops two files that never belonged in the repository: a tracked Eclipse installer under a URL-mangled filename, and a machine-specific workspace file. - Why: the package held six weeks of unversioned work, and I was about to change direction. Nothing should be lost across that pivot. - Affected: the whole repository; `origin/main` now matches the working tree. - Decision: I committed the deletions as they stood rather than restoring either file. Neither is source. ## 2026-09-18 — Reentrance-ticket login for `abap-adt-mcp`: built, tested, rejected - What changed: I built a login helper at `tools/adt-reentrance-login/` (Node, no dependencies): a one-shot loopback listener that captures an ADT reentrance ticket from the `redirect-url=http://localhost:/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/` [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-` 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-`, 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-` 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:/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...v0001` with alias `SAP__self` and `_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.