Skip to content

release: v1.40.2 (DEV→main promotion) - #2853

Merged
jung-thomas merged 22 commits into
mainfrom
release/v1.40.2
Oct 19, 2026
Merged

jung-thomas merged 22 commits into
mainfrom
release/v1.40.2

Conversation

@jung-thomas

Copy link
Copy Markdown
Contributor

Release 1.40.2 — DEV → main promotion

Patch release promoting the fixes and docs merged to DEV since 1.40.1 to main for a PROD deploy.

Version bumps

MTA File Change
Main (tutorials-ims) .deploy/mta.yaml 1.40.1 → 1.40.2
MCP (tutorials-mcp) mta-mcp.yaml 1.0.1 → 1.0.2

Changes in this window (10 PRs since 1.40.1)

No user-facing features — all fixes, reliability hardening, and author/ops docs. Patch bump per convention.

What's New digest

hugo/data/whats_new.json refreshed with the 10 PRs since 1.40.1 (849 entries total).

Deploy status

Main tutorials-ims already deployed + smoke-verified on DEV via deploy-watcher (mtar 1.40.1-equivalent, 342 smoke tests passed, from the same origin/DEV HEAD 0ad36d50). This PR promotes to main for the PROD deploy.

🤖 Generated with Claude Code

jung-thomas and others added 22 commits October 18, 2026 17:50
The #2552 global identity-pin `before('*')` hook (srv/server.js) was
registered on EVERY ApplicationService, including the internal CronService.
On a scheduled tick the hook calls `pinResolvedUser(req.user, cds.tx(req))`,
and `cds.tx(req)` dereferences `ctx.context._set` on the cron event's
context — which is not a real EventContext — throwing
`ctx.context._set is not a function` on EVERY tick.

The throw is caught fail-open (WARN), so jobs still run, but:
- it spams the PROD log on every scheduled tick, and
- after an instance restart (e.g. a blue-green swap) resets the canary
  clocks, the noise coincides with the scheduler-stall canary (#2782)
  firing a false ALERT.

The pin is a pure no-op on a cron tick anyway — a scheduled tick's user is
always system/anonymous. Skip CronService by its fully-qualified name
(com.sap.developers.ims.CronService) in the hook-registration loop.

Regression first observed on PROD after the 1.40.1 blue-green swap; the
hook + the throwing `cds.tx(req)` form both shipped in 1.40.0
(a3412e0 / 60c6a5b).

Test: extend test/hybrid/cron-service-schedule.test.js to assert the
identity-pin before(*) handler is NOT registered on CronService. Runs in
the post-deploy hybrid CI job (needs a HANA bind profile; not runnable in a
fresh worktree without `npm run bind:setup`).

Follow-up (separate issue): the same #2552 hook also throws
`Cannot set property userId of #<XsuaaToken> which has only a getter` on
every authenticated request in PROD — a distinct bug in pinResolvedUser's
write to the read-only XsuaaToken getter, not addressed here.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ser (#2552)

Second #2552 regression, surfaced in PROD logs during the 1.40.1 scheduler
diagnosis: on EVERY authenticated request, the identity-pin hook threw
`Cannot set property userId of #<XsuaaToken> which has only a getter`.

Root cause: pinResolvedUser pinned the resolved sapId by assigning
`user.authInfo.token.userId = row.sapId`. In PROD the real @sap/xssec
XsuaaToken exposes `userId` as a GETTER-ONLY property, so the bare
assignment throws. Caught fail-open (WARN), but it fired on every authed
request and the pin silently never cached anything on the XSUAA path.

Fix: cache the resolved sapId on `user.attr.sapId` (always a plain writable
object) as the source of truth, and only mirror onto
`authInfo.token.userId` when that slot is actually writable (checked via
getOwnPropertyDescriptor, wrapped defensively). The idempotency short-circuit
now reads `user.attr.sapId` first, falling back to the token for older pins.
The dev/basic-auth path (writable token) still mirrors userId as before.

Test: 4 new cases in test/unit/resolve-db-user-resolve.test.js exercising a
getter-only token (reproducing the XsuaaToken), asserting no throw, sapId
cached on attr, idempotent re-call, and the writable-token mirror path.
All 34 tests in the file pass (`vitest run`).

Paired with the CronService guard in this PR — both are #2552 before('*')
identity-pin regressions from 1.40.0.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…tity-pin

fix(identity): two #2552 before(*) pin regressions — CronService stall + XsuaaToken getter
The Joule/Sapphire App Space hero gradients are dark in both light and
dark mode, but the base .hero only inherited --sapShell_TextColor, which
resolves to a dark value under the Horizon light theme. That left the
banner text near-illegible on the purple gradient
(/app-space/?theme=joule in light mode, reported by DJ Adams).

Pin the themed hero (and its loading skeleton) to white regardless of the
active Horizon palette. Verified via vite dev harness: hero text is
rgb(255,255,255) with the fix and rgb(34,53,72) without, in light+joule;
dark mode unchanged.
…ero-contrast

fix(#2839): white hero text for themed App Space banners
convertOptionBlocks spliced OPTION shortcodes flush-left, which closed the
surrounding numbered list. Figures inside an os-panel — or trailing an OPTION
group in the same substep — then rendered as a top-level <figure> sibling of
the list, losing their indentation under the substep (the 'centered vs
left-aligned image' QA report).

PR #2822 only adjusted figure text-align (CSS), which cannot re-nest a DOM
sibling, so the figures stayed un-indented.

Approach A: indent the shortcode WRAPPER lines to the substep so the block
stays inside the <li> (list never closes), while the panel BODY stays at
column 0 so os-panel.html's markdownify pass parses code fences/images as
markdown (preserves the #2703 behaviour). The old flush-left tail-dedent is
removed — with the list open, trailing content keeps its substep indent.

Verified through real Hugo renders (incl. the live Tutorials-Contribution
hana-clients-install source): figures nest as li > ol > figure; #2703 code
fences unaffected. New render-level regression test added.
Disable the three hidden scavenger-hunt clues (homepage, /ai/, /api-docs/)
by commenting out their render entry points in baseof.html and the
api-docs shortcode call. The feature's data/layouts/CSS are kept dormant
so it can be re-enabled next Devtoberfest by uncommenting.

No backend/CDS/seed changes; pure Hugo frontend.
…-clues

fix(#2841): remove the 3 hidden Devtoberfest scavenger hunt clues
…escape-2820

fix(options): keep OPTION-block figures nested in the list item (#2820)
Basic setup to connect the existing tutorials-aicore instance to the
tutorials-hana container for DB-native VECTOR_EMBEDDING (issue #2810),
ahead of any rewrite.

- db/src/_grants.hdbgrants: grant CREATE PSE to the container user via
  the existing tutorials-kg-grantor UPS. Capability probe confirmed the
  _RT user already holds CREATE REMOTE SOURCE; CREATE PSE was the only
  missing privilege for the sapgenaihub remote source.
- docs/developers/operations/hana-aicore-embeddings.md: setup runbook
  (built-in NLP tier A, AI Core remote-source tier B, PSE+remote source
  SQL with DEV worked values, PROD checklist, auto-embedding appendix).
  PSE paste step described in prose (no literal PEM markers) to avoid a
  gitleaks private-key false positive.
- docs/superpowers/specs: design doc with verified DEV facts.
- CLAUDE.md: link the runbook in the deep-dive list.

Tier A (built-in SAP_GXY.20250407) verified on DEV: 768-dim vector.
Tier B deploy-gated on the CREATE PSE grant landing via db-deployer.
…edding-setup

docs(#2810): HANA-native AI Core embedding setup + grant CREATE PSE
…grants

The first attempt added CREATE PSE to _grants.hdbgrants under the
tutorials-kg-grantor SQL grantor. That failed on DEV deploy
(20261019-105602): the deployer emitted GRANT "CREATE PSE" TO ...#OO,
which HANA rejects as 'invalid role name' — a system privilege cannot be
granted that way, and the grantor lacks CREATE PSE WITH ADMIN OPTION.

Correct HDI-native mechanism (per the @sap/hdi-deploy README): a role at
the exact path src/defaults/default_access_role.hdbrole named
default_access_role is auto-granted by the container object owner to the
service instance's global access role on deploy — so a system privilege
listed in it is granted by #OO with no external grantor.

- db/src/defaults/default_access_role.hdbrole: new; system_privileges
  [CREATE PSE]. Path + name are the trigger for the deployer special case.
- db/src/_grants.hdbgrants: reverted to SPARQL-only (remove CREATE PSE).
- runbook: B1 rewritten to the default_access_role mechanism + the failed
  hdbgrants attempt recorded.

No .hdinamespace needed (db/src defines no real namespace prefix);
db/src/.hdiconfig already maps .hdbrole.
…-role

fix(#2810): grant CREATE PSE via default_access_role.hdbrole
Second DEV deploy (20261019-115443) failed:
  com.sap.hana.di.role: "CREATE PSE": invalid system privilege

CREATE PSE is the SQL STATEMENT, not a system-privilege name. The
privilege that authorizes CREATE PSE is TRUST ADMIN; ALTER PSE ... SET
OWN CERTIFICATE needs CERTIFICATE ADMIN. The default_access_role
mechanism itself was correct (the artifact deployed and reached the
grant) — only the privilege names were wrong.

- default_access_role.hdbrole: system_privileges now
  [TRUST ADMIN, CERTIFICATE ADMIN].
- runbook: B1 corrected; both failed attempts recorded; verify query and
  tier table updated.
fix(#2810): PSE privileges are TRUST ADMIN + CERTIFICATE ADMIN, not CREATE PSE
…iner grant

Remove db/src/defaults/default_access_role.hdbrole entirely. The PSE and
remote source are one-time, database-level admin objects — shared across
containers/apps — not HDI container artifacts. Baking TRUST ADMIN into
default_access_role would over-privilege every app binding user
permanently for a one-time setup, and the container #OO can't delegate
PKI system privileges anyway (confirmed: #OO not allowed to grant
CERTIFICATE ADMIN, DEV 20261019-125352).

This also unblocks DEV deploys, which were failing every db-deployer run
on the TRUST ADMIN grant since #2846/#2847.

Correct split (runbook rewritten):
- B1: a HANA admin creates PSE + remote source once (needs TRUST ADMIN +
  CREATE REMOTE SOURCE). CERTIFICATE ADMIN is managed-PSE-only, not needed.
- B2: container gets only GRANT EXECUTE ON REMOTE SOURCE TUTORIALS_AICORE.
- B3: VECTOR_EMBEDDING proof, unchanged.
- All three failed container-grant attempts recorded in a details block.

default_access_role.hdbrole remains the right mechanism for privileges
the container user should own long-term — just not for this.
…ntainer

fix(#2810): PSE setup is instance-level admin, not a container grant
The container EXECUTE grant on the AI Core remote source belongs on the
broker-created <schema>::external_privileges_role (SAP HDI's documented
path for external-object access), NOT a specific _RT user and NOT
default_access_role.hdbrole:
- each CF binding mints a new _RT user, so a per-user grant breaks on
  rebind (and fails outright if the binding is gone: 'invalid user name');
- the role is auto-assigned to every binding user and persists for the
  life of the container;
- default_access_role.hdbrole would REVOKE the container's default
  run-time-schema permissions as a side effect, and #OO can't grant
  EXECUTE on a remote source it doesn't own.

Verified on DEV + PROD (2026-10-19): a container _RT user inheriting only
::external_privileges_role returned a 1536-dim text-embedding-3-small
vector via TUTORIALS_AICORE. PROD section marked DONE.
…eges-role

docs(#2810): B2 grant via external_privileges_role; DEV+PROD live
The HANA AI Core embeddings runbook was added to
docs/developers/operations/ without a matching sidebar entry, so
check-docs-sidebar.cjs failed every 'Deploy Docs to GitHub Pages'
build. Add the alphabetical Operations entry.
…a-aicore

fix(#2810): register hana-aicore-embeddings in docs sidebar
@jung-thomas
jung-thomas merged commit 79e59da into main Oct 19, 2026
6 checks passed
@jung-thomas
jung-thomas deleted the release/v1.40.2 branch October 19, 2026 22:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant