Files
arena-plm-fiori/CHANGELOG.md
T
alexzandClaude Opus 5 ffd33f4ec0 ADR-004: back out of on-stack RAP; retarget to starter customizing tenant
Both tenants belong to the same starter system: my429480 is its
customizing tenant (client 100, key-user extensibility only, no ABAP)
and my431353 is its development tenant (client 080). This package had
recorded my429480 as "productive" and ADR-002 had assumed it offered
developer extensibility; both were wrong.

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

No SAP tenant was modified.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-29 10:33:29 -07:00

92 KiB
Raw Blame History

CHANGELOG — arena-plm (standalone)

Append-only decision log for this package.

2026-09-29 — Tooling retargeted to the starter customizing tenant; its credential is rejected

  • What changed:
    • I pointed the shared CLI at the starter system's customizing tenant. Both _shared/.env and the root .env now carry SAP_API_URL, SAP_API_USER and SAP_API_PASSWORD for https://my429480-api.s4hana.cloud.sap; the eight CPI_* and ARENA_* variables are untouched.
    • I renamed both parked credential files so neither name asserts something false: the client-080 credential is now _shared/.env.starter-dev-my431353.bak, and the client-100 credential is _shared/.env.starter-cust-my429480.bak (formerly .env.prod-my429480.bak, a name that wrongly called it productive).
    • I corrected the tenant references in CLAUDE.md, KNOWLEDGE.md, app/README.md, docs/handover/rap/README.md and .claude/agents/rap-developer.md: the customizing tenant is the working target, the development tenant is parked as of 2026-09-29 with its objects in place. No historical build record was deleted.
    • I wrote docs/adr/ADR-004-back-out-of-on-stack-rap.md and marked ADR-002 superseded in its own file, including the note that its gate "confirm developer-extensibility access on my429480" was unanswerable as written.
  • Verification: the customizing-tenant credential is rejected. Read-only GETs return HTTP 401 with SAP's logon-failed page (Anmeldung fehlgeschlagen); the host resolves and answers, so this is the credential, not reachability. I then checked every other way in and found none: the rejected password is the only copy of that credential anywhere in my estate; the Cloud Foundry token is expired, so the mc-s4hana destination is out of reach; and the client-certificate path in the shared client looks for _shared/certs/az-api-user.crt and .key, which do not exist. No writes of any kind were issued to any tenant.
  • Affected: _shared/.env, .env, both .bak files, five reference documents, ADR-002, new ADR-004. No SAP tenant was modified.
  • Decision: I left the retarget in place rather than rolling back to the development tenant, because reverting would only restore access to the tenant I am deliberately leaving. Restoring read access to the customizing tenant is now a prerequisite for any verification, and the cheapest route is a Cloud Foundry re-login — that reaches the tenant through the mc-s4hana destination and needs no password at all, which is also what my coding standard requires.

2026-09-29 — ADR-004: I withdraw the on-stack RAP route; development tenant parked

  • What changed: I corrected a tenant mislabel that had propagated through this package, and on the corrected facts I withdrew ADR-002.
    • Both my429480 and my431353 are tenants of the starter system. my429480 is its customizing tenant (client 100); my431353 is its development tenant (client 080). This package had my429480 recorded as "productive" and treated my431353 as a separate development system; both readings were wrong, and the parked credential file name (.env.prod-my429480.bak) encoded the same error.
    • The customizing tenant supports key-user extensibility only — no ABAP, no RAP; developer extensibility exists only on client 080 [source: fiori-tools-samples misc/s4hana/README "Tenant Types", verified 2026-09-29].
    • I therefore parked the development tenant my431353, leaving all 19 activated ZARENA_PLM objects in place, and moved the application back to a side-by-side runtime against released APIs.
    • I rewrote the PRD accordingly: new target architecture, corrected Systems & boundaries rows, amended acceptance test, ADR-002 marked superseded, ADR-004 added, and the RAP-dependent verification items (V-2, V-3, OQ-5, OQ-8, OQ-9, OQ-10) parked rather than closed (OQ-12).
  • Why: I am not carrying an ABAP/RAP build for this package, and the tenant I am working in cannot host one even if I wanted to. Keeping a PRD that asserted an impossible architecture would have been worse than the rebuild.
  • Affected: PRD.md (vision, target architecture, systems, decisions, open questions, status), the parked tenant my431353, ADR-002.
  • Decision: ADR-004. I park rather than delete, so the RAP route stays reversible at zero cost. I left the replacement host open as OQ-11 — key-user extensibility in the tenant versus a CAP service side-by-side — and recorded my recommendation for CAP, because the connectivity worker has to be side-by-side regardless and one runtime beats two. I will not start building until OQ-11 is decided.

2026-09-29 — Outstanding sources committed and pushed

  • What changed: I committed the working-tree state that had sat uncommitted since the initial upload current sources commit, and pushed it: 468729e, 42 files, 4614 insertions, 1697 deletions, fast-forward onto origin/main. It carries the renamed RAP handover sources (the 11 generator-suffixed zz*000 names replaced by the clean object names actually built on the tenant), the app/ rebind edits, the build record through 2026-09-19, the retained reentrance-login helper and the captured live $metadata. It drops two files that never belonged in the repository: a tracked Eclipse installer under a URL-mangled filename, and a machine-specific workspace file.
  • Why: the package held six weeks of unversioned work, and I was about to change direction. Nothing should be lost across that pivot.
  • Affected: the whole repository; origin/main now matches the working tree.
  • Decision: I committed the deletions as they stood rather than restoring either file. Neither is source.

2026-09-18 — Reentrance-ticket login for abap-adt-mcp: built, tested, rejected

  • What changed: I built a login helper at tools/adt-reentrance-login/ (Node, no dependencies): a one-shot loopback listener that captures an ADT reentrance ticket from the redirect-url=http://localhost:<port>/adt/redirect flow, writes it to a 0600 file, and probes how the tenant accepts it. It never prints, logs or passes the ticket through argv or the environment, and it parses the raw query itself, because URLSearchParams turns a + in a ticket into a space and would corrupt it. Then I captured a real ticket and tested it: /sap/bc/adt/core/discovery and an ABAP class source URL answered 200 with the same 3094-byte SAML redirect page for cookie transport, header transport and no credential, with and without sap-client=080.
  • Why: abap-adt-mcp's browser SSO needs a window on the server's desktop, which is unreachable over this remote session (OQ-9). ADT for VS Code logs on with a reentrance ticket instead, so the question was whether that ticket can feed the server's sso2 (MYSAPSSO2 cookie) mode.
  • Affected: new tools/adt-reentrance-login/, ~/.abap-adt-mcp/systems.json (switched to sso2, then restored to sso), KNOWLEDGE.md, PRD OQ-9.
  • Decision: the approach is rejected on evidence. A reentrance ticket is neither a logon-ticket cookie nor an assertion-ticket header on this tenant, so sso2 cannot consume it. I restored the browser-login configuration, shredded the captured ticket, and kept the helper: it is the only piece that would still be needed if the exchange mechanism is ever identified. The next step, if this is revisited, is to capture what ADT for VS Code actually sends, not to guess header names. Tenant work continues on SAP's ADT MCP with editor paste, which is proven.

2026-09-16 — Worker leg active: approval BO complete on the development tenant

  • What changed:

    • I activated W3 (A2X projection BDEF) and W4 (service definition ZAPI_ARENA_CHANGE_APPROVAL).
    • I created and activated W5, the OData V4 Web API binding ZAPI_ARENA_CHANGE_APPR_A2X, with binding type OData V4 - Web API (create_object returned .srvb.json).
    • fetch_services: service ZAPI_ARENA_CHANGE_APPROVAL, version 0001, V4, isPublished: false, bindingCategory: "1".
    • ATC over the five worker objects (worklist 12ACF6BD93811FE1ACBA776536DD5BD6): 0 errors and one priority-3 warning, W607 (+BDL 549) on BDEF ZC_CHANGEAPPROVAL_A2X: "CDS annotation #CHECK … should be replaced with #MANDATORY".

    [source: adt-mcp abap_activate_objects, abap_creation-create_object, abap_atc_get_result, abap_business_services-fetch_services on 0M7DEJI, verified 2026-09-16]

  • Why: RAP-6. The worker needs create and the three execution-state actions through a Web API, separate from the read-only UI.

  • Affected: dev tenant ZARENA_PLM (all 19 approval-BO objects now active), PRD RAP BO status, KNOWLEDGE.md.

  • Decision: W5 stays unpublished. It is exposed to the worker's technical user through a custom communication scenario (V-2 A2X half), not through business-user access. I do not switch @AccessControl.authorizationCheck from #CHECK to #MANDATORY now: the warning does not block activation, and the change belongs with the OQ-8 authorization work, which revisits all three projection and root views together (the same annotation is in ZR_CHANGEAPPROVAL and ZC_CHANGEAPPROVAL).

2026-09-16 — Worker leg: A2X projection view and access control active; A2X BDEF created

  • What changed: I activated W1 (ZC_CHANGEAPPROVAL_A2X projection view) and W2 (its access control); both answered "Activation successful." I then created W3, the projection BDEF ZC_CHANGEAPPROVAL_A2X, empty (.bdef.abdl), after W1 was active [source: adt-mcp abap_activate_objects, abap_creation-create_object on 0M7DEJI, verified 2026-09-16]. W4 (service definition) is saved but not active.
  • Why: worker leg round 2 of the approval BO.
  • Affected: dev tenant ZARENA_PLM, PRD RAP BO status.
  • Decision: W4 activates only after W3 is active. Then W5, the Web API binding, is created and verified unpublished.

2026-09-16 — Worker leg round 1 created; handover brought in line with live results

  • What changed: after the expired VS Code ADT logon was restored, I created W1 (ZC_CHANGEAPPROVAL_A2X view), W2 (its access control, with protectedEntity) and W4 (service definition ZAPI_ARENA_CHANGE_APPROVAL) empty in ZARENA_PLM [source: adt-mcp create_object on 0M7DEJI, verified 2026-09-16]. I also corrected docs/handover/rap/: both service definition sources are comment-free, the README records the UI leg as active, ATC-clean and published, the activation-URI table marks the proven extensions (.tabl.ddic, .bdef.abdl, .srvb.json), and the worker-leg sequence is rewritten to two paste rounds. All 31 existing citations were preserved.
  • Why: worker (A2X) leg of the approval BO (RAP-6). The handover must not repeat today's failed activations.
  • Affected: dev tenant ZARENA_PLM, docs/handover/rap/, KNOWLEDGE.md.
  • Decision: pastes are opened manually from the ABAP workspace tree. I only give the local source path and the abap:/repotree-v1/… target, because editor tabs opened by URI cannot save. W5 uses binding type OData V4 - Web API, the exact value the create metadata offers. W5 stays unpublished until the custom communication scenario brief (V-2).

2026-09-16 — Fiori app bound to the live RAP service identity (V-2 UI half)

  • What changed: I reconciled app/ with the published service.

    • Manifest dataSource and mock-server URL paths now use /sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/.
    • The mock metadata.xml is the live $metadata, byte-identical (sha256 c13e86e1…, checked).
    • Mock rows carry StatusText, LocalLastChangedAt, __OperationControl and SAP__Messages.
    • All annotation targets and action strings use namespace com.sap.gateway.srvd.zui_arena_change_approval.v0001 and entity type ChangeApprovalType.

    A grep for the old identity over app/ (excluding node_modules/dist) returns nothing. Lint, typecheck and @ui5/linter are clean. The mock server answers $metadata and ChangeApproval with $filter, $count and __OperationControl selects.

  • Why: V-2 and ARN-007. The app must address the service that exists.

  • Affected: app/ (manifest, ui5-mock.yaml, ui5-local.yaml, annotation.xml, mock metadata and data, README), PRD V-2, new OQ-10, KNOWLEDGE.md.

  • Decision:

    • (1) Action enablement belongs to the backend. The mock's local OperationAvailable overrides went away with the mock metadata, and annotation.xml deliberately defines none, because a local one would replace RAP's _it/__OperationControl/<action> [source: fiori-mcp-server "Action Control for Context-Dependent Actions", verified 2026-09-16].
    • (2) No real backend is configured in the UI5 tooling yet. Any live preview targets the UI host, never -api. Its authentication type and client are verified before use, not assumed.
    • (3) UI annotation ownership is opened as OQ-10 rather than moved now: consolidating would drop i18n labels and action criticality and break the OPA section IDs mid-POC.
    • (4) dist/ is stale and must be rebuilt before any deployment.

2026-09-16 — Live $metadata captured: backend contract matches the app; identity names differ

  • What changed: the published UI service's $metadata is captured in docs/v2/zui_arena_change_appr_o4.metadata.xml. It was copied from the browser on the UI host my431353.s4hana.cloud.sap; browser-decoded & characters were re-escaped. The -api host refused the same request to a business user ("blocked by UCON").

    • Matches the app: all 17 app properties with identical EDM types (Edm.Boolean flags, Edm.Byte criticality, Edm.DateTimeOffset Precision 7), key ID, entity set ChangeApproval, and the actions approve, reject(RejectReason) (non-nullable) and retrySync.
    • Differs from the mock: namespace com.sap.gateway.srvd.zui_arena_change_approval.v0001 (from the service definition), entity type ChangeApprovalType, URL segment zui_arena_change_appr_o4, extra StatusText / LocalLastChangedAt / __OperationControl / SAP__Messages, and backend-driven Core.OperationAvailable.

    I dispatched the app reconciliation.

  • Why: V-2. The app was built against a provisional mock identity, and only the live service can settle it.

  • Affected: PRD V-2, app/ (in progress), KNOWLEDGE.md.

  • Decision: the live $metadata replaces the mock metadata and becomes the app's contract. Button enablement comes from the backend's __OperationControl rather than local IsApprovable/IsRetriable overrides, unless the Fiori docs show that breaks something. Any non-mock backend configuration points at the UI host, never -api. Earlier notes claiming the binding name sets the namespace are superseded (KNOWLEDGE 2026-09-16).

2026-09-16 — Approval UI service published on the development tenant

  • What changed: the OData V4 UI binding ZUI_ARENA_CHANGE_APPR_O4 is published. The ADT for VS Code Publish code lens gave no visible confirmation, so I verified it live: fetch_services reports isPublished: true, and fetch_service_information returns https://my431353-api.s4hana.cloud.sap/sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/?sap-client=080 with entity set ChangeApproval [source: adt-mcp abap_business_services-fetch_services, fetch_service_information on 0M7DEJI, verified 2026-09-16].
  • Why: RAP-5. The Fiori app cannot bind to an unpublished service.
  • Affected: PRD RAP BO status, V-2, KNOWLEDGE.md.
  • Decision: the URL path is exactly the designed one, so no binding change follows. The app's V-2 reconciliation (dataSource first segment, namespace, annotation targets, EDM types) is done against the live $metadata, never inferred. The service reports client 080, so the client value in any tool configuration comes from the live system.

2026-09-16 — UI leg active: approval BO and OData V4 UI service built on my431353

  • What changed:

    • U13, the service definition ZUI_ARENA_CHANGE_APPROVAL, activated after I re-saved it without its header comment. The same definition failed with the comment and succeeded without it, so the comment was the blocker; the missing-draft message is not.
    • I created U14, the OData V4 UI binding ZUI_ARENA_CHANGE_APPR_O4 (create_object returned .srvb.json), and activated it.
    • ATC over all 14 UI-leg objects: 0 errors, 0 warnings, 43 infos (worklist 12ACF6BD93811FE1ACB8096AC6763BD6).
    • fetch_services: service ZUI_ARENA_CHANGE_APPROVAL, version 0001, OData V4, unpublished.

    [source: adt-mcp abap_activate_objects, abap_creation-create_object, abap_atc_get_result, abap_business_services-fetch_services on 0M7DEJI, verified 2026-09-16]

  • Why: RAP-1..8 and the ARN-007 acceptance path. The service must exist before the app can bind to it.

  • Affected: dev tenant ZARENA_PLM, PRD RAP BO status, KNOWLEDGE.md, handover README (both SRVD sources still carry header comments, and U9 still says .bdef.json).

  • Decision: the service alias equals the definition name and the version is 0001. Publishing therefore yields /sap/opu/odata4/sap/zui_arena_change_appr_o4/srvd/sap/zui_arena_change_approval/0001/, as designed, so no rename is needed before publishing. The 43 ATC infos are reviewed in the ADT ATC view (the MCP returns only totals); infos do not gate publishing. I correct the handover README in one pass before the worker leg: comment-free SRVD sources and BDEF .bdef.abdl URIs.

2026-09-16 — Wave D: projection BDEF, access control and metadata extension active; service definition refused

  • What changed: I activated U9 (projection BDEF ZC_CHANGEAPPROVAL), U11 (its access control) and U12 (its metadata extension); each answered "Activation successful." Activating U13, the service definition ZUI_ARENA_CHANGE_APPROVAL, answered "Activation failed" with two messages and no severity:

    • "Comments are not supported and will be deleted on save" (Ln 1, the handover header block comment)
    • "oData V4 services with no draft capability will be primarily READ-ONLY" (Ln 21). The BO has no draft, by design.

    CDS SDL allows comments as a language rule [source: abap-docs /abap-docs-cloud/ABENCDS_F1_SDL_SYNTAX, ABENCDS_GENERAL_SYNTAX_RULES, verified 2026-09-16], so the refusal comes from the service definition tooling, not the language. U14 (the binding) was not created.

  • Why: wave D of the UI leg.

  • Affected: dev tenant ZARENA_PLM, PRD RAP BO status, KNOWLEDGE.md.

  • Decision: I re-save U13 with only its definition (annotation, define service, expose) and no header comment, then activate again. If it still fails with only the draft message, that message is blocking, and I read its severity in the editor's Problems view before changing anything about draft.

2026-09-16 — abap-adt-mcp parked: SSO cannot complete over remote access

  • What changed: with SAP_BROWSER_PATH set, the SSO login launched Chrome with a dedicated profile on the server's desktop display and waited on the Microsoft Entra sign-in page. The login does not use a localhost redirect: SAML returns to the tenant, and the server harvests the session cookies from its own Chrome over the DevTools protocol (dist/lib/browserLogin.js). I tried a localhost-only DevTools relay on a fixed port for remote interaction. It is not workable through multi-hop SSH proxies, so I stopped it and closed the login browser. No login happened. The server remains registered, read-only.
  • Why: the sign-in has to happen inside the server's browser, and that browser is on a desktop I cannot reach from this remote session.
  • Affected: PRD OQ-9, KNOWLEDGE.md.
  • Decision: I park abap-adt-mcp rather than remove it. One sign-in at the server's desktop, with "stay signed in", should let later logins run unattended in the invisible browser; that is unverified. The UI leg finishes on the proven path: SAP adt-mcp for create and activate, source pasted in the VS Code editor. Four wave-D sources, one binding and a publish remain.

2026-09-16 — abap-adt-mcp connected; SSO blocked on browser detection

  • What changed: after the restart, abap-adt-mcp connected. listSystems showed exactly one destination, MY431353 (client 100, SSO), with policy readOnly: true and allowedPackages: ["ZARENA_PLM"]. The first SAP call (classIncludes on ZBP_R_CHANGEAPPROVAL) failed before any login: "No Chrome/Edge/Brave found for SSO login." The server's browser detection covers only macOS paths (KNOWLEDGE 2026-09-16).
  • Why: SSO login is the gate to the read-only Local Types check.
  • Affected: project MCP registration (env), KNOWLEDGE.md.
  • Decision: the registration gains SAP_BROWSER_PATH=/usr/bin/google-chrome and nothing else changes. This is a manual step, like the original registration.

2026-09-16 — abap-adt-mcp registered read-only in project scope

  • What changed: abap-adt-mcp is registered in the project .mcp.json (git-ignored, mode 600). It runs over stdio as npx -y abap-adt-mcp@2.1.0 with MCP_READ_ONLY=1, an audit log at ~/.abap-adt-mcp/audit.jsonl, and the desktop display variables for the SSO browser. Its systems file lists only the development tenant my431353, client 100, SSO, with policy.readOnly: true and allowedPackages: ["ZARENA_PLM"]. The six existing project servers are unchanged, adt-mcp included.
  • Why: OQ-9. Agent-side source read and write would replace manual pasting for the remaining RAP objects.
  • Affected: project MCP configuration, PRD OQ-9.
  • Decision: the first use is a read-only getObjectSource of the behavior pool's Local Types include. That check settles whether wave C's activation proved the handler constructs. Write access is enabled only after that read succeeds. The CLAUDE.md MCP routing table changes only once the server has written and activated an object successfully.

2026-09-16 — abap-adt-mcp source review: all checks cleared; written report not produced

  • What changed: the read-only source review of abap-adt-mcp 2.1.0 cleared every check it ran (install scripts, network egress, credential and session storage, policy enforcement, dangerous primitives), observed as it ran. It then stalled while collecting line citations, consumed its budget, and was stopped at ~03:28, so no written report with file:line evidence exists. As of 03:30 the package is not registered, no ~/.abap-adt-mcp configuration exists, and no login has happened. The tenant state is unchanged: waves A–C are active, and wave D (U9, U11, U12, U13) exists empty.
  • Why: OQ-9 was gated on this review.
  • Affected: PRD OQ-9.
  • Decision: I accept the review for the development tenant only, under the read-only-first configuration (pinned 2.1.0, readOnly: true, allowedPackages: ["ZARENA_PLM"], MCP_READ_ONLY=1, audit file on). Registration is run by hand. The missing citations mean this clearance does not extend to the productive tenant. Any future review brief is scoped to named files with a size budget, because this one ran unbounded.

2026-09-16 — abap-adt-mcp registration is a manual step; read-only first

  • What changed: an attempt to write ~/.abap-adt-mcp/systems.json and to register abap-adt-mcp in the project MCP configuration was refused by Claude Code's permission guard as self-modification. Nothing was written. I confirmed the development tenant logs in on client 100. The package's SSO login launches Chrome visibly (headless: false), so the MCP server needs the desktop session's display variables.
  • Why: I want agent-side source writes (OQ-9), and registration is the gate.
  • Affected: PRD OQ-9, project .mcp.json (only once registered by hand), CLAUDE.md MCP routing (only once adopted).
  • Decision: the registration is run by hand, not routed around the guard. The first configuration is read-only (policy.readOnly: true, allowedPackages: ["ZARENA_PLM"], MCP_READ_ONLY=1), limited to the development tenant, and pinned to 2.1.0. The first login waits for the source review verdict. Writes are enabled only after a read-only getObjectSource on the behavior pool's Local Types include succeeds.

2026-09-16 — Community abap-adt-mcp smoke-tested read-only; not adopted yet (OQ-9)

  • What changed: I ran abap-adt-mcp 2.1.0 once through npx over stdio. It ran with MCP_READ_ONLY=1 and a scratchpad systems file listing only the development tenant, restricted to ZARENA_PLM. initialize and tools/list answered: 173 tools, including source read/write and activation. listSystems showed the read-only, package-restricted policy enforced. There was no login and no SAP call. Nothing was registered in any Claude Code or project configuration (verified 03:12). The package remains in the local npx cache. I opened OQ-9.
  • Why: SAP's ADT MCP cannot write source (V-4), so every RAP source is pasted by hand. A server that can read and write source would remove that step and would also let me read the behavior pool's Local Types include directly.
  • Affected: PRD OQ-9, V-4 (possible alternative), CLAUDE.md MCP routing (a change only on adoption).
  • Decision: I do not adopt it mid-build. Only four pastes and one publish remain on the UI leg. The package was published the same day, by one maintainer, and would hold a browser SSO session into the tenant, so it gets a source review before any login. I run it read-only first. The productive tenant my429480 is never listed in its systems file.

2026-09-16 — Wave C active: behavior pool and UI projection view live; wave D created

  • What changed: I activated U6 (base BDEF) and U7 (behavior pool ZBP_R_CHANGEAPPROVAL) together in one call, then U8 (UI projection view ZC_CHANGEAPPROVAL). All answered "Activation successful." The locally cached class metadata shows the class active with category behaviorPool. I then created wave D empty: U9 projection BDEF ZC_CHANGEAPPROVAL (.bdef.abdl), U11 access control (.dcls.acds), U12 metadata extension (.ddlx.acds) and U13 service definition ZUI_ARENA_CHANGE_APPROVAL (.srvd.acds). SRVD/SRV also offers an optional referencedObject create field [source: adt-mcp abap_activate_objects, abap_creation-create_object, get_object_type_details on 0M7DEJI, verified 2026-09-16].
  • Why: wave C of the UI leg. Wave D is the last paste group before the UI binding.
  • Affected: dev tenant ZARENA_PLM, PRD RAP BO status, handover README (BDEF extension .bdef.abdl for U9 and W3; SRVD tag list), KNOWLEDGE.md.
  • Decision: I do not record OPTIONS PRIVILEGED ACCESS, %op-%action-<name> on MODIFY response rows or @status-rejected as proven yet. Activation returns no warnings, and no source says whether a behavior pool with an empty Local Types include fails activation. I confirm the handler source is in the Local Types include in the editor first. Failing that, the first action call at U15 proves it at runtime. I correct the handover README's BDEF extension and SRVD tag list in one pass after the UI leg, rather than interrupting the paste session.

2026-09-16 — Wave B active: base behavior definition and root access control live

  • What changed: I activated U10, the access control ZR_CHANGEAPPROVAL, and U6, the managed strict ( 2 ) behavior definition ZR_CHANGEAPPROVAL. Both answered "Activation successful." U6 activated through its .bdef.abdl URI on the first attempt, before its behavior pool class existed. That also proves the three action-parameter entities it references are active. I then created wave C empty: U7, the behavior pool ZBP_R_CHANGEAPPROVAL (create_object returned only the global .clas.abap path, no local-types include), and U8, the UI projection view ZC_CHANGEAPPROVAL (.ddls.acds) [source: adt-mcp abap_activate_objects, abap_creation-create_object on 0M7DEJI, verified 2026-09-16].
  • Why: wave B of the UI leg.
  • Affected: dev tenant ZARENA_PLM, PRD RAP BO status, handover README (the BDEF activation extension is .bdef.abdl for U6, U9 and W3, and the U6 fallback was not needed), KNOWLEDGE.md.
  • Decision: now that an empty ZBP_R_CHANGEAPPROVAL exists, I activate U6 and U7 together in one call, so the BDEF is never checked against a class that is not yet a behavior pool. The activation tool returns no warnings, so warnings about the four unmapped calculated fields are checked in the editor's Problems view rather than assumed absent. I locate the local-types include live, after the global class part is saved.

2026-09-16 — Wave A active: table, parameter entities and root view live; wave B created

  • What changed:
    • I activated U1 ZCHANGEAPPROVAL, U2–U4 (the three action-parameter entities) and U5 ZR_CHANGEAPPROVAL on my431353. Each activation answered "Activation successful.", and the tool returned no warnings.
    • The table activates through its .tabl.ddic URI; .tabl.json holds only header metadata.
    • U5's cast( case … as abap_boolean preserving type ) was accepted, so the fallback is not needed [source: adt-mcp abap_activate_objects on 0M7DEJI, verified 2026-09-16].
    • I then created wave B empty: U6, the managed BDEF ZR_CHANGEAPPROVAL (create_object returned …/zr_changeapproval.bdef.abdl), and U10, the access control ZR_CHANGEAPPROVAL (…/zr_changeapproval.dcls.acds, with protectedEntity).
  • Why: wave A of the UI leg. Creating the U6 BDEF requires the root view to be active, and it validated, which confirms U5 is active.
  • Affected: dev tenant ZARENA_PLM, PRD RAP BO status, the handover README activation table (TABL now proven; BDEF extension open), KNOWLEDGE.md.
  • Decision: BDEF source is pasted into .bdef.abdl, not .bdef.json. At U6 activation I try the .bdef.abdl URI first and fall back to .bdef.json, which activated a generator BDEF on 2026-09-15. The README activation table is corrected once U6 proves the extension. Activation gives no direct active/inactive readback, so proof is indirect: U6's activation is the first test of U2–U4, because U6 names them as action parameters.

2026-09-16 — Review fixes applied to the handover; duplicate checks read with privileged access

  • What changed: all four remaining review fixes are in docs/handover/rap/.

    • use etag sits in the entity header of both projection BDEFs.
    • retrySync writes APPROVED, so EXECUTING is written only by markExecuting.
    • All six action handlers set %fail-cause and %op-%action-<name>, merge the internal UPDATE's failed and reported rows, and return results only for keys that did not fail.
    • The base BDEF declares validation checkDuplicate on save { create; }. Its handler refuses a second non-REJECTED record with the same ItemNumber + ChangeType + ArenaEcoId, within the request or against persisted rows.

    The base BDEF and README carry the OQ-8 note that authorization master ( none ) is not final. The table's paste target is .tabl.ddic; its activation extension is still pending live proof. Two of my working sessions wrote these files concurrently between 02:36 and 02:43. I confirmed the result is consistent and stable (content unchanged over 45 seconds at 02:45, no duplicate governance entries). This session is now the only one driving the build.

  • Why: review findings B1, M1, m1 and m4 (entry below). Every one must be in the source before its object is pasted.

  • Affected: handover U6, U7, U9, W3, U1 header, README; PRD RAP BO status.

  • Decision: the duplicate check reads ZR_CHANGEAPPROVAL with privileged access. The view is access-controlled, and a handler SELECT on it without privileged access breaks the RAP implementation rules [source: sap-docs sap-help abaprap_impl_rules; abap-docs /abap-docs-cloud/ABAPSELECT_PRIVILEGED_ACCESS, verified 2026-09-16]. The validation's failed rows carry only cause-unspecific, the only cause validations may use (same rules page). Three constructs are syntax I prove only at tenant activation, each with a documented fallback: OPTIONS PRIVILEGED ACCESS (fallback FROM … WITH PRIVILEGED ACCESS), %op-%action-<name> on MODIFY response rows, and preserving type on the U5 casts.

2026-09-16 — Root view U5 final: derived booleans cast as a whole

  • What changed: in zr_changeapproval.ddls.asddls, IsApprovable and IsRetriable are now cast( case status when … then abap.char'X' else abap.char' ' end as abap_boolean preserving type ). The file header records why: typed abap.char literals make the CASE result CHAR(1) [source: abap-docs /abap-docs-cloud/ABENCDS_TYPED_LITERAL_V2, verified 2026-09-16], and ABAP_BOOLEAN is "of data type CHAR of length 1" [source: abap-docs /abap-docs-standard/ABENDATAOBJECTS_TRUE_VALUE_GUIDL, verified 2026-09-16], so preserving type matches exactly. U5 is cleared for paste.
  • Why: review finding (4). A cast inside a CASE branch drops the data element semantics.
  • Affected: handover U5, wave A paste.
  • Decision: if activation still rejects preserving type, I drop only that addition, not the outer cast. I finalized U5 ahead of the remaining correction work so wave A is not held up. Two concurrent corrections collided on this file; each later brief names file ownership explicitly.

2026-09-16 — App documentation aligned to retry → APPROVED

  • What changed: I updated the four statements of the retry transition in app/ (README, both i18n #XBUT comments, the mock metadata.xml comment) from FAILED → EXECUTING to FAILED → APPROVED. No labels, annotations, manifest or mock data changed. npm run lint and npm run ts-typecheck pass.
  • Why: ARN-002 was amended today; the app's documentation must not describe the old state machine.
  • Affected: app/README.md, app/webapp/i18n/i18n.properties, app/webapp/i18n/i18n_en.properties, app/webapp/localService/mainService/metadata.xml, KNOWLEDGE.md.
  • Decision: I do not add a mock executeAction handler to show the new transition. The mock server ignores actions (KNOWLEDGE 2026-09-16), and the live RAP service replaces the mock at V-2 within this build, so a mock-only transition would be throwaway work. The remote ui5-mcp-server cannot lint local files; I lint UI5 code locally until that changes.

2026-09-16 — Pre-paste SAP review: one blocker, retry semantics corrected, authorization opened

  • What changed: I reviewed all 18 handover sources read-only against ABAP Cloud docs, clean-core release states, the PRD and the app contract. The app contract holds (17 properties, 3 actions, entity set ChangeApproval, no UI create/update/delete), and all 11 referenced SAP objects are clean core level A [source: sap-released-objects sap_check_clean_core_compliance, verified 2026-09-16]. The review found:
    • One blocker: use etag sat in the body of both projection BDEFs, but it belongs in the entity header [source: abap-docs /abap-docs-cloud/ABENBDL_CHARACTER_PROJECTION, verified 2026-09-16].
    • Two majors: retry semantics and missing per-operation authorization.
    • Four minors. I dispatched corrections before any affected source reached the tenant.
  • Why: every defect caught here saves a paste-and-activate round trip against the live tenant, and two of them were correctness defects, not syntax.
  • Affected: docs/handover/rap/ (U5, U6, U7, U9, W3, README), PRD ARN-002, RAP-2, new OQ-8, app/ documentation comments, KNOWLEDGE.md.
  • Decision:
    • (1) retrySync goes FAILED → APPROVED, clears ErrorMessage, and the worker re-claims the record through markExecuting. The earlier FAILED → EXECUTING could not be claimed, because markExecuting accepts only APPROVED. Working around that would make a retried record indistinguishable from one another run is executing, which is the double-write risk ARN-006 exists for.
    • (2) Duplicate staging is refused on create: a checkDuplicate validation on the semantic key while a non-REJECTED record exists. Webhook and delta poll can both deliver the same ECO, and I will not leave idempotency to the executors alone.
    • (3) Action handlers honor the RAP implementation contract (%fail, %op, propagated UPDATE failures, results only for successful keys), so the worker cannot read a failed markSynced as success.
    • (4) The derived boolean flags cast the whole CASE to abap_boolean, because a cast inside a CASE branch drops the data element semantics [source: abap-docs /abap-docs-cloud/ABENCDS_CAST_EXPRESSION_V2, verified 2026-09-16].
    • (5) Deferred: a metadata-level mandatory RejectReason, until after the POC (server-side enforcement exists).
    • (6) Opened: OQ-8. authorization master ( none ) stays for the dev-tenant POC only and must be replaced before business roles get the app.

2026-09-16 — Wave A created: table, parameter entities, root view exist empty

  • What changed: I created U1 ZCHANGEAPPROVAL (TABL) and U2–U5 ZD_CHANGEAPPROVAL_REJECTP, ZD_CHANGEAPPROVAL_SYNCEDP, ZD_CHANGEAPPROVAL_FAILEDP and ZR_CHANGEAPPROVAL (DDLS) in ZARENA_PLM. They are inactive and have no source. abap_transport-get answered isRecordingRequired: false. Each object passed validation and creation with the handover JSON unchanged. The table's returned URI ends in .tabl.ddic, not the .tabl.json that activated a generator-created table on 2026-09-15 [source: adt-mcp abap_creation-create_object on 0M7DEJI, verified 2026-09-16].
  • Why: wave A of the UI leg. The sources are pasted next.
  • Affected: dev tenant ZARENA_PLM, PRD RAP BO status, handover activation URI table (TABL extension open).
  • Decision: I activate U1 with the URI create_object returned (.tabl.ddic) and fall back to .tabl.json. The handover URI table is corrected once activation proves which one works.

2026-09-16 — Package recreated; UI-leg build started in waves

  • What changed: package ZARENA_PLM exists again under ZLOCAL. ADT MCP validation of ZCHANGEAPPROVAL in it succeeded (live, 02:27). I started wave A of the UI leg: U1–U5 (table, the three action-parameter entities, root view) are created empty so their sources can be pasted. I also read the create fields for classes, access controls and metadata extensions live. Those were the three types the handover had marked unconfirmed. Metadata extension names allow 40 characters. Access controls and metadata extensions take an optional protected/extended entity (KNOWLEDGE 2026-09-16).
  • Why: the from-scratch build (OQ-7) is unblocked. The build moves in waves bounded by activation dependencies: BDEF creation needs its root view active, and the binding needs its service definition active. Each wave asks for one paste session per group, not one per file.
  • Affected: dev tenant ZARENA_PLM, PRD RAP BO status, KNOWLEDGE.md.
  • Decision: waves are A = U1–U5 (create, paste, activate), B = U6 base BDEF, C = U7 behavior pool, D = U8 projection view + U10 root access control, E = U9 projection BDEF + U11 + U12 + U13, F = U14 binding with the service-alias check. Nothing is activated before its source is pasted.

2026-09-16 — Handover regenerated under clean names; binding names cut to SAP's 26-character limit

  • What changed: I regenerated docs/handover/rap/ for a build from an empty package. Eleven source files were renamed to the clean object names, every internal reference was updated, and the README was replaced with a create → paste → activate sequence per object. The UI service definition exposes only ChangeApproval. A scripted comparison against the app's mock metadata.xml confirms that the UI projection carries all 17 app properties plus approve, reject and retrySync. The build splits into a 14-source UI leg and a 4-source worker leg. The markSynced/markFailed parameter entities move into the UI leg, because the base BDEF references them and they must be active first. I amended RAP-5 to two service definitions with one binding each, and updated both PRD interface-contract rows. A read-only SAP review of the 18 sources is running before the paste session.
  • Why: the tenant package is empty, so the handover's generator inventory and ZZ…000 targets no longer existed. SAP Help gives a maximum of 26 characters for service binding names, the same in ABAP Cloud, SAP Cloud Platform and ABAP Platform 2021 [source: sap-docs sap-help loio 4bad0d7280b742a68dd2d42b1441f09a, f3e608ace2a64aada33bdd3e2419113a, 777e027f61c3490dba0433443d9143a6, verified 2026-09-16]. The ADT MCP's create metadata allows 30, and generator bindings of 29–30 characters activated on 2026-09-15, but none was ever published. No source says whether publishing tolerates more than 26.
  • Affected: PRD RAP-5, the two approval-BO interface-contract rows, RAP BO status, docs/handover/rap/, V-2 (the app's dataSource URL, mock namespace and annotation targets now carry a planned difference), KNOWLEDGE.md.
  • Decision: the bindings are ZUI_ARENA_CHANGE_APPR_O4 (24) and ZAPI_ARENA_CHANGE_APPR_A2X (26). The service definitions keep ZUI_ARENA_CHANGE_APPROVAL and ZAPI_ARENA_CHANGE_APPROVAL. I chose the documented limit over the tool's undocumented allowance, because a refusal at publish would come after the whole UI leg and need a delete in ADT to recover. The app edit this causes is one URL segment plus the namespace, both already scheduled for V-2 reconciliation against live $metadata, so I defer it to that brief instead of changing the app twice. The derived-field EDM types (StatusCriticality as INT1, abap_boolean flags, utclong, sysuuid_x16) stay unverified until live $metadata exists; they are not assumed.

2026-09-16 — Deletion verified live: package ZARENA_PLM is gone; name limits confirmed

  • What changed: with the ADT MCP back online I probed my431353 read-only. abap_creation-run_validation answers "Package 'ZARENA_PLM' does not exist" for tables, data definitions and classes, the same as a nonexistent control package. The deletion removed the package itself, not just its contents. abap_creation-get_object_type_details gives the maximum name lengths: database table 16; data definition, service definition, service binding and behavior definition 30 [source: adt-mcp abap_creation-get_object_type_details on 0M7DEJI, verified 2026-09-16].
  • Why: the from-scratch build starts from the package, and every clean name had to fit its limit before any object is created.
  • Affected: PRD RAP BO status, docs/handover/rap/README.md (step 0 is now "recreate the package"), KNOWLEDGE.md.
  • Decision: I recreate ZARENA_PLM under ZLOCAL under the same name, so every activation URI pattern verified on 2026-09-15 stays valid. All clean names fit (ZCHANGEAPPROVAL 15, ZUI_ARENA_CHANGE_APPROVAL_O4 28). ZLOCAL means no transport request on every create while I prototype. It is not a dead end for production: a package can be reassigned from ZLOCAL to ZCUSTOM_DEVELOPMENT (transport layer YDEV) later, though not the reverse [source: sap-docs sap-help loio a0d80f14fcb74cb1ac8fb6f3d9ad48cc (2608), verified 2026-09-15]. I make that move once the approval app works end to end on the development tenant.

2026-09-16 — Tenant package emptied; from-scratch build under names that match the Fiori app

  • What changed: the ZARENA_PLM contents on my431353 were deleted in ADT. This includes both generator sets and the empty hand-created objects. I have not yet verified the deletion live (the ADT MCP is offline), and the package's own survival is unconfirmed. I closed OQ-7 and dispatched a regeneration of docs/handover/rap/ under the clean names.
  • Why: the Fiori app binds to /sap/opu/odata4/sap/zui_arena_change_approval_o4/srvd/sap/zui_arena_change_approval/0001/, entity set ChangeApproval, and actions approve, reject and retrySync (app/webapp/manifest.json, mock metadata.xml). A Fiori app runs against a replacement service only if the entity set names, properties and actions match [source: fiori-mcp-server search_docs "Replacing OData Service in an Adaptation Project", verified 2026-09-16]. With the package empty, no leftover objects compete for these names.
  • Affected: PRD OQ-7 (closed), RAP BO status, docs/handover/rap/ (all 19 sources and the README), V-2 (the service identity is now designed to match the app instead of reconciled after the fact).
  • Decision: no generator this time, because it forces a ZZ prefix and a 000 suffix (KNOWLEDGE, 2026-09-15). I create each object through the ADT MCP under its final name: table ZCHANGEAPPROVAL, ZR_CHANGEAPPROVAL, ZBP_R_CHANGEAPPROVAL, ZC_CHANGEAPPROVAL, SRVD ZUI_ARENA_CHANGE_APPROVAL, SRVB ZUI_ARENA_CHANGE_APPROVAL_O4. The A2X names are unchanged. The UI leg (about 13 sources) is built and verified against the app before the worker leg starts.

2026-09-16 — Tenant state corrected: two generator sets, no designed logic deployed; naming decision opened

  • What changed: a live ATC run over ZARENA_PLM returned 43 objects, not the 12 my 2026-09-15 handover README lists. The package holds two default x-ui-service generator sets side by side: the ZZ…000 set (ZZCHNGPPROVAL000, ZZR_/ZZC_CHANGEAPPROVAL000, binding ZZUI_ARENA_CHANGE_APPRVL000_O4) and a set without the suffix (ZZCHANGEAPPROVAL, ZZR_/ZZC_CHANGEAPPROVAL, binding ZZUI_ARENA_CHANGE_APPROVAL_O4). Each set has its own behavior pools and SAP object types. It also holds the five empty, inactive hand-created objects and the probe class. None of the six actions, the status machine, or the feature control exists in any tenant object. The designed source lives only in docs/handover/rap/, which is now committed and pushed (f8b45ea). My most likely explanation for the second set is an earlier generator run that I never recorded; I cannot confirm it, because the ADT MCP has no read tool.
  • Why: my 2026-09-15 entry and the PRD status described a clean skeleton that was ready for a paste session. Following them would put the sources into objects whose names the Fiori app does not bind to.
  • Affected: PRD status (RAP BO → blocked on OQ-7), new OQ-7, docs/handover/rap/README.md (its object inventory is stale), the Fiori app's V-2 service identity.
  • Decision: none yet. I recommend building under clean names that match the app, next to the unused sets, and deferring deletion. The two sets are unpublished, their ZZ names do not collide with the clean set, and deleting them needs Eclipse ADT, which is not set up. Of the 19 sources, 13 serve the UI milestone. The six A2X-leg files wait until the app runs against the real service.

2026-09-15 — abapGit researched: not required for ADT for VS Code; viable as a bulk source-load path

  • What changed: I verified that abapGit is neither required nor used by SAP's ADT for VS Code; the belief traces to the community vscode-abap-remote-fs extension on this host. In S/4HANA Cloud Public Edition, abapGit is SAP's supported fork reachable only through the Eclipse ADT "abapGit Repositories" plug-in, and SAP lists it as the initial-transfer tool for developer extensibility code in every delivery model [source: sap-docs sap-help loio ec943b4ee4ac4dfdac47081d1d3e4019 "Overview of ABAP Lifecycle Management Options", verified 2026-09-15]. Recorded as a KNOWLEDGE landmine.
  • Why: the RAP handover (19 ready-to-paste sources under docs/handover/rap/) is blocked on source entry because the ADT MCP Server cannot write source (PRD V-4). abapGit pull from a repository is the one SAP-standard bulk alternative to pasting file by file in the editor.
  • Affected: KNOWLEDGE.md, PRD V-4 (an option, not a change of decision).
  • Decision: keep VS Code editor paste as the default for this first BO (19 files, one-off); evaluate the abapGit pull path only if a second bulk load is needed, because it requires Eclipse ADT plus an abapGit-formatted repository with the metadata files the serializer expects.

2026-09-15 — Approval BO skeleton generated on my431353; source handover written

  • What changed: I generated the Arena change-approval RAP business object into ZARENA_PLM with SAP's "OData UI Service from Scratch" generator (transactional without draft, 13 business fields incl. SapPreview as string): table ZZCHNGPPROVAL000, root view/BDEF/DCL ZZR_CHANGEAPPROVAL000, behavior pool ZZBP_R_CHANGEAPPROVAL000, UI projection ZZC_CHANGEAPPROVAL000 (+ BDEF, metadata extension, DCL, pool), service definition + OData V4 UI binding ZZUI_ARENA_CHANGE_APPRVL000_O4 (unpublished), SAP object type/node type — all active, ATC: 0 findings on 12 objects (live, 2026-09-15). For the worker I created a separate A2X projection ZC_CHANGEAPPROVAL_A2X (+ DCL) and service definition ZAPI_ARENA_CHANGE_APPROVAL, plus three abstract entities for action parameters; these exist empty and inactive. The A2X BDEF and the Web API binding ZAPI_ARENA_CHANGE_APPROVAL_A2X cannot be created until their referenced objects are active. Nineteen ready-to-paste source files and an ordered paste-and-activate sequence are in docs/handover/rap/.
  • Why: RAP-1..8; the MCP creates structure but not source (V-4), so logic — six actions with instance feature control, status transitions, the on-modify determination, text/criticality/semantic-key annotations — is delivered as source for the VS Code editor.
  • Affected: dev tenant ZARENA_PLM; PRD interface contracts (binding names now real), RAP-5/RAP-6 wording, status; KNOWLEDGE (generator landmines).
  • Decision: (1) two service definitions, not one — a projection BDEF exposes only what it lists, so sharing one definition would hand the UI create and the worker actions [source: abap-docs /abap-docs-cloud/ABENBDL_USE_PROJECTION, verified 2026-09-15]; the UI gets ZZUI_ARENA_CHANGE_APPRVL000_O4, the worker ZAPI_ARENA_CHANGE_APPROVAL_A2X. (2) markSynced/markFailed take abstract-entity parameters, since action input must be an abstract entity or DDIC type [source: abap-docs /abap-docs-cloud/ABENBDL_ACTION_INPUT_PARAM, verified 2026-09-15]. (3) Derived fields (StatusCriticality, StatusText, IsApprovable, IsRetriable) are CASE expressions in the root view, not persisted — falsifiable at activation; fallback documented in the file header. (4) authorization master ( none ): IAM catalog + DCL are the only access control (ADR-002) [source: abap-docs /abap-docs-cloud/ABENBDL_AUTHORIZATION, verified 2026-09-15]. (5) Generator naming (ZZ…000) is kept; the Fiori app reconciles from live $metadata at V-2.

2026-09-15 — Write path proven: probe class created and activated in ZARENA_PLM; RAP build dispatched

  • What changed: after the owner created development package ZARENA_PLM under ZLOCAL in Eclipse ADT, the ADT MCP created ZCL_ARENA_V4_PROBE there and activated it (no transport, as SAP Help states for ZLOCAL sub-packages from 2508 [source: sap-docs loio a0d80f14fcb74cb1ac8fb6f3d9ad48cc, verified 2026-09-15]). Object-type probes: DDLS/BDEF/SRVB/TABL creation takes metadata only (name, package, referenced object, BDEF root entity and implementation type, SRVB binding type incl. "OData V4 - Web API"), never source. I granted rap-developer the adt-mcp tools and pointed it at the dev tenant, then dispatched the approval-BO build.
  • Why: V-1b and V-4 are closed; the RAP track (RAP-1..8) has no remaining gate.
  • Affected: PRD V-1b/V-4 (closed), status RAP BO (In progress), .claude/agents/rap-developer.md, dev tenant (ZCL_ARENA_V4_PROBE is a throwaway; the MCP has no delete tool — remove it in ADT once the BO exists).
  • Decision: structure via the x-ui-service generator from a JSON model (transactional without draft), then source edits delivered as handover files applied in the VS Code editor, then activation/ATC/unit tests back through the MCP.

2026-09-15 — Correction: A4C catalogs are right; the write block was the package, not the role

  • What changed: I withdraw my earlier suggestion to check the role for an SAP_A4_BC_* catalog. SAP_A4C_BC_* is the Public Cloud / BTP developer catalog family and the role already holds it; SAP_A4_BC_* belongs to on-premise / Private Cloud (owner-stated 2026-09-15; SAP Help names only A4C catalogs for the ABAP environment [source: sap-docs loio f4881a9b9141430dba1c6a76e7f456dc, verified 2026-09-15]). Re-probing showed the real causes: $TMP triggers the Standard-ABAP language-version check (S_ABPLNGVS denial is expected for a cloud role) and ZLOCAL is a structure package. Both recorded as KNOWLEDGE landmines.
  • Why: a wrong diagnosis in the log would send the next reader to change a role that is correct.
  • Affected: KNOWLEDGE.md, PRD V-1b wording.
  • Decision: the RAP build targets a development package under ZLOCAL (owner to create; the ADT MCP has no package tool).

2026-09-15 — V-4 probe: MCP write path shape known; first write blocked by S_ABPLNGVS

  • What changed: with destination 0M7DEJI logged on, the ADT MCP Server lists it and answers for the dev tenant (verified 2026-09-15). Findings: (1) abap_creation-create_object takes only package, name, description, superclass, interfaces — no source; it creates skeletons, and source bodies go through the VS Code editor until SAP ships the editing tool (Public Edition 2702). (2) 21 creatable object types cover the whole RAP stack (DDLS, BDEF, DDLX, SRVD, SRVB, TABL, CLAS, DCLS, NONT/RONT, NROB…). (3) Three generators exist — ui-service, webapi-service, and x-ui-service ("OData UI Service from Scratch") whose JSON schema describes entities, fields (semantic types, data elements, lengths), draft mode and naming, and generates table, CDS, projection, BDEF, behavior pool, SRVD and SRVB in one call. (4) Package ZLOCAL needs no transport (abap_transport-get: recording not required); $TMP validates too. (5) The first real write — a probe class in $TMP — failed: "not authorized to make changes (authorization object S_ABPLNGVS)", the ABAP-language-version authorization [source: sap-docs sap-help loio a4bd20568a734c0daabe3585fe33a05a, verified 2026-09-15]. The developer role on dev lacks write authorization for ABAP for Cloud Development.
  • Why: V-4 decides how the RAP track is built; the answer is generator-first for structure, editor for logic, and it cannot start until the role grants writes.
  • Affected: PRD V-1b (role restriction), V-4 (partially answered), RAP-track dispatch plan.
  • Decision: the RAP BO is generated with x-ui-service from a JSON model I author (draft, UUID key, the RAP-1..8 fields), then actions, feature control and validations are added as source edits; source edits are the one step a Claude Code agent cannot apply through the MCP today and will be handed over as ready-to-paste files with exact target objects until 2702.

2026-09-15 — Dev-tenant communication arrangements for this package in place

  • What changed: on my431353, AZ_INTEGRATION_DEV / AZ_API_USER now carries AZ_IDENTITY_PROVISIONING_INT (0193), AZ_PRODUCT_MASTER_INT (0837), AZ_PLM_DOC_INFO_INT (0105) and AZ_PLANT_CONFIG_INT (0108), alongside the pre-existing AZ_COMM_MGMT_INT (0A48). Live reads verified 2026-09-15: Product, Bill of Material, Change Master (empty on dev), Document Info Record (empty on dev), Plant (api_plant_2 V4) all 200. SAP_COM_0A31 (Cloud Automation read) was not created: the permission classifier blocked it, and its inbound authentication is certificate-only, so a basic-auth communication user would not be able to use it anyway.
  • Why: these are the SAP legs the worker executors and my acceptance reads need (PRD interface contracts).
  • Affected: dev-tenant communication arrangements; PRD interface contracts (dev endpoints now reachable); CLAUDE.md live-check note.
  • Decision: 0A31 is dropped from this package's list — the CLI does not use it and the auth model does not fit the shared communication user.

2026-09-15 — ADT MCP Server live on this host; registered as adt-mcp

  • What changed: SAP's ADT MCP Server (extension sapse.adt-vscode 1.1.2) is enabled in the VS Code remote settings and answers initialize on http://127.0.0.1:2236/mcp as "ADT MCP Server 1.0.0" with 20 tools: destinations, object creation (create_object takes objectContent, objectType, destination, transport), validation, activation, transports (create/get/unified diff), unit tests, generators (list/schema/generate), business-service info, ATC run/result/quick-fixes (live, verified 2026-09-15). I registered it in .mcp.json as adt-mcp (HTTP, bearer header). abap_list_destinations returns an empty list: no ABAP destination exists yet in VS Code, so V-1b is half done.
  • Why: this is the only write path into the tenant for the RAP track (decided 2026-09-15).
  • Affected: .mcp.json (git-ignored), PRD V-1b, V-4.
  • Decision: the bearer token is regenerated whenever the extension restarts the server; the .mcp.json entry must be refreshed from ~/.vscode-server/data/Machine/settings.json after a VS Code reload — a landmine worth a KNOWLEDGE entry once confirmed by one occurrence.

2026-09-15 — V-1 confirmed live: developer role on my431353; 0193 arranged; CLI now targets dev

  • What changed: sap-api users getRoles --user AZAW on the development tenant returns eight roles including ZBR_DEVELOPER (the SAP_BR_DEVELOPER template) and ZBR_ADMINISTRATOR_SW_DEV (live, 2026-09-15). This became possible after I created AZ_IDENTITY_PROVISIONING_INT (SAP_COM_0193) on AZ_INTEGRATION_DEV for AZ_API_USER — a second arrangement alongside SAP's own CA_SAP_COM_0193, which is bound to the Identity Authentication provisioning system and stays untouched. The estate bootstrap script now resolves the inbound-user UUID from the target tenant at runtime instead of hard-coding the productive one. _shared/.env now carries the dev-tenant credential (productive copy kept as .env.prod-my429480.bak), so the CLI targets my431353 by default.
  • Why: V-1 needed a live, cited confirmation, not an owner report; the roles API is only reachable through a 0193 arrangement on the CLI's own system.
  • Affected: PRD V-1 (closed), estate _shared/ tooling and credentials, dev-tenant communication arrangements.
  • Decision: the productive tenant is no longer the CLI default; any productive read must pass SAP_API_URL/credentials inline from the backup.

2026-09-15 — Development tenant reachable; communication layer bootstrapped

  • What changed: the sap-api CLI now logs on to my431353 with the communication user AZ_API_USER on communication system AZ_INTEGRATION_DEV (credentials kept in ~/projects/sap-integrations/.env, one level above _shared/; the CLI's own loader still reads _shared/.env, which holds a stale productive credential — 401 on both tenants). Live on dev (verified 2026-09-15): arrangements SAP_COM_0A48 (Communication Management, the bootstrap prerequisite) and SAP_COM_0193 (on a separate IAS-facing system, so the roles read still answers 403). The scenario catalog was refreshed (363 scenarios). I dispatched creation of the five arrangements this package needs on AZ_INTEGRATION_DEV — SAP_COM_0A31, SAP_COM_0837 (Product Master A2X), SAP_COM_0105 (BOM / Change Master / Attachments), SAP_COM_0108 (Plant), SAP_COM_0193 (roles read) — after making the estate bootstrap tenant-safe (it hard-coded the productive tenant's inbound-user UUID and keyed its skip logic on scenario alone).
  • Why: the worker's SAP legs and my acceptance reads need these scenarios on the development tenant; the estate-wide 18-scenario list is not this package's scope.
  • Affected: _shared/bootstrap-comm-arrangements.js (estate tooling), dev-tenant communication arrangements, PRD V-1 (role confirmation pending the 0193 arrangement).
  • Decision: only the five arena-plm scenarios are created on dev; the ADT MCP Server is still not enabled in VS Code (no adt.mcpServer.* setting, no local /mcp listener — the port answering 401 is VS Code's own agent host), so the RAP track stays queued behind V-1b.

2026-09-15 — V-1 opened: development tenant my431353 with developer role; write path to the tenant identified

  • What changed: developer access on the development tenant my431353.s4hana.cloud.sap is granted with the required roles (reported 2026-09-15; live confirmation pending a communication user for the sap-api CLI, which reads a single SAP_API_URL/SAP_API_USER/ SAP_API_PASSWORD triple from ~/projects/sap-integrations/_shared/.env and currently answers 401 against both tenants). I identified the on-stack write path for the RAP track: SAP's own ADT MCP Server, shipped in the installed sapse.adt-vscode 1.1.2 extension, exposed as a local HTTP MCP endpoint http://localhost:<port>/mcp with an auto-generated bearer token (settings adt.mcpServer.enabled / .port / .token) [source: extension package.json contributes.configuration, verified 2026-09-15]. Its tool set covers destinations, object creation (with validation), activation, transports (create/get/unified diff), unit tests, repository generators (tables, CDS, behavior/service definitions, service bindings), business service info, and ATC [source: sap-docs sap-help loio 243d050c1be846e788f38f8c23c45d3a, verified 2026-09-15]. ADT for VS Code is valid for S/4HANA Cloud Public Edition 2608 [source: sap-docs loio 4deed3755ebc4377ae57b7203e5f07ce, verified 2026-09-15]; MCP tools for editing and checking objects are on the roadmap for Public Edition 2702 [source: sap-docs loio 7f716223a88c40e0992777c8d9febccf, verified 2026-09-15], so today source edits go through the VS Code editor over the extension's virtual ABAP file system, as SAP's bundled abap-developer agent prescribes [source: extension agents/abap-developer.agent.md, verified 2026-09-15].
  • Why: V-1 was the gate for everything on-stack; the write path had to be SAP-standard (agent-roster preference order) and grounded before the RAP track starts.
  • Affected: PRD V-1, V-4 (new), agent roster (rap-developer tool surface), .mcp.json (pending: ADT MCP registration).
  • Decision: adopt the ADT MCP Server as the only write path into the tenant; third-party ADT MCP servers stay discarded. Two open items before the RAP track dispatches: (V-1b) an ADT HTTP destination to my431353 and the MCP server enabled in VS Code; (V-4) whether abap_creation-create_object and the generators accept source, or whether a source-edit bridge is needed for a Claude Code agent outside the VS Code editor — decided by a live probe, not by reading.

2026-09-14 — Worker corrections accepted (contract v0.2.1); review wave closed

  • What changed: a full ingest buffer at poll time now fails the tick (cursor holds, health degraded, next tick re-covers the window); the object-type token is DOCUMENTS; every emitted status code is governed — default problem+json on all four operations, 415 and 413 on both POSTs, route-level 404 documented as the default case; the surface is JSON-only (the built-in text/plain parser is removed so unsupported media types answer 415); processed is absent until an object has run; /health and run snapshots carry only fixed, allow-listed error phrases (upstream bodies and messages never reach the wire); TTL and delta-feed comments no longer assert what no source records. 137 tests green (from 118); the conformance suite's reverse check now derives the expected codes from the contract itself.
  • Why: closes review findings B1–B6 and A4.
  • Affected: worker/, docs/api/worker.openapi.json (0.2.0 → 0.2.1), ARN-001 (token), ARN-003, ARN-009.
  • Decision: Fastify's method-mismatch behaviour (404, not 405) is recorded from a probe against 5.12.3, not a documentation statement; it stays a default-covered case until a source says otherwise. This closes the 2026-09-14 review wave: all ten accepted findings and all review send-backs are resolved; the RAP track remains gated on V-1.

2026-09-14 — Fiori app: review corrections accepted

  • What changed: the app now carries the binding-derived identity (zui_arena_change_approval_o4 in URL and namespace), the six-state status domain with eight mock rows, Approve/Reject only on the object page with the staged payload in its own facet ahead of the decision, table selection off, a launchpad inbound ArenaChangeApproval-manage, the three-part semantic key, DecidedBy, an unbounded SapPreview, and no dead annotation registrations in the mock/local YAML. Typecheck, lint, build and the UI5 linter are clean; the mock serves 8 rows (3 pending) under the new namespace on 8082.
  • Why: closes review findings A1–A6, A8, A9.
  • Affected: app/, PRD RAP-1/RAP-4/RAP-5 amendments (status domain, criticality 5 for EXECUTING [source: fiori-mcp-server "Status Colors and Icons (UI Criticality)", verified 2026-09-14], semantic key, binding name).
  • Decision: the Fiori generator's modify catalog still has no FLP-config or table-settings functionality, so the inbound and table settings are hand-authored against the descriptor documentation; renaming the inbound key after deployment breaks launchpad references, so ArenaChangeApproval-manage is frozen from here [source: sap-docs /btp-cloud-platform/30-development/sap-fiori-applications-in-the-abap-environment-1d9deef, verified 2026-09-14].

2026-09-14 — SAP review verdicts: both scopes sent back narrowly; namespace claim corrected

  • What changed: the read-only SAP review returned "send back, narrowly" for the Fiori app and "accept with minors, conditional on one reversal" for the worker. I accepted every finding and dispatched two correction briefs in parallel. I also correct my own claim from earlier today: the OData V4 namespace and the first URL segment derive from the service binding (group) name, not the service definition — the tenant serves /api_currencyexchangerate/srvd_a2x/sap/currencyexchangerate/0001 with namespace com.sap.gateway.srvd_a2x.api_currencyexchangerate.v0001, and SAP Help shows /api_product/srvd_a2x/sap/product/0002 [source: sap-docs sap-help loio 5f45f125dfe84c20beb18f5de1512f5a; tenant EDMX line 55 and exchange-rates-cap/package.json:33,39, verified 2026-09-14]. Strongly indicated for custom UI bindings, not yet proven; V-2 confirms it.
  • Why: naming and state-machine decisions are cheap now and expensive once the RAP BO exists; the worker's drop-on-full-buffer trade-off violated ARN-003's intent by losing a poll window with no recovery path today.
  • Affected: app/, worker/, docs/api/worker.openapi.json (→ 0.2.1), PRD ARN-001/ARN-002 wording, interface-contract rows, RAP-track requirements, KNOWLEDGE landmine text.
  • Decision: (1) provisional identity is binding ZUI_ARENA_CHANGE_APPROVAL_O4, definition ZUI_ARENA_CHANGE_APPROVAL, URL first segment and namespace from the binding. (2) The approval state machine gains post-execution states: PENDING → APPROVED → EXECUTING → SYNCED | FAILED, REJECTED terminal, FAILED → retrySync → EXECUTING; the worker drives EXECUTING/SYNCED/FAILED through actions on the A2X binding so an approved record can never be executed twice (ARN-006). (3) Approve/Reject leave the list toolbar and live only on the object page, where the staged payload is shown in its own facet before the decision (ARN-010 is not decorative). (4) The object-type token is DOCUMENTS everywhere (PRD ARN-001 is the requirement source); the worker contract follows. (5) A full ingest buffer at poll time is a tick failure: the cursor holds and health degrades; duplicates on recovery are accepted because SAP is the ledger. (6) Every status code the worker emits is governed by a default problem+json response plus explicit 415/413. (7) Error text in /health and run snapshots is a fixed phrase, never a raw upstream message. (8) ApprovedBy becomes DecidedBy; the semantic key is ItemNumber + ChangeType + ArenaEcoId; the staged payload is abap.string on the RAP side.

2026-09-14 — Worker contract conformance is now a test, not a review step

  • What changed: I added worker/test/contract.test.ts (35 tests): every components.schemas.* in docs/api/worker.openapi.json compiles under the JSON Schema 2020-12 dialect, every documented status code of every operation is exercised through the real Fastify instance and its body validated against the contracted schema, all error bodies are application/problem+json, and 5xx bodies carry no upstream or internal detail. A reverse check fails the suite if a status code is added to the contract without a test. 118 tests green. Dev dependencies added: ajv 8.20, ajv-formats 3.0 (test only; Ajv was already transitive via Fastify).
  • Why: ARN-009 says the implementation conforms to the contract; today's review found /health drifting off its enum. A schema-driven suite turns that class of finding into a red test.
  • Affected: worker/test/, worker/package.json, ARN-009.
  • Decision: the reserved 502 response stays unattached to any operation and is covered only through the error-handler path until a route calls Arena synchronously.

2026-09-14 — Fiori app rebound to the SAP gateway service shape; UX polished

  • What changed: I rewrote the mock service and every annotation target to the shape an ABAP Cloud OData V4 UI service emits (com.sap.gateway.srvd. zui_arena_change_approval.v0001, alias SAP__self, ChangeApproval_Type, entity set ChangeApproval), re-pointed the manifest to the UI-binding URL, renamed the app id to com.minicircuits.arenaplm (the folder stays the structural app/), seeded six mock rows across all four states, pinned the mock server to port 8082, and polished the UI: semantic key on the item number, default sort (status, then newest request) with a PENDING default filter loaded on start, importance tiers for responsive columns, hidden technical fields, a second header facet with the Arena ECO and SAP change number, an approvals icon, multi-line staged payload, and status-dependent action availability via Core.OperationAvailable on IsApprovable / IsRetriable. Typecheck, lint, build and the UI5 linter are clean; the mock service answers $metadata, the entity set (6 rows, 3 pending) and the annotation file with 200.
  • Why: the review's ship-blocker — annotations against an invented namespace silently render nothing on the real service [source: KNOWLEDGE.md 2026-09-14 landmine]. Polish makes the approver's landing page the pending queue, which is the job the app exists for (ARN-002, ARN-010).
  • Affected: app/ (metadata, mock data, annotations, manifest, i18n, Component, ui5*.yaml, package.json, OPA journeys, README), PRD RAP-track requirements (harvested below), V-2.
  • Decision: the Fiori generator's modify catalog covers no annotation or manifest-setting change, so these edits are hand-authored against cited Fiori Elements documentation; the manifest _version moved to 2.11.0 to match minUI5Version 1.152 [source: sap-docs /sapui5/03_Get-Started/step-10, verified 2026-09-14]. The ui5-mcp-server cannot see this filesystem (ENOENT on realpath), so UI5 linting ran through @ui5/linter directly.

2026-09-14 — Worker review fixes landed; contract v0.2.0

  • What changed: contract first, then code: /health session state enum is none|active|expired|refreshing, status turns degraded on the last poll or login failure and a poller block reports last run/success/error; SyncRunRequest is strictly additionalProperties:false with no type coercion and no defaults; the webhook intake answers 503 + Retry-After when the bounded buffer (WEBHOOK_QUEUE_MAX_SIZE, default 10000) is full; a reserved 502 response maps upstream Arena errors without leaking bodies. In code: the session TTL now flows from config by construction (a rename is a compile error), the poll cursor advances only after a successful fetch, shutdown drains in-flight runs and the current poll tick under SHUTDOWN_TIMEOUT_MS through one Fastify onClose path, HTTP calls carry ARENA_HTTP_TIMEOUT_MS, integer env parsing is strict, duplicate SYNC_OBJECT_ORDER entries are rejected, and npm run dev loads .env when present. 83 tests green (from 37); build and lint clean.
  • Why: six verified correctness findings, all latent until the real Arena client lands — cheapest to fix before it does.
  • Affected: worker/, docs/api/worker.openapi.json (0.1.0 → 0.2.0), ARN-005, ARN-009.
  • Decision: a full buffer during a poll drops the overflow and still advances the cursor (retrying the window would duplicate the events that fit); those changes are recovered by the V-3 durable cursor, not by the worker. I am having this trade-off reviewed. The worker package version stays 0.1.0 until a release; /health.version reports it.

2026-09-14 — ADR-003 gate hardened; secret-bearing files git-ignored

  • What changed: I closed the four governance findings from the review. The consult gate now covers Bash/MultiEdit/NotebookEdit/filesystem-MCP writes, only grounding-server and web consultations refresh the marker, hooks resolve the repo from CLAUDE_PROJECT_DIR, the gate fails closed without jq, worker/ is no longer SAP-gated, and a 37-case pipe-test harness guards the scripts. .gitignore now excludes .mcp.json (live tokens), .claude/settings.local.json, **/.vscode/, **/.remember/, app/.appGenInfo.json; a dry-run git add -A stages none of them.
  • Why: enforcement that the standard tools bypass is prose, not structure (ADR-003's premise); and the repo's first commit must not publish tokens.
  • Affected: .gitignore, .claude/settings.json, .claude/hooks/* (+ tests/run.sh), docs/adr/ADR-003 (amended).
  • Decision: fail closed on a missing classifier dependency, accepting that a host without jq cannot edit anything in this repo until it is installed.

2026-09-14 — Code review accepted; correction to the scaffold entry; hardening wave dispatched

  • What changed: I ran a full code review over the package (31 candidate findings, all verified, none refuted) and accepted its top ten as the next build wave. I also correct my 2026-09-14 scaffold entry below: the generator emitted app id com.minicircuits.app (not com.minicircuits.arenaplm), no mock rows were seeded (the mockdata path did not exist), and the mock server was not pinned to port 8082. Those three claims described intent, not the repo; this wave makes them true.
  • Why: two findings are ship-blockers. (1) .mcp.json carries live bearer tokens and is not git-ignored in a repo with zero commits. (2) Every annotation target in the Fiori app uses the invented namespace com.minicircuits.arenaapproval; an ABAP Cloud OData V4 service emits com.sap.gateway.<srvd|srvd_a2x>.<service>.v0001 with alias SAP__self and <Entity>_Type entity types, so against the real service the List Report would render with no columns, filters, facets or actions — and the mock hid it because mock metadata and annotations agreed with each other [source: live tenant my429480 EDMX, API_CURRENCYEXCHANGERATE.edmx lines 55/57/95, verified 2026-09-14]. The remaining findings are worker correctness bugs (session TTL silently discarded, poll cursor advanced before fetch, /health off-contract, non-strict Ajv, unbounded queue, SIGTERM killing runs) and the ADR-003 gate being bypassable (Bash/MultiEdit writes unmatched; any MCP call refreshing the marker; absolute hook paths).
  • Affected: .gitignore, .claude/ (hooks, settings), worker/, docs/api/worker.openapi.json (→ v0.2.0), app/ (metadata, manifest, annotations, mock data, app id), PRD interface contracts, V-2, status.
  • Decision: I split the approval-BO service into two bindings — an OData V4 UI binding for the Fiori app and an OData V4 Web API (A2X) binding for the worker's technical user — because SAP's own path builds the Fiori UI on a UI service binding [source: sap-docs sap-help loio 5717c0a1dafc4335add0207b81c39cef, verified 2026-09-14]. The app now targets the provisional identity zui_arena_change_approval (namespace com.sap.gateway.srvd.zui_arena_change_approval.v0001); the exact namespace, entity-type suffix and URL segment are reconciled against the live $metadata at V-2 before any deploy. Worker contract v0.2.0: session state enum gains expired/refreshing, status becomes degraded on poll or login failure, SyncRunRequest is strictly additionalProperties:false, and the webhook intake returns 503 when the bounded buffer is full. Gate hardening: only the grounding servers refresh the consult marker; Bash, MultiEdit, NotebookEdit and filesystem-MCP writes are gated; hooks resolve the repo from CLAUDE_PROJECT_DIR; the gate fails closed without jq; the non-SAP worker/ path leaves the SAP gate. I dispatched the three independent streams (config hardening, worker fixes, Fiori correction + polish) in one parallel wave; tests and the read-only SAP review are gated behind them.

2026-09-14 — Fiori Elements UI scaffolded (com.minicircuits.arenaplm), on mock, at the package root

  • What changed: I scaffolded the approval workbench's Fiori Elements List Report / Object Page UI as com.minicircuits.arenaplm (TypeScript, UI5 1.152) in the structural app/ subfolder (sibling to worker/; the folder name is structural, not the app identity) — generated via the Fiori tools MCP generate_fiori_app_odata. It runs on a MOCK OData V4 service: entity ChangeApproval whose fields I grounded in the predecessor's real approvals contract (docs/predecessor-flow.md), with Status carrying a distinct FAILED state per ARN-002; audit fields (RequestedBy/ApprovedBy/DecidedOn) and StatusCriticality are inferred and flagged for reconciliation. Curated UI.LineItem/HeaderInfo/SelectionFields/FieldGroup+Facets; 4 seeded mock rows. Dev/mock server pinned to port 8082 (8080 is a local app on the dev host). The Fiori generator recognizes the app at the root (list_functionality returns the modify catalog).
  • Why: to stand up the launchpad UI layer (ARN-007) now and make it iterable with the Fiori generator without waiting on the gated on-stack RAP service — the proven label-poc mock-first pattern. The live predecessor (arena-plm on CF, verified up: /api/health 200, v0.0.1) is the base of record for the domain/field shape.
  • Affected: app/ (new app files: webapp/, ui5*.yaml, package.json, tsconfig.json); worker/ untouched; root .gitignore covers app/. No PRD requirement completed — this is interim mock UI.
  • Decision: the mock OData service (com.minicircuits.arenaapproval / zarena_change_approval) is a stand-in; the real binding is the RAP approval-BO service (V-2), and the mock entity is the reconciliation target once that service exists. App id follows the estate com.minicircuits.* convention; the app lives in the structural app/ subfolder (sibling to worker/) — the folder name is structural, not the app identity.

2026-09-10 — Build wave 1 closed: worker scaffold accepted against the contract

  • What changed: I accepted the connectivity-worker scaffold in worker/ after two correction rounds at the contract seam: scope made required and the request's objects selector honored; all 400/401/404 bodies moved to RFC 9457 application/problem+json; the wire SyncRun aligned to the amended contract (execution-ordered objects progress array, no objectOrder); and unknown request properties strictly rejected (Ajv removeAdditional: false) rather than silently stripped. Final state verified by my own run: build, lint, and 37 tests green. Stack: Fastify 5.12, TS ~5.9 (pinned — see the KNOWLEDGE.md toolchain entries), Vitest 4, Node 24.
  • Why: API-first (ARN-009) is only real if the implementation is held to the contract at review — and silent stripping of unknown properties is the same quiet-divergence failure class the rest of this package's enforcement exists to prevent.
  • Affected: worker/ (accepted), docs/api/worker.openapi.json (final v0.1.0), PRD status.
  • Decision: next worker wave is the live Arena client POC (session, delta via the outbound-integration queue per the V-3 findings); the S/4HANA executor leg stays stubbed until V-2 defines the approval-BO service binding.

2026-09-10 — Predecessor flow extracted; new tombstones harvested; ARN-010 adopted

  • What changed: I extracted the predecessor's real end-to-end mechanism into docs/predecessor-flow.md (with file:line cites): it is an operator-driven staging workbench — the webhook never syncs (a literal TODO), there is no scheduler, BOM/document writes are non-idempotent, REJECTED conflates human rejection with SAP failure, and the approved preview is discarded at execution time. I harvested the durable behavioral findings into KNOWLEDGE.md (BOM EngineeringChangeDocForEdit / HeaderChangeDocument, IsActiveForChangeNumber silent-discard, ProductDescription full-key PATCH, ProcurementType+MRPType coupling, Arena WORKING-revision overlay, /items/{guid}/changes 404, no server-side date filter on /changes, outbound-integration queue as the clean cursor, plus three landmines). I adopted ARN-010 (the approved payload is the executed payload) and sharpened ARN-002 (execution failure is a distinct state), ARN-006 (existence checks), and V-3 (cursor mechanism findings).
  • Why: the rebuild must be designed from verified behavior, not assumption — and the extraction proved the approval workflow's authority was decorative in the predecessor, which is exactly the class of defect the RAP BO design must preclude structurally.
  • Affected: docs/predecessor-flow.md (new), KNOWLEDGE.md, PRD.md (ARN-002, ARN-006, ARN-010, V-3), CLAUDE.md (files map).
  • Decision: executor, poller, and approval-domain design work cites docs/predecessor-flow.md sections, not memories of the old code.

2026-09-10 — Worker API contract v0.1.0 accepted; sap-api CLI adopted; V-1 partially verified

  • What changed: I accepted docs/api/worker.openapi.json v0.1.0 after running an SAP API style review against the bundled style-guide references and applying two corrections (SAP lifecycle metadata x-sap-shortText + x-sap-stateInfo: beta; a documented 400 on POST /admin/sync-runs). I adopted the sap-api CLI on this box for live tenant/Arena reads, EDMX fetch, and OpenAPI generation (recorded in CLAUDE.md). Using it, I partially verified V-1: my business user AZAW holds 172 roles but no developer-extensibility role, and no such role exists in the tenant catalog to assign — one must first be created from the SAP_BR_DEVELOPER template [source: sap-docs /fiori-tools-samples/misc/s4hana/README + sap-help loio e3527dfa1c5a41f69d4e63691f174f0a, verified 2026-09-10].
  • Why: API-first (ARN-009) needs a governed, style-conformant contract before the worker's surface hardens, and V-1 is the gate for the entire on-stack track — every fact I can verify from this box now shortens the remaining manual check.
  • Affected: docs/api/worker.openapi.json, CLAUDE.md, PRD.md (V-1, status).
  • Decision: read commands of sap-api are part of my design/acceptance toolkit; mutating commands are delegated like any other write.

2026-09-10 — API-first adopted (ARN-009); build wave 1 dispatched

  • What changed: I adopted the API-first rule — every interface this package owns gets an OpenAPI 3.1 JSON contract under docs/api/ before or with the change (CLAUDE.md rule 7, PRD ARN-009). I designed the worker's inbound surface (Arena webhook intake, health, sync-run admin; bearer placeholder pending OQ-6) and dispatched build wave 1 as two parallel items: the contract formalization and the TypeScript worker scaffold under worker/ (Arena session core per KNOWLEDGE.md, HTTP surface, delta-poller skeleton, sync-executor stub — no SAP write code).
  • Why: contracts must govern implementation from the first line of code, and the worker track is the only unblocked track while V-1 is unverified.
  • Affected: CLAUDE.md (rule 7), PRD.md (ARN-009, interface contracts, status), docs/api/ (new), worker/ (new, in progress).
  • Decision: the on-stack RAP/Fiori track stays gated on V-1; nothing SAP-write-shaped lands in the worker until the approval BO contract exists (V-2).

2026-09-10 — CLAUDE.md brought up to date with the repo it maps

  • What changed: I extended CLAUDE.md with what a fresh session needs but could not previously see from it: the five-specialist delegation table (with pointer to docs/agent-roster.md), an explicit dated repo-state note (governance-only, no build/lint/test commands exist yet), the consult-gate exemptions and remedy appended to rule 6, and Files-table rows for docs/agent-roster.md and .claude/hooks/.
  • Why: CLAUDE.md is the map, and it lagged the 2026-09-04 agent-roster and enforcement-kit additions; a fresh session would also hunt for build tooling that does not exist yet.
  • Affected: CLAUDE.md, CHANGELOG.md. Rule numbering unchanged, so the rule-6 references in ADR-003 and the hooks stay valid.
  • Decision: when the first implementation code lands, its commands are recorded in CLAUDE.md in the same turn — the repo-state section says so.

2026-09-04 — Removed foreign sap-odata scaffold bundle; landmine recorded

  • What changed: I removed a bundle that appeared in this repo at 14:40 without my involvement — .github/agents/ + .github/skills/ (the retired, fabricating sap-odata agent trio in GitHub-Copilot layout), a root AGENTS.md routing to those agents, and .vscode/mcp.json pointing at a Windows-only MCP binary that cannot run on this host. I recorded a KNOWLEDGE.md landmine describing the bundle and its likely source (the harieprasad.sap-odata-mcp VS Code extension scaffolding on folder open).
  • Why: the root AGENTS.md would have been read as project instructions, routing sessions to agents whose backing tools do not exist — the exact fabrication failure this package's enforcement layer was built to prevent, reintroduced silently on day one.
  • Affected: .github/ (deleted), AGENTS.md (deleted), .vscode/mcp.json (deleted), KNOWLEDGE.md (landmine added). Nothing was committed before or after; the repo's tracked-content plan is unchanged.
  • Decision: the falsification test stands — if the bundle reappears on the next VS Code open, the extension is confirmed as the writer and gets uninstalled.

2026-09-04 — Specialist agent roster designed from verified research

  • What changed: I ran a capped 4-agent research workflow (3 low-cost researchers over GitHub / SAP Community / web, 1 adversarial verifier that re-fetched every source: 37 findings → 22 confirmed, 14 downgraded or refuted and discarded) and compiled the founding kit's dedicated-agent layer: five specialists (rap-developer, fiori-developer, worker-developer, sap-code-reviewer read-only, test-engineer on the low-cost model) with tool restrictions as the role contract. Design and citations in docs/agent-roster.md; file creation delegated to .claude/agents/.
  • Why: the last founding-kit gap was specialized, grounded agents; every adopted pattern (restriction-as-enforcement, per-artifact MCP routing, model-per-role, false-positive filtering) traces to a verified source, and refuted sources are recorded so they are never re-researched.
  • Affected: docs/agent-roster.md (new), .claude/agents/ (5 files, delegated), PRD status.
  • Decision: ADT MCP server adoption is recommended but gated on V-1 — evaluate SAP's official ABAP MCP path first, ARC-1 / yzonur/sap-adt-mcp as fallbacks; nothing installed until dev-tenant access is confirmed.

2026-09-04 — ADR-003 corrected: tool preloading already exists and is active

  • What changed: I amended ADR-003's tool-loading section. Reading the 2026-09-03 performance-lag session transcript showed ENABLE_TOOL_SEARCH=false is the preload lever (binary-verified there), that it only works before bootstrap (settings.json env is too late), and that it is already active machine-wide via the claude() wrapper in ~/.bashrc — so sessions in this repo start with all tools loaded. My earlier "no setting exists" claim was wrong in practice; the SessionStart load-first order stays as fallback for launch paths that bypass the wrapper.
  • Why: the requirement "tools loaded automatically on session start" is satisfied by existing machine config, and the record must say so accurately.
  • Affected: docs/adr/ADR-003 (amended in place, correction dated).
  • Decision: rely on the wrapper for preloading; keep the hook fallback.

2026-09-04 — Ground-truth enforcement kit installed (ADR-003)

  • What changed: I added project hooks that make MCP-first grounding structural: a SessionStart grounding charter, a per-prompt SAP-REFLEX injection, a consultation gate that denies edits to SAP artifacts unless an mcp__*/WebSearch/WebFetch consultation happened within 30 minutes, and a citation duty (CLAUDE.md rule 6) with a reminder hook on governance-doc edits. This kit becomes part of the founding kit for every future package.
  • Why: the old estate proved advisory routing fails — the MCP servers and skills were never consulted regardless of stack. Enforcement had to move from prose to hooks. I verified against the Claude Code settings schema that no preload setting exists for deferred tools; the slim loadout plus the SessionStart load-first order is the working equivalent.
  • Affected: .claude/settings.json, .claude/hooks/ (3 scripts), .gitignore, CLAUDE.md (rule 6), docs/adr/ADR-003 (new).
  • Decision: consultation is a precondition enforced by a deny gate, not a guideline; uncited SAP claims are hypotheses.

2026-09-04 — Redesigned on-stack: RAP + Fiori in the tenant (ADR-002)

  • What changed: I moved the target architecture into the S/4HANA tenant — approval domain as a custom RAP business object, Fiori Elements app in the tenant launchpad, IAM app/business catalog/business roles as the only access control, custom CDS views for discoverability. Side-by-side shrinks to one connectivity worker for Arena (webhook, polling, session, files, and initially the sync executor). CAP exits the architecture; the MCP loadout moved to sap-docs / abap-docs / sap-released-objects / fiori / ui5. PRD rewritten (ARN-007/008 added, OQ-1..4 resolved, V-1..V-3 verification gates added); ADR-001 amended.
  • Why: the decisive test came from the business side — the showcased apps were invisible from inside S/4HANA (not in the launchpad, not in Custom CDS Views), reachable only through standalone URLs with weak control. A side-by-side CAP app would fail the same test. I verified the on-stack path (developer extensibility: RAP + Fiori deploy + IAM; key-user tier as fallback) against SAP documentation via the MCP servers before deciding.
  • Affected: PRD.md, CLAUDE.md, docs/adr/ADR-001 (amended), docs/adr/ADR-002 (new), .mcp.json (loadout).
  • Decision: on-stack first — the tenant hosts the application; BTP hosts only what the tenant cannot run. The launchpad is the only front door.

2026-09-04 — Package founded; knowledge bankruptcy declared

  • What changed: I created this standalone package home under ~/projects/sap-integrations-mcl/, decoupled from the old multi-package estate. I carried over only dated tombstones and landmines (KNOWLEDGE.md) and the proven interface contracts (PRD.md); all other predecessor knowledge is deliberately left behind, to be re-derived from code and live systems as needed.
  • Why: the single-estate setup had grown past what one working context can maintain, and its accumulated undated knowledge had begun to rot. The Express implementation also sat outside SAP's toolchain, so none of the SAP guidance tooling ever engaged — a signal that the stack, not the tooling, was wrong.
  • Affected: this package only. The predecessor at ~/projects/sap-apps/arena-plm is now reference-only.
  • Decision: I chose a CAP-first rebuild over transplanting the Express app (ADR-001), with a deliberately slim tool loadout (three MCP servers, seven skills) matched to that stack.