{
  "version": "1.0",
  "cdsVersion": "10",
  "generationDate": "2026-07-01",
  "entryCount": 34,
  "entries": [
    {
      "id": "annotate-invalid-target-is-error",
      "title": "Annotations w/o Targets",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "cdl"
      ],
      "group": "cdl-annotations",
      "guidance": "The compiler emits an error only when a security-related annotation target cannot be resolved; all other invalid-target annotate statements remain warnings. Run `cds compile *` and look for errors of the form \"Artifact has not been found\" or \"Element has not been found\".\n",
      "compilerDetects": true,
      "patternsComplete": true,
      "body": "Annotations with invalid targets are in general reported as warnings by cds compiler. However, in case of the security-related annotations, including `@restrict`, `@requires`, and `@ams.*`, this is not just a harmless issue, but may cause unauthorized access to be granted silently, for example:\n\n<!-- cds-mode: ignore -->\n```cds\nannotate AdmnService with @requires:'admin';\nannotate AdmnService.Books with @restrict: [...];\nannotate Books:ttle with @ams.attributes: {...};\n```\n\nTo avoid that such issues are overlooked, we fixed the compiler to report such cases as errors instead of warnings.\n\n**Check whether you are affected** by this change, for example, by running this in your project root, to provoke errors as shown below, if any:\n\n```sh\ncds compile \\*\n```\n```js\n[ERROR] Artifact “AdmnService” has not been found (in annotate:“AdmnService”)\n[ERROR] Artifact “AdmnService.Books” has not been found (in annotate:“AdmnService.Books”)\n[ERROR] Element “ttle” has not been found (in annotate:Books/element:“ttle”)\n```\n\nIf you encounter such errors, **you must fix these** by providing valid targets, or by removing the annotations in case they are no longer needed.",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#cds-security-annotations",
      "capireSection": "CDS – Improved Checks",
      "compilerPattern": [
        "ext-undefined-.*-sec"
      ]
    },
    {
      "id": "async-handler-compat-removed",
      "title": "Removed `async_handler_compat`",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "api",
        "config"
      ],
      "group": "event-handlers",
      "patternCdsEnv": [
        "cds\\.features\\.async_handler_compat"
      ],
      "guidance": "For patternAst matches: the YAML rule filters out async function expressions — only plain `function` (without `async`) is flagged. Note: arrow functions without `async` are equally affected by the removal but are not matched by this pattern — they require manual review. For patternCdsEnv matches: the flag's presence means the project opted in to compat behavior that is now gone — any match is a genuine finding regardless of provenance.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "- we removed the legacy compat flag `cds.features.async_handler_compat` completely.\n\n#### Are you affected?\n- check if flag `cds.features.async_handler_compat=true` is set in any of cds config files (package.json, cdsrc.json, cdsrc.yml, cdsrc.js)\n\n#### How to address?\n- You have to adapt your implementation.\n- do not depend on order of handler execution in before phase\n- ensure that the custom handlers cannot be influenced through asynchronous processing",
      "capireSection": "Changes to Runtime"
    },
    {
      "id": "auth-info-http-req-removed",
      "title": "API cds.context.http.req.authInfo",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "api"
      ],
      "group": "auth-context",
      "patternSource": "req\\.authInfo",
      "guidance": "Matches any `req.authInfo` in JS files. Breaking unconditionally when on the CAP `cds.context.http.req` path. Plain Express `req.authInfo` set by Passport or xssec is a FP — those are not affected by this removal.\n",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "- the undocumented API is now removed, but there is a successor.\n\n#### Are you affected?\n- check if `req.authInfo` occurs in js files\n\n#### How to address?\n- instead of `cds.context.http.req.authInfo` use `cds.context.user.authInfo`\n- inside a custom handler: instead of use `req.http.req.authInfo` use `req.user.authInfo`\n- also see [Aug 25](https://cap.cloud.sap/docs/releases/2025/aug25#cds-user-authinfo)",
      "capireSection": "Changes to Runtime"
    },
    {
      "id": "bulk-inserts-via-rest-introduced",
      "title": "Fixed Bulk Inserts via REST",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "config"
      ],
      "compatFlag": "features.bulk_inserts_via_rest: false",
      "group": "rest-adapter",
      "patternCdsEnv": [
        "cds\\.features\\.bulk_inserts_via_rest"
      ],
      "guidance": "For patternCdsEnv matches: if the value is explicitly `false`, the project uses the kill switch (restores old behavior) — not affected. If the key is absent, the new default applies and the project may be affected. Detection of affected handler code is hard from patterns alone — the agent should scan REST service handlers (`srv.before('CREATE', ...)`, `srv.on('CREATE', ...)`) for logic that expects `req.data` to be a single object or `req.query.INSERT.entries` to contain only one entry.\n",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "CAP services generally support bulk inserts of multiple entries like so:\n\n```js\nawait srv.create(Books).entries(\n  { title: 'Book 1', stock: 10 },\n  { title: 'Book 2', stock: 20 },\n  { title: 'Book 3', stock: 30 }\n)\n```\n\nAnd the same can be done via REST as well, for example, like that:\n\n```http\nPOST /Books\nContent-Type: application/json\n\n[\n  { \"title\": \"Book 1\", \"stock\": 10 },\n  { \"title\": \"Book 2\", \"stock\": 20 },\n  { \"title\": \"Book 3\", \"stock\": 30 }\n]\n```\n\nYet the REST adapter did not support this properly before, but silently converted such bulk creates into multiple single creates, which caused that custom handlers for CREATE requests did not receive the complete set of entries, and hence had no chance to optimize processing, for example, simply delegating the bulk insert to the database service. This has been fixed with cds10.\n\n#### Are you affected?\n\nYou are only affected by this change if all of the below conditions are true:\n\n- You have a service exposed via REST\n- Your clients send bulk create requests to these services\n- You handle these requests with custom handlers, and ...\n- you expect the former behavior of `req.data` being a single object, or\n- you expect only one entry in `req.query.INSERT.entries` within these handlers.\n\n#### How to address?\n\nMake the custom handlers aware of the bulk inserts, for example, by delegating the bulk insert to the database service, like that:\n\n```js\nthis.on ('CREATE', Books, req => INSERT.into(Books).entries(req.data))\n```\n\n\n\n#### Kill Switch\n\nAs a last resort, you can restore the former behavior with the following config option:\n\n| `cds.features.`...                                                   | -> restores:                  |\n|----------------------------------------------------------------------|-------------------------------|\n| <Config section=\"cds.features\">bulk_inserts_via_rest: false</Config> | the erroneous former behavior |\n\n> [!warning]\n> As such kill switches restore unintended, and erroneous behavior, they should only be used as a temporary measure. It's recommended to update your code to be compatible with the new behavior. The kill switches will be removed in a future release, and relying on them for longer time may cause maintenance issues and technical debt.",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#fixed-bulk-inserts-via-rest",
      "capireSection": "Changes to Runtime",
      "defaultValue": "true"
    },
    {
      "id": "common-side-effects-type-effects-type-removed",
      "title": "CDS Vocabulary change for Common.SideEffectsType",
      "runtime": "both",
      "scope": [
        "cdl"
      ],
      "group": "cdl-annotations",
      "patternCdl": [
        "EffectsType"
      ],
      "guidance": "Pattern matches any occurrence of the string `EffectsType` in CDL files. This is a narrow identifier name with low FP risk — confirm the match is inside a `@Common.SideEffects` annotation context. Matches outside of OData vocabulary annotations are FPs.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "cds-compiler v7 contains an update of the OData vocabulary `Common`, where\nthe complex type `Common.SideEffectsType` was changed incompatibly:\nthe property `EffectsType` was removed. This property was already marked as deprecated,\nand no client makes use of it.\n\nIf you use this property in a `@Common.SideEffects` annotation, the compiler still renders\nit to the OData Edmx, but due to (now) lacking vocabulary information with a wrong type.\nAs clients don't use this property, this has no negative impact.\n\n#### Are you affected?\n\nWith cds-compiler v7, there is a compiler warning:\n```txt\nWarning[odata-anno-type]: “EffectTypes” is not a known property for “@Common.SideEffects” of type “Common.SideEffectsType”\n```\n\nNo negative impact on your project is expected.\n\n#### How to address?\n\n(optional) For the sake of clean models, we recommend to remove the unnecessary property\n`EffectsType` from your `@Common.SideEffects` annotations in your CDS models.\n\n```cds\n @Common.SideEffects: {\n  // ...\n  EffectTypes : #ValueChange,  // <-- obsolete, remove it\n  // ...\n}\n```",
      "capireSection": "Changes to Runtime"
    },
    {
      "id": "compat-assert-not-null-removed",
      "title": "compat_assert_not_null compat flag removed",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "api",
        "config"
      ],
      "group": "compat-flag-removals",
      "compatFlag": "compat_assert_not_null",
      "patternCdsEnv": [
        "cds\\.features\\.compat_assert_not_null"
      ],
      "guidance": "For patternCdsEnv matches: the compat flag is an explicit project opt-in, not a framework default — any match is a genuine finding.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "The following flags already had the new fixed behavior as default in cds 9, but you were still able to revert it to the former erroneous behavior.\nIn cds 10, these flags are removed entirely, and hence ignored if set in your project.\n\n| Removed Flag                                                                   | Fixed behavior                                 | Was   | Since                                                   |\n|--------------------------------------------------------------------------------|------------------------------------------------|-------|---------------------------------------------------------|\n| <Config section=\"cds.features\" value=\"false\"> consistent_params </Config>      | Unclear `req.params` -> now always an array    | true  | [May 25](https://cap.cloud.sap/docs/releases/2025/may25#changed-structure-of-req-params) |\n| <Config section=\"cds.features\" value=\"false\"> compat_save_drafts </Config>     | Draft `SAVE` handlers called on `PATCH` events | false | [Sep 25](https://cap.cloud.sap/docs/releases/2025/sep25#revised-fiori-support)           |\n| <Config section=\"cds.features\" value=\"false\"> compat_assert_not_null </Config> | `ASSERT_MANDATORY` instead of `_NOT_NULL`      | false | [Sep 25](https://cap.cloud.sap/docs/releases/2025/sep25#translated-error-messages)       |\n\n> [!caution] If you still use any of these in your project you must fix your code now!\n> These flags were kill switches for the grace periods of 1-2 years, and they will not work anymore with cds10. Follow the instructions in the linked former migration guide sections to fix your code.",
      "capireSection": "Flags Entirely Removed",
      "defaultValue": "false"
    },
    {
      "id": "compat-clone-appends",
      "title": "Fixed `cds.ql.clone()`",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "api"
      ],
      "compatFlag": "features.compat_clone_appends",
      "group": "query-api",
      "patternSource": "ql\\.clone",
      "patternCdsEnv": [
        "cds\\.features\\.compat_clone_appends"
      ],
      "guidance": "Only breaking if the cloned query is subsequently modified via .columns(), .orderBy(), or .groupBy() AND the code relied on these calls REPLACING the existing clause content rather than appending to it. .where() always appended even in CDS 9, so it is not affected. If the code only uses .where() after clone, this is not breaking. For patternCdsEnv matches: only report if the provenance grep finds it in a project config file, not as a framework default.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "We fixed a bug in the implementation of [`cds.ql.clone()`](https://cap.cloud.sap/docs/node.js/cds-ql.md#cds-ql-clone) which caused that Fluent API methods `.columns()`, `.orderBy()`, or `.groupBy()` did not append to existing clauses, as intended, but replaced instead.\n\nFollowing shows the erroneous behavior (in red), and the fixed one (in green):\n\n```js\nlet q1 = SELECT`a,b`.from`Foo`.where`x>1`.orderBy`a`\nlet q2 = cds.ql.clone(q1)\n```\n```js\nq1.columns`c`.where`y<2`.orderBy`b`\nq2.columns`c`.where`y<2`.orderBy`b`\n```\n```sql\nq1 ⇒ SELECT a, b, c from Foo where x>1 and y<2 order by a, b\nq2 ⇒ SELECT a, b, c from Foo where x>1 and y<2 order by a, b -- [!code ++] fixed\nq2 ⇒ SELECT       c from Foo where x>1 and y<2 order by    b -- [!code --] wrong\n```\n\n\n\n#### Are you affected?\n\nLikelihood that you are affected is low, as `cds.ql.clone()` was rolled out in [January 26, 2026](https://cap.cloud.sap/docs/releases/2026/jan26#new-cds-ql-clone-method) and this only applies to a specific combination of API usages, which silently yielded wrong outcomes. So, you are only affected, if all three of the below are true:\n\n1. Are you using `cds.ql.clone()` at all?\n    ```sh\n    grep -rnw --exclude=\"*/node_modules/*\" --include=\"*.js\" \"ql.clone\"\n    ```\n\n2. Modified these using fluent API methods `.columns()`, `.orderBy()`, or `.groupBy()`\n    ```sh\n    grep -rnw --exclude=\"*/node_modules/*\" --include=\"*.js\" \".columns\"\n    grep -rnw --exclude=\"*/node_modules/*\" --include=\"*.js\" \".orderBy\"\n    grep -rnw --exclude=\"*/node_modules/*\" --include=\"*.js\" \".groupBy\"\n    ```\n3. And relied on the erroneous behavior that these methods replaced existing clauses instead of appending to them.\n\n\n#### How to address?\n\nIf you are affected, explicitly override the CQN properties instead of using Fluent API if you don't want to append to existing clauses. For example:\n\n```js\nconst { columns, orders } = cds.ql\nlet q1 = SELECT`a,b`.from`Foo`.where`x>1`.orderBy`a`\nlet q2 = cds.ql.clone(q1)\nq2.SELECT.columns = columns`c,d,e`\nq2.SELECT.orderBy = orders`b`\n```\n\n#### Kill Switch\n\nAs a last resort, you can restore the former behavior with the following config option:\n\n| `cds.features.`...                                                 | -> restores:                  |\n|--------------------------------------------------------------------|-------------------------------|\n| <Config section=\"cds.features\">compat_clone_appends: true</Config> | the erroneous former behavior |\n\n> [!warning]\n> As such kill switches restore unintended, and erroneous behavior, they should only be used as a temporary measure. It's recommended to update your code to be compatible with the new behavior. The kill switches will be removed in a future release, and relying on them for longer time may cause maintenance issues and technical debt.",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#fixed-cds-ql-clone",
      "capireSection": "Changes to Runtime",
      "defaultValue": "false"
    },
    {
      "id": "compat-consistent-params-removed",
      "title": "consistent_params compat flag removed — req.params is always array of objects",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "api"
      ],
      "group": "request-api",
      "compatFlag": "consistent_params",
      "patternCdsEnv": [
        "cds\\.features\\.consistent_params"
      ],
      "guidance": "For patternCdsEnv matches: the flag is ignored in cds 10 but its presence indicates the project was relying on the old behavior (reverting to the former structure). The project must fix its code per the linked migration guide sections. Only report if the provenance grep finds it in a project config file.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "The following flags already had the new fixed behavior as default in cds 9, but you were still able to revert it to the former erroneous behavior.\nIn cds 10, these flags are removed entirely, and hence ignored if set in your project.\n\n| Removed Flag                                                                   | Fixed behavior                                 | Was   | Since                                                   |\n|--------------------------------------------------------------------------------|------------------------------------------------|-------|---------------------------------------------------------|\n| <Config section=\"cds.features\" value=\"false\"> consistent_params </Config>      | Unclear `req.params` -> now always an array    | true  | [May 25](https://cap.cloud.sap/docs/releases/2025/may25#changed-structure-of-req-params) |\n| <Config section=\"cds.features\" value=\"false\"> compat_save_drafts </Config>     | Draft `SAVE` handlers called on `PATCH` events | false | [Sep 25](https://cap.cloud.sap/docs/releases/2025/sep25#revised-fiori-support)           |\n| <Config section=\"cds.features\" value=\"false\"> compat_assert_not_null </Config> | `ASSERT_MANDATORY` instead of `_NOT_NULL`      | false | [Sep 25](https://cap.cloud.sap/docs/releases/2025/sep25#translated-error-messages)       |\n\n> [!caution] If you still use any of these in your project you must fix your code now!\n> These flags were kill switches for the grace periods of 1-2 years, and they will not work anymore with cds10. Follow the instructions in the linked former migration guide sections to fix your code.",
      "capireSection": "Flags Entirely Removed",
      "defaultValue": "false"
    },
    {
      "id": "compat-odata-metadata-compat-removed",
      "title": "Removed `odata_metadata_compat`",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "config"
      ],
      "group": "compat-flag-removals",
      "compatFlag": "odata_metadata_compat",
      "patternCdsEnv": [
        "cds\\.features\\.odata_metadata_compat"
      ],
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "- we removed the legacy compat flag `cds.features.odata_metadata_compat` completely.\n\n#### Are you affected?\n- check if flag `cds.features.odata_metadata_compat=true` is set in any of cds config files (package.json, cdsrc.json, cdsrc.yml, cdsrc.js)\n\n#### How to address?\n- You have to adapt your implementation.\n- Check that no handlers are registered for getCsn calls of the ModelProviderService",
      "capireSection": "Changes to Runtime",
      "defaultValue": "false"
    },
    {
      "id": "compat-save-drafts-removed",
      "title": "`compat_save_drafts`",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "config"
      ],
      "group": "compat-flag-removals",
      "compatFlag": "compat_save_drafts",
      "patternCdsEnv": [
        "cds\\.features\\.compat_save_drafts"
      ],
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "- we removed the legacy compat flag `cds.features.compat_save_drafts` completely.\n\n#### Are you affected?\n- check if flag `cds.features.compat_save_drafts=true` is set in any of cds config files (package.json, cdsrc.json, cdsrc.yml, cdsrc.js)\n\n#### How to address?\n- Instead of registering handlers for the `SAVE` event on `<entity>.drafts`, register it on the events `['CREATE', 'UPDATE']`",
      "capireSection": "Flags Entirely Removed",
      "defaultValue": "false"
    },
    {
      "id": "crud-return-values",
      "title": "Fixed Service Results – CRUD return values",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "api"
      ],
      "group": "crud-api",
      "guidance": "Breaking only if the return value is consumed as an entity object — e.g. property access on the result (`result.ID`, `result.status`) or assignment to a typed variable that expects an entity shape. Matches where the return value is discarded or compared as a number are not breaking. Detection of this change requires semantic analysis of return value usage — no simple grep pattern available.\n",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "Before cds10, results of local service calls involving write operations, that is, INSERT, UPDATE and DELETE, were undocumented and inconsistent. In particular:\n\n| Operation | with db services                 | with app services         |\n|-----------|----------------------------------|---------------------------|\n| INSERT    | => insert results                | _=> req.data input_{.red} |\n| UPDATE    | _=> # of affected rows_{.yellow} | _=> req.data input_{.red} |\n| DELETE    | _=> # of affected rows_{.yellow} | _=> req.data input_{.red} |\n\nWith cds10 we fixed and consolidated that, so that ...\n\n- All write operations of app services return the same kind of result: an array with property `affected` indicating the affected rows, for example, like that:\n  ```js\n  let { affected } = await srv.create(Books).entries(...)\n  let { affected } = await srv.update(Books) .where `stock > 111` ...\n  let { affected } = await srv.delete(Books) .where `stock = 0`\n  ```\n\n- Same for db services, with opt-in via <config>cds.features.legacy_db_results: false</config>.\n\n\nIn addition, the change to real _array_ objects, also for `InsertResults` allows us to uniformly use object spread destructuring as well as standard array operations, for example, to retrieve generated primary keys in case of INSERTs, for example:\n\n```js\nlet [ Emily, Charlotte ] = await srv.create(Authors).entries(\n  {name:'Emily Brontee'},\n  {name:'Charlotte Brontee'}\n)\n```\n\nIn addition, that also allows us to support [SQL `returning` clauses](https://sqlite.org/lang_returning.html) in future with INSERT, UPDATE, and DELETE requests.\n\nNo change was made to the results of read operations, that is, SELECTs, which return plain arrays of entries, as before.\n\n\n#### Are you affected?\n\nYou are affected by this change if you have custom code that relies on the former inconsistent and undocumented results of UPDATE and DELETE operations, in particular if you have...\n\n1. Calls to UPDATE or DELETE with app services which do expect `req.data` as result\n2. Custom `after` handlers for the same which do expect `req.data` as first argument\n3. Calls to UPDATE or DELETE with db services which do expect a number as result\n4. Tests which expect an _object_, but not an _array_, as result of INSERTs on db level\n\n#### How to address?\n\nIf you are affected, you should adapt your code to the new consistent results.\n\nFor example, for 1. and 2., you can simply access the input data via `req.data` instead of the result, for example, like that:\n\n```js\nthis.on ('UPDATE', Books, async (req, next) => {\n  let { ID, stock } = await next() // [!code --] returned req.data before\n  await next(); let { ID, stock } = req.data // [!code ++] just access req.data explicitly now\n})\n```\n\nFor 3., you can access the number of affected rows via the `affected` property of the result, for example, like that:\n\n```js\nlet affected = await srv.update(Books) .where `stock > 111` ... // [!code --]\nlet { affected } = await srv.update(Books) .where `stock > 111` ... // [!code ++]\n```\n\nFor 4., you can adapt your tests to expect an array instead of an object, for example, like that:\n\n```js\nexpect(result).to.deep.equal ({ affectedRows:1 }) // [!code --]\nexpect({...result}).to.deep.equal ({ affectedRows:1 }) // [!code ++]\nexpect({...result}).to.deep.equal ({ affected:1 }) // [!code ++]\nexpect(result).to.have.property ('affected',1) // [!code ++]\n```\n\n\n#### Opt-in & Kill Switches\n\nAs a last resort, you can restore the former behavior with the following config options:\n\n| `cds.features.`...                                               | -> restores:                                         |\n|------------------------------------------------------------------|------------------------------------------------------|\n| <Config section=\"cds.features\">legacy_srv_results: true</Config> | the undocumented former behavior                     |\n| <Config section=\"cds.features\">legacy_db_results: true</Config>  | the former behavior, and still the default for cds10 |\n\n> [!warning]\n> As such kill switches restore unintended, and erroneous behavior, they should only be used as a temporary measure. It's recommended to update your code to be compatible with the new behavior. The kill switches will be removed in a future release, and relying on them for longer time may cause maintenance issues and technical debt.",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#fixed-srv-results",
      "capireSection": "Changes to Runtime"
    },
    {
      "id": "decimal-sqlite-type-mapping-changed",
      "title": "Fixed Affinity for Decimals",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "cdl"
      ],
      "compatFlag": "cds.requires.db.decimal_affinity",
      "group": "database-config",
      "guidance": "For patternCdsEnv matches: `decimal_affinity` is not a framework default (absent means the new default REAL applies automatically). Any match is a genuine finding. REAL stores values as 8-byte IEEE 754 float; NUMERIC attempts integer storage when possible — the two affinities differ in precision for non-integer values.\n",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "To avoid such unexpected integer division effects with `Decimal` elements in SQLite, we had to change the type affinity from `NUMERIC` to `REAL`,\nby changing the generated column type from `DECIMAL` to `REAL_DECIMAL` for SQLite:\n\n```cds\nentity E { d: Decimal }\n```\n```sql\nCREATE table E ( d DECIMAL );       -- [!code --] NUMERIC affinity\nCREATE table E ( d REAL_DECIMAL );  -- [!code ++] REAL affinity\n```\n\nWe can demonstrate the effect of the former NUMERIC affinity with the following SQL snippet (you can run that in `sqlite3` CLI):\n\n```sql\nCREATE table T ( a REAL_DECIMAL, b DECIMAL );\nINSERT into T values ( 2.0, 2.0 );\nSELECT 1/a from T;\nSELECT 1/b from T;\n```\n```sql\n0.5 -- correct result with REAL affinity\n0 -- unexpected integer division due to NUMERIC affinity\n```\n\nThis change is not breaking. No changes apply to HANA and PostgreSQL.\nStill, the former behavior can be restored by setting <config>cds.requires.db.decimal_affinity: 'numeric'</config>.",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#decimal-affinity",
      "capireSection": "Changes to Runtime"
    },
    {
      "id": "default-for-struct-is-error",
      "title": "Defaults for Structs",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "cdl"
      ],
      "group": "cdl-syntax",
      "guidance": "A match is breaking only when the element's type is a structured type (an entity, aspect, or user-defined type with sub-elements). Check the element type to distinguish structured from scalar defaults.\n",
      "compilerDetects": true,
      "patternsComplete": true,
      "body": "Before cds10, you were able to provide invalid default values for structured elements, which were silently ignored.\nFor example, the below was accepted but ignored in `2sql` and `4odata` backends:\n\n```cds\ntype struct { a: Integer; b: String; }\nentity Foo { bar: struct default 22; }\n```\n\nWith cds10, such invalid defaults result in an error, for example, like that:\n\n```js\n[ERROR] Unexpected ‘default’ for a structured element with not exactly one sub element (in element: “bar”)\n```\n\nIn case you get such an error, simply remove the invalid default, which has no negative impact, as it was ignored anyway before.",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#cds-defaults-for-structs",
      "capireSection": "CDS – Improved Checks",
      "compilerPattern": [
        "type-unexpected-default-struct"
      ]
    },
    {
      "id": "duplicate-element-via-extend-is-error",
      "title": "Duplicate Elements",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "cdl"
      ],
      "group": "cdl-syntax",
      "guidance": "Cannot detect statically whether two aspects produce a duplicate element — determining this requires semantic analysis. The compiler warning (`name-duplicate-element`) introduced in v6.9+ is the primary detection mechanism. Run `cds compile` with v6.9+ before upgrading and check for name-duplicate-element warnings.\n",
      "compilerDetects": true,
      "patternsComplete": true,
      "body": "Before cds10, it was possible to extend an entity with multiple aspects that contain elements with the same name, leading to unexpected behavior.\nWith cds10, this is now an error, to avoid such late surprises.\nFor example:\n\n```cds\nentity E { ID : Integer; }\nextend E with { field : String; };\nextend E with { field : Date; };\n```\n```js\n[ERROR] Duplicate definition of element “field” ...\n```\nIf you encounter such errors, you need to adapt your model to avoid duplicate elements.\nFor example, you could simply remove one of the conflicting elements, or rename it.",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#cds-duplicate-elements",
      "capireSection": "CDS – Improved Checks",
      "compilerPattern": [
        "duplicate-definition"
      ]
    },
    {
      "id": "hdbcds-backend-removed",
      "title": "Removed deploy format `hdbcds`",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "compiler"
      ],
      "group": "compiler-config",
      "patternCdsEnv": [
        "hdbcds",
        "cds\\.hana\\.deploy-format"
      ],
      "patternOther": [
        "hdbcds",
        "cds\\.hana\\.deploy-format"
      ],
      "guidance": "For patternCdsEnv and patternOther matches: the value `hdbcds` in `cds.hana.deploy-format` is unconditionally breaking — the compiler backend is removed. Also check for `cds.compile.to.hdbcds` calls in JS code. Bare string matches in comments or documentation prose are FPs. These keys are not framework defaults; any config-context match is a genuine finding.\n",
      "compilerDetects": true,
      "patternsComplete": true,
      "body": "- we removed the support for deploy format `hdbcds`\n\n#### Are you affected?\n\n- check for `\"deploy-format\": \"hdbcds\"` in cds config files (double check!)\n- check for `cds.compile.to.hdbcds` calls in js code\n\n#### How to address?\n\n- Use the default deploy format `.hdbtable` instead. It can also be programmatically called with `cds.compile.to.hdbtable`\n- see also [May 25](https://cap.cloud.sap/docs/releases/2025/may25#removed-hdbcds-format)\n- Note that the format is different. check [the documentation for migration](https://cap.cloud.sap/docs/cds/compiler/hdbcds-to-hdbtable)",
      "capireSection": "CDS – Improved Checks"
    },
    {
      "id": "ieee754-compatible-default-true",
      "title": "Decimals & Int64 as Strings",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "config"
      ],
      "compatFlag": "features.ieee754compatible",
      "group": "serialization",
      "patternCdsEnv": [
        "cds\\.features\\.ieee754compatible"
      ],
      "guidance": "For patternCdsEnv matches: check whether the value is absent or explicitly `false` — only those cases mean the new default (`true`) now applies. Only report if the provenance grep finds this key in a project config file. HTTP `Content-Type` headers containing `IEEE754Compatible=true` in test files or Postman collections are not config flags.\n",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "Decimal and Int64 values cannot be represented as JavaScript numbers without risks of losing precision. Therefore many database drivers, including those for [HANA](https://cap.cloud.sap/docs/guides/databases/hana.md) and [PostgreSQL](https://cap.cloud.sap/docs/guides/databases/postgres.md), always return such data as strings, while [SQLite](https://cap.cloud.sap/docs/guides/databases/sqlite.md) drivers return numbers.\n\nThis database-dependent discrepancy caused late surprises to CAP projects, when moving to production with HANA or PostgreSQL, after developing with SQLite.\n\nTo avoid such late surprises we consolidated the default behavior for SQLite with the behavior of HANA and PostgreSQL. This is controlled by config option <config>cds.features.ieee754compatible: true</config> (was `false` before).\n\n\n::: details See also...\n\n- [JavaScript numbers](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)\n- [IEEE 754 64-bit binary format](https://en.wikipedia.org/wiki/Double-precision_floating-point_format)\n- [RFC 7493](https://www.rfc-editor.org/info/rfc7493/)\n- [SQLite numbers](https://sqlite.org/floatingpoint.html)\n- [Why is 0.1 + 0.2 != 0.3?](https://stackoverflow.com/questions/50778431/why-does-0-1-0-2-return-unpredictable-float-results-in-javascript-while-0-2)\n\n```js\n0.1 + 0.2 //> 0.30000000000000004\n(0.1).toString(2)\n(0.2).toString(2)\n(0.3).toString(2)\n(0.1 + 0.2).toString(2)\n```\n```js\n(0.5 + 0.25 + 0.125).toString(2)\n(1/2).toString(2)\n(1/2/2).toString(2)\n(1/2/2/2).toString(2)\n```\n\n\nYes, JavaScript has `bigint` support, but JSON doesn't. Even if we would custom-serialize them as numbers losslessly, clients would parse these into JavaScript Numbers, hence losing precision.\nBtw: Same applies to Java, which has dedicated `BigDecimal` and `BigInteger` types, but these are not supported by JSON, nor the JSON clients.\nBottom line: If you want to exchange such data, always do so as strings.\n\n:::\n\n#### Are you affected?\n\nYou are affected by this change if:\n\n- You have [`Decimal`](https://cap.cloud.sap/docs/cds/types.md) or [`Int64`](https://cap.cloud.sap/docs/cds/types.md) elements in your model.\n   For example, search for usages of these types in your _*.cds_ files like so:\n   ```shell\n   grep -rni --exclude=\"*/node_modules/*\" --include \\*.cds \":\\s*Decimal\"\n   grep -rni --exclude=\"*/node_modules/*\" --include \\*.cds \":\\s*Int64\"\n   ```\n- And you have custom code that does calculations with such fields, for example:\n  ```js\n  await INSERT.into(Books).entries({ID:1,stock:10})\n  let { stock } = await SELECT.one.from (Books,1)\n  stock = stock + 1 //> with SQLite: 11, with HANA: '101'\n  ```\n- And/or you have tests that compare such elements by equality, e.g.:\n  ```js\n  expect(book.stock).to.equal(10)\n  expect(book).to.equal({ ..., stock:10 })\n  ```\n\nGood news: You are *not* affected if:\n\n- You already had to fix those discrepancies when you went productive before.\n- You already switched on <config>cds.features.ieee754compatible: true</config> in the past.\n\nEven if you are affected, such silent string concatenations were ticking time bombs, which you would have encountered eventually in production.\n\n#### How to address?\n\n1. If you don't care about functional correctness in production, for example, if you're just doing prototypes or demos, revert to the former behavior by setting <config>cds.features.ieee754compatible: false</config>.\n\n2. Use [`Double`](https://cap.cloud.sap/docs/cds/types.md) instead of [`Decimal`](https://cap.cloud.sap/docs/cds/types.md) if you do want JavaScript numbers, and are fine with neglectable precision loss.\n\n3. Rewrite failing tests to not check for numeric equality. For example, the asserts above could be rewritten like that:\n   ```js\n   expect(book.stock).to.equal('10')\n   expect(book).to.equal({ ..., stock:'10' })\n   ```\n\n4. If you need to do arithmetics in JavaScript, explicitly convert respective data to a Number before, for example, like that:\n   ```js\n   stock = Number(stock) + 1\n   ```\n\n> [!tip]\n>\n> In general: Avoid calculations with such fields in JavaScript, as these always may result in precision losses. Do these in the database instead. For example, this is safe: `UPDATE Books set stock = stock + 1`.",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#ieee754compatible",
      "capireSection": "Changes to Runtime",
      "defaultValue": "true"
    },
    {
      "id": "legacy-srv-results-default-false",
      "title": "Fixed Service Results – legacy_srv_results flag",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "config"
      ],
      "compatFlag": "features.legacy_srv_results: true",
      "group": "handler-api",
      "patternCdsEnv": [
        "cds\\.features\\.legacy_srv_results"
      ],
      "guidance": "For patternCdsEnv matches: if the value is explicitly `true`, the project uses the kill switch (restores legacy return shape) — protected, not breaking. If the key is absent, the new default applies and the project may be affected. Only report if the provenance grep finds it in a project config file. This change is not detectable from a single pattern alone — the agent should scan handler code for return statements whose value is then consumed by callers as `req.data`-shaped (object with the row's properties) or, for DELETE, as a number. Look for patterns like `return req.data`, `return result.affectedRows`, or `expect(result).toEqual({ID: 1, ...})` in tests — all these now see arrays carrying an `.affected` property instead.\n",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "Before cds10, results of local service calls involving write operations, that is, INSERT, UPDATE and DELETE, were undocumented and inconsistent. In particular:\n\n| Operation | with db services                 | with app services         |\n|-----------|----------------------------------|---------------------------|\n| INSERT    | => insert results                | _=> req.data input_{.red} |\n| UPDATE    | _=> # of affected rows_{.yellow} | _=> req.data input_{.red} |\n| DELETE    | _=> # of affected rows_{.yellow} | _=> req.data input_{.red} |\n\nWith cds10 we fixed and consolidated that, so that ...\n\n- All write operations of app services return the same kind of result: an array with property `affected` indicating the affected rows, for example, like that:\n  ```js\n  let { affected } = await srv.create(Books).entries(...)\n  let { affected } = await srv.update(Books) .where `stock > 111` ...\n  let { affected } = await srv.delete(Books) .where `stock = 0`\n  ```\n\n- Same for db services, with opt-in via <config>cds.features.legacy_db_results: false</config>.\n\n\nIn addition, the change to real _array_ objects, also for `InsertResults` allows us to uniformly use object spread destructuring as well as standard array operations, for example, to retrieve generated primary keys in case of INSERTs, for example:\n\n```js\nlet [ Emily, Charlotte ] = await srv.create(Authors).entries(\n  {name:'Emily Brontee'},\n  {name:'Charlotte Brontee'}\n)\n```\n\nIn addition, that also allows us to support [SQL `returning` clauses](https://sqlite.org/lang_returning.html) in future with INSERT, UPDATE, and DELETE requests.\n\nNo change was made to the results of read operations, that is, SELECTs, which return plain arrays of entries, as before.\n\n\n#### Are you affected?\n\nYou are affected by this change if you have custom code that relies on the former inconsistent and undocumented results of UPDATE and DELETE operations, in particular if you have...\n\n1. Calls to UPDATE or DELETE with app services which do expect `req.data` as result\n2. Custom `after` handlers for the same which do expect `req.data` as first argument\n3. Calls to UPDATE or DELETE with db services which do expect a number as result\n4. Tests which expect an _object_, but not an _array_, as result of INSERTs on db level\n\n#### How to address?\n\nIf you are affected, you should adapt your code to the new consistent results.\n\nFor example, for 1. and 2., you can simply access the input data via `req.data` instead of the result, for example, like that:\n\n```js\nthis.on ('UPDATE', Books, async (req, next) => {\n  let { ID, stock } = await next() // [!code --] returned req.data before\n  await next(); let { ID, stock } = req.data // [!code ++] just access req.data explicitly now\n})\n```\n\nFor 3., you can access the number of affected rows via the `affected` property of the result, for example, like that:\n\n```js\nlet affected = await srv.update(Books) .where `stock > 111` ... // [!code --]\nlet { affected } = await srv.update(Books) .where `stock > 111` ... // [!code ++]\n```\n\nFor 4., you can adapt your tests to expect an array instead of an object, for example, like that:\n\n```js\nexpect(result).to.deep.equal ({ affectedRows:1 }) // [!code --]\nexpect({...result}).to.deep.equal ({ affectedRows:1 }) // [!code ++]\nexpect({...result}).to.deep.equal ({ affected:1 }) // [!code ++]\nexpect(result).to.have.property ('affected',1) // [!code ++]\n```\n\n\n#### Opt-in & Kill Switches\n\nAs a last resort, you can restore the former behavior with the following config options:\n\n| `cds.features.`...                                               | -> restores:                                         |\n|------------------------------------------------------------------|------------------------------------------------------|\n| <Config section=\"cds.features\">legacy_srv_results: true</Config> | the undocumented former behavior                     |\n| <Config section=\"cds.features\">legacy_db_results: true</Config>  | the former behavior, and still the default for cds10 |\n\n> [!warning]\n> As such kill switches restore unintended, and erroneous behavior, they should only be used as a temporary measure. It's recommended to update your code to be compatible with the new behavior. The kill switches will be removed in a future release, and relying on them for longer time may cause maintenance issues and technical debt.",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#fixed-srv-results",
      "capireSection": "Changes to Runtime",
      "defaultValue": "false"
    },
    {
      "id": "queue-legacy-locking-default-false",
      "title": "Queue legacyLocking default changed to false",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "config"
      ],
      "compatFlag": "legacyLocking: true in queue config",
      "group": "messaging-queue",
      "patternCdsEnv": [
        "cds\\.requires\\.messaging\\.queue\\.legacyLocking"
      ],
      "guidance": "For patternCdsEnv matches: `legacyLocking` is not a framework default — any match means the project explicitly configured this key. The new default is `false`. Per the body, this is relevant when skipping cds^9 (upgrading from cds^8 directly to cds^10) and utilizing blue-green deployments — in that case, set `legacyLocking: true` and `cds.requires.scheduling: false` for deployment, then remove both configs again.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "We introduced optimized scheduling by default (`cds.requires.scheduling=true`). This is only relevant in case projects used the in-memory queue or need to opt-out of certain event queues configs.\n\nQueue kind `in-memory-queue` is deprecated and not supported if optimized scheduling is enabled.\n\nWe streamlined the event queues config options:\n\n- Sources:\n  - `cds.requires.outbox` is deprecated. Use `cds.requires.queue` instead.\n  - `cds.requires.<srv>.outbox` is deprecated. Use `cds.requires.<srv>.outboxed` instead.\n- Options:\n  - `cds.requires.queue.legacyLocking` is now `false` by default\n  - `cds.requires.queue.storeLastError` was removed (now always `true` implicitly)\n  - `cds.requires.queue.maxAttempts` is now `10` by default\n  - Inofficial `cds.requires.queue.targetPrefix` is deprecated. Use `cds.appid` instead.\n\n#### Are you affected?\n\n- check for `in-memory-queue` in all cds env input files\n- check for `requires.outbox` in all cds env input files\n- check for `outbox` in a `requires` entry in all cds env input files (e.g., `requires.API_BUSINESS_PARTNER.outbox`)\n- `legacyLocking`: check if cds^9 is being skipped, i.e., upgrading from cds^8 directly to cds^10\n- check for `storeLastError` in all cds env input files\n- check for `targetPrefix` in all cds env input files\n\n#### How to address?\n\n- `in-memory-queue`: Switch to default `persistent-queue` (i.e., remove the config).\n- `legacyLocking`: In case of skipping cds^9 and utilizing blue-green deployments, projects should set `cds.requires.queue.legacyLocking=true` and `cds.requires.scheduling=false` for deployment and then remove both configs again.",
      "capireSection": "Changes to Runtime",
      "defaultValue": "false"
    },
    {
      "id": "queue-max-attempts-default-10",
      "title": "Queue maxAttempts default reduced from 20 to 10",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "config"
      ],
      "group": "messaging-queue",
      "patternCdsEnv": [
        "cds\\.requires\\.messaging\\.queue\\.maxAttempts"
      ],
      "guidance": "For patternCdsEnv matches: `maxAttempts` appears as a framework default in `cds env -l` output. Only report if the provenance grep finds it in a project config file.\n",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "We introduced optimized scheduling by default (`cds.requires.scheduling=true`). This is only relevant in case projects used the in-memory queue or need to opt-out of certain event queues configs.\n\nQueue kind `in-memory-queue` is deprecated and not supported if optimized scheduling is enabled.\n\nWe streamlined the event queues config options:\n\n- Sources:\n  - `cds.requires.outbox` is deprecated. Use `cds.requires.queue` instead.\n  - `cds.requires.<srv>.outbox` is deprecated. Use `cds.requires.<srv>.outboxed` instead.\n- Options:\n  - `cds.requires.queue.legacyLocking` is now `false` by default\n  - `cds.requires.queue.storeLastError` was removed (now always `true` implicitly)\n  - `cds.requires.queue.maxAttempts` is now `10` by default\n  - Inofficial `cds.requires.queue.targetPrefix` is deprecated. Use `cds.appid` instead.\n\n#### Are you affected?\n\n- check for `in-memory-queue` in all cds env input files\n- check for `requires.outbox` in all cds env input files\n- check for `outbox` in a `requires` entry in all cds env input files (e.g., `requires.API_BUSINESS_PARTNER.outbox`)\n- `legacyLocking`: check if cds^9 is being skipped, i.e., upgrading from cds^8 directly to cds^10\n- check for `storeLastError` in all cds env input files\n- check for `targetPrefix` in all cds env input files\n\n#### How to address?\n\n- `in-memory-queue`: Switch to default `persistent-queue` (i.e., remove the config).\n- `legacyLocking`: In case of skipping cds^9 and utilizing blue-green deployments, projects should set `cds.requires.queue.legacyLocking=true` and `cds.requires.scheduling=false` for deployment and then remove both configs again.",
      "capireSection": "Changes to Runtime"
    },
    {
      "id": "queue-store-last-error-deprecated",
      "title": "Queue storeLastError deprecated — removed in cds^11",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "config"
      ],
      "deprecated": "10.0",
      "group": "messaging-queue",
      "patternCdsEnv": [
        "cds\\.requires\\.messaging\\.queue\\.storeLastError"
      ],
      "guidance": "For patternCdsEnv matches: `storeLastError` is not a framework default — any match means the project explicitly set this now-removed option. The option is removed and always implicitly `true`. Any config-file match is a cleanup finding: remove the key.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "We introduced optimized scheduling by default (`cds.requires.scheduling=true`). This is only relevant in case projects used the in-memory queue or need to opt-out of certain event queues configs.\n\nQueue kind `in-memory-queue` is deprecated and not supported if optimized scheduling is enabled.\n\nWe streamlined the event queues config options:\n\n- Sources:\n  - `cds.requires.outbox` is deprecated. Use `cds.requires.queue` instead.\n  - `cds.requires.<srv>.outbox` is deprecated. Use `cds.requires.<srv>.outboxed` instead.\n- Options:\n  - `cds.requires.queue.legacyLocking` is now `false` by default\n  - `cds.requires.queue.storeLastError` was removed (now always `true` implicitly)\n  - `cds.requires.queue.maxAttempts` is now `10` by default\n  - Inofficial `cds.requires.queue.targetPrefix` is deprecated. Use `cds.appid` instead.\n\n#### Are you affected?\n\n- check for `in-memory-queue` in all cds env input files\n- check for `requires.outbox` in all cds env input files\n- check for `outbox` in a `requires` entry in all cds env input files (e.g., `requires.API_BUSINESS_PARTNER.outbox`)\n- `legacyLocking`: check if cds^9 is being skipped, i.e., upgrading from cds^8 directly to cds^10\n- check for `storeLastError` in all cds env input files\n- check for `targetPrefix` in all cds env input files\n\n#### How to address?\n\n- `in-memory-queue`: Switch to default `persistent-queue` (i.e., remove the config).\n- `legacyLocking`: In case of skipping cds^9 and utilizing blue-green deployments, projects should set `cds.requires.queue.legacyLocking=true` and `cds.requires.scheduling=false` for deployment and then remove both configs again.",
      "capireSection": "Changes to Runtime"
    },
    {
      "id": "requires-scheduling-default-true",
      "title": "cds.requires.scheduling defaults to true — Scheduling Service auto-connects when a database is configured",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "config"
      ],
      "compatFlag": "requires.scheduling: false",
      "group": "messaging-queue",
      "patternCdsEnv": [
        "cds\\.requires\\.scheduling"
      ],
      "guidance": "For patternCdsEnv matches: check whether the value is absent or explicitly `false` — only those cases mean the new default (`true`) now applies. A match for `scheduling` in cds env output may reflect the new framework default; only flag the project as affected if the key is absent from project config files. Per the body, this is only relevant in case projects used the in-memory queue or need to opt-out of certain event queues configs.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "We introduced optimized scheduling by default (`cds.requires.scheduling=true`). This is only relevant in case projects used the in-memory queue or need to opt-out of certain event queues configs.\n\nQueue kind `in-memory-queue` is deprecated and not supported if optimized scheduling is enabled.\n\nWe streamlined the event queues config options:\n\n- Sources:\n  - `cds.requires.outbox` is deprecated. Use `cds.requires.queue` instead.\n  - `cds.requires.<srv>.outbox` is deprecated. Use `cds.requires.<srv>.outboxed` instead.\n- Options:\n  - `cds.requires.queue.legacyLocking` is now `false` by default\n  - `cds.requires.queue.storeLastError` was removed (now always `true` implicitly)\n  - `cds.requires.queue.maxAttempts` is now `10` by default\n  - Inofficial `cds.requires.queue.targetPrefix` is deprecated. Use `cds.appid` instead.\n\n#### Are you affected?\n\n- check for `in-memory-queue` in all cds env input files\n- check for `requires.outbox` in all cds env input files\n- check for `outbox` in a `requires` entry in all cds env input files (e.g., `requires.API_BUSINESS_PARTNER.outbox`)\n- `legacyLocking`: check if cds^9 is being skipped, i.e., upgrading from cds^8 directly to cds^10\n- check for `storeLastError` in all cds env input files\n- check for `targetPrefix` in all cds env input files\n\n#### How to address?\n\n- `in-memory-queue`: Switch to default `persistent-queue` (i.e., remove the config).\n- `legacyLocking`: In case of skipping cds^9 and utilizing blue-green deployments, projects should set `cds.requires.queue.legacyLocking=true` and `cds.requires.scheduling=false` for deployment and then remove both configs again.",
      "capireSection": "Changes to Runtime",
      "defaultValue": "true"
    },
    {
      "id": "srv-getters-removed",
      "title": "Fixed `srv.entities()` – getter methods removed",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "api"
      ],
      "compatFlag": "features.compat_srv_getters",
      "group": "reflection-api",
      "groupTitle": "Fixed `srv.entities()`",
      "patternSource": "(?<!\\bcds)\\s*\\.\\s*entities\\s*\\(|(?<!\\bcds)\\.types\\s*\\(|(?<!\\bcds)\\.events\\s*\\(|(?<!\\bcds)\\.actions\\s*\\(",
      "patternCdsEnv": [
        "cds\\.features\\.compat_srv_getters"
      ],
      "guidance": "Matches function-call syntax on getters (.entities(), .types(), .events(), .actions()). Breaking when the receiver is a service object (a subclass of cds.Service). The fix is to use the property accessor without parentheses. FP risk: `.entities()` on non-CDS objects (e.g. ORM libraries, custom classes) are not affected.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "You can access the linked definitions of a service's entities via convenient accessor [`srv.entities`](https://cap.cloud.sap/docs/node.js/core-services.md#entities), which is a shortcut for the more general [`cds.entities()`](https://cap.cloud.sap/docs/node.js/cds-reflect.md#cds-service) with the service's fully-qualified name as an argument:\n\n```js\nclass CatalogService extends cds.ApplicationService { init() {\n  const { Books, Authors } = this.entities //> equivalent to:\n  const { Books, Authors } = cds.entities ('CatalogService')\n  // ...\n}}\n```\n\nIn the past you were able to also call [`srv.entities`](https://cap.cloud.sap/docs/node.js/core-services.md#entities) as a function, which was confusing, undocumented and unintended, which we fixed now. In case you used the function variant, fix your code like that:\n\n```js\nconst { Books } = srv.entities() // [!code --]\nconst { Books } = srv.entities // [!code ++]\n```\n```js\nconst { Books } = srv.entities ('sap.capire.bookshop') // [!code --]\nconst { Books } = cds.entities ('sap.capire.bookshop') // [!code ++]\n```\n> The same applies to the related getters for [`srv.types`](https://cap.cloud.sap/docs/node.js/core-services.md#types), [`.events`](https://cap.cloud.sap/docs/node.js/core-services.md#events), and [`.actions`](https://cap.cloud.sap/docs/node.js/core-services.md#actions).\n\nFurthermore, from version 10 onwards, the `.texts` entities will not be included in the results returned by [`srv.entities`](https://cap.cloud.sap/docs/node.js/core-services.md#entities) nor [`cds.entities`](https://cap.cloud.sap/docs/node.js/cds-facade.md#cds-entities) anymore. Use the [`texts`](https://cap.cloud.sap/docs/node.js/cds-reflect#texts) property of the respective entity instead, for example, like that:\n\n```js\nconst { \"Books.texts\": Books_texts } = srv.entities // [!code --]\nconst { Books } = srv.entities // [!code ++]\nBooks.texts //> points to the generated `Books.texts` entity [!code ++]\n```\n\n\n#### Kill Switches\n\nAs a last resort, you can restore the former behavior with the following config options:\n\n| `cds.features.`...                                                  | -> restores:                                   |\n|---------------------------------------------------------------------|------------------------------------------------|\n| <Config section=\"cds.features\">compat_srv_getters: true</Config>    | `srv.entities()` as a function                 |\n| <Config section=\"cds.features\">compat_texts_entities: true</Config> | `*.texts` entries in results of `srv.entities` |\n\n> [!warning]\n> As these kill switches restore unintended, and erroneous behavior, they should only be used as a temporary measure. It's recommended to update your code to be compatible with the new behavior. The kill switches will be removed in a future release, and relying on them for longer time may cause maintenance issues and technical debt.",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#fixed-srv-entities",
      "capireSection": "Changes to Runtime",
      "defaultValue": "false"
    },
    {
      "id": "compat-texts-entities-default-false",
      "title": "Fixed `srv.entities()` – texts entity access",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "api",
        "config"
      ],
      "compatFlag": "features.compat_texts_entities",
      "group": "reflection-api",
      "groupTitle": "Fixed `srv.entities()`",
      "patternSource": "(\\.texts.*\\}\\s*=.*\\.entities)|(\\.entities.*\\[.*\\.texts.*\\])",
      "guidance": "For patternAst matches: breaking only when the bracket key contains a `.texts` suffix (e.g. `.entities['Books.texts']`). Generic bracket access for other entity names is not affected. The new style is `.entities['Books'].texts`. For patternCdsEnv matches: this key may appear as a framework default in `cds env -l` output. Only report if the provenance grep finds it in a project config file (see prompt Step 3).\n",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "Furthermore from version 10 onwards, the `.texts` entities will not be included in the results returned by [`srv.entities`](https://cap.cloud.sap/docs/node.js/core-services.md#entities) nor [`cds.entities`](https://cap.cloud.sap/docs/node.js/cds-facade.md#cds-entities) anymore. Use the [`texts`](https://cap.cloud.sap/docs/node.js/cds-reflect#texts) property of the respective entity instead, for example, like that:\n\n```js\nconst { \"Books.texts\": Books_texts } = srv.entities // [!code --]\nconst { Books } = srv.entities // [!code ++]\nBooks.texts //> points to the generated `Books.texts` entity [!code ++]\n```\n\n\n#### Kill Switches\n\nAs a last resort, you can restore the former behavior with the following config options:\n\n| `cds.features.`...                                                  | -> restores:                                   |\n|---------------------------------------------------------------------|------------------------------------------------|\n| <Config section=\"cds.features\">compat_srv_getters: true</Config>    | `srv.entities()` as a function                 |\n| <Config section=\"cds.features\">compat_texts_entities: true</Config> | `*.texts` entries in results of `srv.entities` |\n\n> [!warning]\n> As these kill switches restore unintended, and erroneous behavior, they should only be used as a temporary measure. It's recommended to update your code to be compatible with the new behavior. The kill switches will be removed in a future release, and relying on them for longer time may cause maintenance issues and technical debt.",
      "capireSection": "Changes to Runtime",
      "capireAnchor": "https://cap.cloud.sap/docs/releases/migration/cds10#fixed-srv-entities",
      "defaultValue": "false"
    },
    {
      "id": "token-info-removed",
      "title": "API cds.User.tokenInfo",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "api"
      ],
      "group": "auth-context",
      "patternSource": "user\\.tokenInfo",
      "guidance": ".tokenInfo appears in JWT libraries unrelated to CAP. A match is only breaking when the receiver is `cds.context.user`, `req.user`, or a variable assigned from either. Receivers from `xssec.createSecurityContext()`, `passport`, or `jwt.verify()` are FPs.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "- the undocumented API is now removed, but there is a successor.\n\n#### Are you affected?\n- check if `user.tokenInfo` occurs in js files\n\n#### How to address?\n- instead of `cds.context.user.tokenInfo` use `cds.context.user.authInfo.token`\n- inside a custom handler: instead of use `req.user.tokenInfo` use `req.user.authInfo.token`\n- also see [Aug 25](https://cap.cloud.sap/docs/releases/2025/aug25#cds-user-authinfo)",
      "capireSection": "Changes to Runtime"
    },
    {
      "id": "transitive-localized-views-removed",
      "title": "Removed Transitive Localized Views",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "compiler"
      ],
      "group": "compiler-config",
      "patternCdsEnv": [
        "cds\\.sql\\.transitive_localized_views"
      ],
      "guidance": "For patternCdsEnv and patternOther matches: `transitive_localized_views` is not a framework default — any match means the project set this option explicitly. The option is silently ignored after the upgrade regardless of its value; remove it from config.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "Since cds-compiler v5, the compiler doesn't any longer generate so-called \"transitive localized views\" by default,\nbecause they are no longer used by the runtimes.\nSee [Release notes June 2024](https://cap.cloud.sap/docs/releases/2024/jun24#transitive-localized-views-removed).\n\nBefore cds-compiler v7,\nit was possible to switch them back on with configuration `cds.sql.transitive_localized_views`\n(see [Deprecated Features](https://cap.cloud.sap/docs/releases/2024/jun24#deprecated-features)).\n\nWith cds-compiler v7,\nthis configuration option has been removed. There is no possibility to generate transitive localized views any longer.\nThese views will disappear with the next database migration. As proven by multiple stakeholders and customers during the grace period of >2 years, that is transparent, and non breaking to applications.",
      "capireSection": "CDS – Improved Checks"
    },
    {
      "id": "cds-plugin-activate-removed",
      "title": "Removed cds-plugin.js `activate()` function",
      "runtime": "nodejs",
      "appliesTo": {
        "package": "@sap/cds",
        "versionRange": ">=9.0.0 <10.0.0"
      },
      "scope": [
        "api"
      ],
      "group": "plugin-api",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "Removed support for async `activate()` functions returned from cds-plugin.js modules, which was never documented, and deprecated since Oct 2023. If you need to run async code during plugin loading, just return a promise as default export.",
      "capireAnchor": null,
      "capireSection": "Changes to Runtime"
    },
    {
      "id": "java-cds-maven-plugin-generate-properties-removed",
      "title": "cds-maven-plugin generate goal – eventContext and cqnService removed",
      "runtime": "java",
      "scope": [
        "build"
      ],
      "group": "build-tooling",
      "patternOther": [
        "<eventContext>",
        "<cqnService>"
      ],
      "guidance": "Matches for <eventContext> and <cqnService> inside a cds-maven-plugin generate goal configuration are direct findings — these properties are removed. Matches in comments or unrelated plugin configurations are FPs.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "The `generate` goal of the `cds-maven-plugin` had two deprecated configuration properties removed in version 5.0.0:\n\n- **`eventContext`** — controlled whether interfaces for actions/functions extend `EventContext`. Now always `true`.\n- **`cqnService`** — controlled whether typed interfaces are generated for application services. Now always `true`.\n\nRemove these properties from the `generate` goal configuration in `pom.xml`:\n\n```diff\n  <configuration>\n-   <eventContext>false</eventContext>\n-   <cqnService>false</cqnService>\n  </configuration>\n```",
      "capireAnchor": null,
      "capireSection": "Java / Spring Boot Migration"
    },
    {
      "id": "java-cds-maven-plugin-install-cdsdk-removed",
      "title": "cds-maven-plugin install-cdsdk goal removed",
      "runtime": "java",
      "scope": [
        "build"
      ],
      "group": "build-tooling",
      "patternOther": [
        "install-cdsdk"
      ],
      "guidance": "Any match for `install-cdsdk` in a pom.xml is a direct finding — the goal no longer exists in cds-maven-plugin 5.0.0. Matches in comments or documentation are FPs.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "The `install-cdsdk` goal of the `cds-maven-plugin` is removed in version 5.0.0. Replace with the `npm` goal:\n\n```diff\n  <execution>\n    <id>install-cdsdk</id>\n    <goals>\n-     <goal>install-cdsdk</goal>\n+     <goal>npm</goal>\n    </goals>\n+   <configuration>\n+     <arguments>install --save-dev @sap/cds-dk</arguments>\n+   </configuration>\n  </execution>\n```",
      "capireAnchor": null,
      "capireSection": "Java / Spring Boot Migration"
    },
    {
      "id": "java-maven-minimum-version",
      "title": "Maven minimum version increased to 3.9.10",
      "runtime": "java",
      "scope": [
        "prerequisite"
      ],
      "group": "prerequisites",
      "patternOther": [
        "<maven\\.version>[^<]*</maven\\.version>",
        "required-maven-version"
      ],
      "guidance": "Matches Maven version declarations in pom.xml. Any declared minimum below 3.9.10 is affected. Projects without explicit version constraints should verify their CI Maven version.\n",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "CAP Java 5.0 (CDS 10) requires **Maven 3.9.10 or higher**. Update Maven Wrapper, enforcer plugin, and CI pipelines:\n\n```diff\n- distributionUrl=.../apache-maven-3.9.6-bin.zip\n+ distributionUrl=.../apache-maven-3.9.15-bin.zip\n```\n\n```diff\n  <requireMavenVersion>\n-   <version>3.6</version>\n+   <version>3.9.10</version>\n  </requireMavenVersion>\n```",
      "capireAnchor": null,
      "capireSection": "Java / Spring Boot Migration"
    },
    {
      "id": "java-saas-registry-dependency-appid-removed",
      "title": "SaaSRegistryDependency appId/appName methods removed",
      "runtime": "java",
      "scope": [
        "api"
      ],
      "group": "java-api-removals",
      "orRecipe": "com.sap.cds.services.migrations.MigrateSaasRegistryDependency",
      "guidance": "Any match for `SaaSRegistryDependency` in Java sources confirms usage of the affected class. Verify the code calls `getAppId`, `setAppId`, `getAppName`, or `setAppName` — these are removed. Other usages of the class are unaffected.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "Four deprecated methods in `SaaSRegistryDependency` are removed in CAP Java 5:\n\n- `getAppId()` → `getXsappname()`\n- `setAppId(value)` → `setXsappname(value)`\n- `getAppName()` → `getXsappname()`\n- `setAppName(value)` → `setXsappname(value)`\n\nFix automatically with OpenRewrite:\n```sh\nmvn rewrite:run -Drewrite.activeRecipes=com.sap.cds.services.migrations.MigrateSaasRegistryDependency\n```",
      "capireAnchor": null,
      "capireSection": "Java / Spring Boot Migration"
    },
    {
      "id": "java-service-exception-utils-removed",
      "title": "ServiceExceptionUtils deprecated methods removed",
      "runtime": "java",
      "scope": [
        "api"
      ],
      "group": "java-api-removals",
      "orRecipe": "com.sap.cds.services.migrations.ServiceExceptionUtils",
      "guidance": "Any match for `ServiceExceptionUtils` in Java sources confirms usage. Verify the code calls `getLocalizedMessage` or `getMessageTarget` — the deprecated overloads are removed.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "Deprecated methods in `ServiceExceptionUtils` are removed in CAP Java 5:\n\n- `getLocalizedMessage(code, args, locale)` → `getLocalizedMessage(code, args, locale, true)`\n- `getMessageTarget(target)` → `MessageTarget.create(target)`\n- `getMessageTarget(parameter, path)` → `MessageTarget.create(parameter, path)`\n\nFix automatically with OpenRewrite:\n```sh\nmvn rewrite:run -Drewrite.activeRecipes=com.sap.cds.services.migrations.ServiceExceptionUtils\n```",
      "capireAnchor": null,
      "capireSection": "Java / Spring Boot Migration"
    },
    {
      "id": "java-ucl-result-getters-removed",
      "title": "UCL result getter/setter methods removed",
      "runtime": "java",
      "scope": [
        "api"
      ],
      "group": "java-api-removals",
      "orRecipe": "com.sap.cds.services.migrations.UclMigration",
      "guidance": "Matches for `getUclResult` or `setUclResult` in Java sources are direct findings. Only projects using the UCL (Unified Customer Landscape) feature are affected.\n",
      "compilerDetects": false,
      "patternsComplete": true,
      "body": "Two deprecated methods in `AssignEventContext` are removed in CAP Java 5:\n\n- `setUclResult(result)` → `setResult(result)`\n- `getUclResult()` → `getResult()`\n\nFix automatically with OpenRewrite:\n```sh\nmvn rewrite:run -Drewrite.activeRecipes=com.sap.cds.services.migrations.UclMigration\n```",
      "capireAnchor": null,
      "capireSection": "Java / Spring Boot Migration"
    },
    {
      "id": "spring-boot-4-upgrade",
      "title": "CAP Java 5 requires Spring Boot 4",
      "runtime": "java",
      "scope": [
        "prerequisite"
      ],
      "group": "prerequisites",
      "patternOther": [
        "<spring-boot.version>[^<]*[23]\\.[^<]*</spring-boot.version>",
        "<artifactId>spring-boot-starter-parent</artifactId>"
      ],
      "guidance": "Patterns match Maven pom.xml (spring-boot.version property, starter-parent artifactId). Any project on Spring Boot 3 or lower requires a full Spring Boot 3 → 4 migration. This entry is a pointer to the Spring Boot migration guide.\n",
      "compilerDetects": false,
      "patternsComplete": false,
      "body": "CAP Java 5 (CDS 10) requires Spring Boot 4. Spring Boot 3 is no longer supported.\n\nUpdate `pom.xml`:\n```diff\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n-   <version>3.4.0</version>\n+   <version>4.0.0</version>\n  </parent>\n```\n\nFollow the [Spring Boot 4.0 Migration Guide](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.0-Migration-Guide) for all breaking changes (Jakarta EE 11, removed APIs, updated auto-configuration).",
      "capireAnchor": null,
      "capireSection": "Java / Spring Boot Migration"
    }
  ]
}
