A practical approach shown in the retrieved material is to make the production itself testable, then test components and message flow inside IRIS rather than against live external systems. The main concrete pattern present is:

  • enable Testing Enabled on the Production so you can use the built-in test pages for Business Processes and Business Operations during development [1][2]
  • start with the Business Operation when building the flow, because that “is convenient to start with the business operation to make testing easier” [1]
  • use a local IRIS-backed Business Operation instead of an external dependency when you want isolation, because a BO “can also be used to directly save in IRIS what we want,” and the training example creates a BO that stores the message in the local database rather than calling an external system [2]
  • drive the flow with standard request/response message classes extending Ens.Request / Ens.Response, and let the BO dispatch behavior through its MessageMap based on request type [2][3]
  • validate the orchestration by examining the resulting trace/messages, since the BP example shows testing the BP and then confirming in the trace that it invoked the defined components sequentially and synchronously [4]

So for a full BS → BP → BO integration scenario in an isolated, repeatable way, the closest pattern supported by the returned material is:

  1. Define request/response message classes for the flow. [2][3]
  2. Build the BP to orchestrate calls between components. [4]
  3. Replace external calls with a BO that performs local work in IRIS, such as persisting the request/result to a table, so assertions can be made without depending on outside systems. [2]
  4. Enable Production testing and use the production test pages for the BP/BO during development. [1][2]
  5. Verify the end-to-end behavior through the production trace/messages to confirm sequencing and data flow. [4]

The retrieved documents do not describe a formal “mock BO” framework or a dedicated mocking API. What they do show is the substitute-operation pattern: use a real BO with the same interoperability contract, but have it perform deterministic local IRIS work instead of reaching an external system. [2]

Note: BS stands for Business Services, BP for Business Processes, and BO for Business Operations. You need to write ObjectScript in Business Services and Business Operations and can be created in VSCode or Studio. Business Processes can also be made in the Management Portal (see this article for more information on using VSCode). There is no particular order of creation, but the external site to be connected to is a public site and can be used immediately in this sample. In this case, it is convenient to start with the business operation to make testing easier. After creating the components, there are test page in the production for business processes and business operations. However, testing is disabled by default in the production definition to avoid random testing in the production environment. [1]

If you specifically want a documented recommendation for mocking Business Operations, the returned material does not provide that level of guidance. The supported guidance is to keep BOs focused on message handling and adapter/use-flow concerns, and move reusable logic into separate helper/service classes, which also makes it easier to substitute a local BO for tests. [5][3]


Sources:

The main trade-off is convenience and built-in mapping control versus flexibility outside the class model.

%JSON.Adaptor is designed to make JSON import/export straightforward for registered, serial, and persistent objects by adding inherited methods such as %JSONImport() and %JSONExport(). It also handles arbitrarily nested object structures, so nested objects are a supported scenario rather than a gap, provided the nested classes also participate in the adaptor-based model. [1][2]

For field naming, %JSON.Adaptor already provides built-in mapping controls. If JSON field names do not match property names, you can use %JSONFIELDNAME, and you can also define mappings in an XData block and select the mapping per import/export call. This means custom naming conventions are often manageable without writing custom serializers. [1][3][4]

For null handling, %JSON.Adaptor also has explicit controls. %JSONNULL can cause unspecified properties to be exported as null rather than omitted, and %JSONIGNORENULL can override default handling of empty strings for string properties. [1][3][4]

It also supports selective inclusion rules through %JSONINCLUDE, including INPUTONLY, OUTPUTONLY, and NONE, plus reference handling via %JSONREFERENCE (OBJECT, ID, OID, GUID). That gives fairly strong out-of-the-box control over projection behavior. [1]

Where custom serialization becomes attractive is when you want behavior that should not be tied to changing or recompiling the class definition, or when you want multiple serialization criteria and transformations with more freedom. One source explicitly presents custom serialization as useful for exporting/importing selected properties, transforming values, using different formats, and doing this “without having to change the class definition.” It also contrasts that with %JSON.Adaptor, noting the custom approach is “more flexible,” though “less performant” and with “less format features,” while still recommending %JSON.Adaptor in general. [5]

Another practical limitation shown in the retrieved material is that when property names differ from incoming JSON field names and no mapping is defined, import can fail with an “unexpected field” error. The documented workaround is to use %JSONFIELDNAME or XData mapping; one article also suggests %JSONIGNOREINVALIDFIELD to avoid unexpected field errors. So adaptor-based serialization works best when the class-to-JSON contract is clearly declared. [3][4]

One additional nuance is case sensitivity of field names during import. The retrieved discussion indicates that, by default, %JSON.Adaptor treats the property name as fixed and case-sensitive unless you explicitly map fields, for example with %JSONFIELDNAME or XData mapping. [6]

So, in practice, the trade-offs described by the sources are:

  • Use %JSON.Adaptor when you want quick, built-in object/JSON serialization with support for nested objects, field aliasing, null control, inclusion/exclusion, and reusable mappings. [1][2][3]
  • Use custom serialization when you need projection logic that is more independent of the class definition, want to inject custom transformations or alternate criteria, or need broader format flexibility beyond what the class-mapping model gives you. [5]

If your concerns are specifically nested objects, nulls, and custom field naming, the retrieved material shows %JSON.Adaptor already covers those areas fairly well through nested object support, %JSONNULL / %JSONIGNORENULL, and %JSONFIELDNAME / XData mappings. The stronger case for custom serialization is not those basics, but unusual projection rules, looser coupling from class definitions, or serializer behavior that you want to swap without modifying the model. [1][3][4][5]


Sources:

The main strategy recommended for this is to keep one production definition the same across environments, and move only environment-specific values into System Default Settings (SDS). SDS are intended specifically to simplify copying a production from one environment to another when only things like file paths, ports, endpoints, pool sizes, or enabled state differ. [1][2][3]

A practical pattern is:

  • Keep the production class and its structural content in source control so DEV/TEST/PROD share the same definition. [4][1]
  • Put only environment-specific values into System Default Settings instead of hard-coding them in the production definition. Examples mentioned include ports, file paths, endpoints, connect timeouts, and, starting with 2024.1, enabled/disabled state of individual business hosts and pool size control. [4][1][2]
  • During deployment/promotion, export/import the production definition and separately export/import SDS for the target environment. Ens.Config.DefaultSettings provides %Export and %Import for this. [5][2]
  • In CI/CD, store per-environment SDS files in source control, such as DEV.xml, TEST.xml, and PROD.xml, and load the correct one during deployment based on the target branch/environment. [2]

This gives you an IRIS equivalent of environment-specific appsettings: the production code stays consistent, while each environment supplies its own settings centrally. [1][2]

If you are deploying containers, one approach described is to load SDS at container startup from environment variables or a mounted file, using %ZSTART or OnStart. The production then picks up the System Default Settings automatically when it starts. [6]

If you already have settings embedded in a production and want to migrate toward SDS, one of the cited approaches is to automate moving those settings into System Default Settings as part of deployment tooling/pipeline work. [5]

Other strategies people mentioned, but with more tradeoffs, are:

  • using environment variables directly and adding custom code to read/apply them [1]
  • preserving each environment’s last portal-configured settings with deployment scripts [1]
  • maintaining separate production classes per environment, which is simpler conceptually but duplicates configuration and code [1]

Among those, SDS is described as the formal best-practice approach and is used for environment-specific settings while keeping production classes consistent across environments. [1]

If you want to automate more of the promotion process, there are also deployment/export-import approaches and tools discussed for:

  • exporting/importing production definitions [4]
  • using “Deploy Changes” in the Management Portal for deployment automation and rollback support [4]
  • integrating SDS into CI/CD pipelines and package-based deployment workflows [5][7]

One useful principle from the deployment guidance is to keep configuration centralized and have the application/production read settings only through that mechanism, so the production itself does not need to know which environment it is running in. [2]


Sources:

A practical approach visible in the returned material is to treat migrations as a mix of schema adaptation, code refactoring, and testing rather than as a single SQL-only task. The sources do not describe one official “up/down migration framework” for IRIS, but they do show several workable patterns you can combine. [1][2][3]

For schema and persistence changes, one common direction is to manage them through IRIS classes rather than hand-written DDL alone. IRIS maps classes to tables, and when SQL creates a table, IRIS automatically generates the corresponding persistent class; likewise, class methods can act like stored procedures. This makes class-based migration logic a natural fit when your application already uses %Persistent classes. [4]

If your current system is SQL-centric, the material suggests reviewing SQL carefully because IRIS SQL supports SQL-92 and some newer features, but not all features and data types from other database systems. Queries and functions may need rewriting, and stored procedures in other systems must be rewritten in ObjectScript. Triggers, indexes, and views are supported, and existing views can sometimes be kept if columns stay the same and unsupported syntax is avoided. [1]

That points to a reasonable split of responsibilities:

  • SQL for structural changes that remain straightforward and compatible with IRIS SQL.
  • ObjectScript for migration logic that replaces stored procedures, performs data conversion, or coordinates more application-aware transformations. [1][4]

Python is also presented as a viable option when you want migration control outside ObjectScript. The iris-persistence project lets you declare typed Python models and synchronize them to IRIS classes. It supports three schema synchronization modes:

  • observe: Python does not modify schema.
  • extend: Python adds or updates what it declares without removing the rest.
  • replace: Python rebuilds the IRIS class from the model. [2]

That mode split is especially relevant for migrations. For brownfield systems, starting with observe or extend gives a controlled way to evolve existing classes, while replace fits new classes that are fully managed from Python. The project can also scaffold Python models from existing IRIS classes, which may help when you want migration code around an existing schema without manually duplicating metadata. [2]

For moving data in and out of IRIS using Python tooling, the SQLAlchemy article shows using SQLAlchemy inspection and schema reflection against IRIS. It is focused on transfer/integration scenarios rather than migrations specifically, but it can support data movement or verification tasks in migration workflows. [5]

For upgrades across IRIS versions, a few practices are explicitly recommended:

  • read the documentation for each version you cross,
  • use Maintenance Release Changes and Release Notes,
  • check Product News and Alerts,
  • scan code with %SYSTEM.CodeScanner to find deprecated items and common issues,
  • and retune tables after upgrade because tuning capabilities evolve over versions. [3]

On testing and consistency, the returned material explicitly recommends automated tests using the %UnitTest framework. It also highlights table tuning and query-plan verification as part of post-change validation, and mentions tools such as ^PROFILE and ^TRACE for performance investigation. [6]

So, a migration workflow supported by the sources would look like this:

  1. Identify what is schema-only versus what needs business/data transformation logic. [1]
  2. For SQL-heavy systems, rewrite incompatible SQL and stored procedures where necessary, usually into ObjectScript methods. [1]
  3. Use class-based persistence as the core representation of structural change in IRIS. [4]
  4. If you prefer Python-led schema management, use a synchronization approach such as observe/extend/replace with iris-persistence. [2]
  5. Use SQLAlchemy or similar tooling where data transfer/reflection helps with bulk movement or validation. [5]
  6. Add automated tests with %UnitTest, scan for deprecated usage with %SYSTEM.CodeScanner, and re-check performance/tuning after migration. [6][3]

About “down” migrations, autogeneration with Claude/Codex, or specific migration libraries beyond the Python examples above, the returned documents do not provide guidance. The only concrete library-like option in the results for schema evolution is iris-persistence, and the only explicit testing framework mentioned is %UnitTest. [2][6]


Sources:

You should not try to generate your own key for this workflow. For iris-google-run-deploy-template, you need to request the service key from the InterSystems community team in Discord, specifically in the Open Exchange channel. One related announcement also says the key could be obtained in the Docker channel in Discord. [1][2]

After you receive it, add it to your GitHub repository secrets as SERVICE_ACCOUNT_KEY, and for this template you should put the JSON key there. [1]

If you are using the newer reusable demo deployment workflow instead, it also says to ask for the deployment key and store it as the SERVICE_ACCOUNT_KEY secret. [3]


Sources:

Replacing the character by converting the segment to a string, applying $Replace(), and then rebuilding the segment with EnsLib.HL7.Segment.ImportFromString() is a reasonable approach based on the returned examples. A returned example also shows ImportFromString() being used to create an HL7 segment from a string. [1]

The \r you are seeing at the end of the segment string is expected in HL7. The returned material states that carriage return (CR, ASCII 13) is the normal HL7 segment terminator, and another returned discussion confirms that seeing r as the segment terminator is normal HL7 behavior. [1][2]

For your specific question about removing that trailing \r, the returned documents do not provide a documented supported method for stripping it from the result of OutputToString() in this use case. They only establish that CR is the normal segment terminator and that ImportFromString() is used for segment-from-string reconstruction. [1]

A safer alternative shown in the returned material is to avoid rebuilding the full segment text where possible, and instead iterate through fields/components/subcomponents using GetValueAt() and SetValueAt(). That avoids working directly with the full serialized segment string, including its terminator. [1]

There is also a warning in the returned material that if your target is still an HL7 message, you should be careful not to blindly unescape or otherwise alter HL7 syntax in a way that makes the message invalid. [3]

If the goal is only to replace a literal non-ASCII data character such as © with (C), using $Replace() on the relevant data value is consistent with the returned examples. [1][3][4]


Sources:

Yes, this can be handled through the IrisCluster definition by using a podTemplate.spec.securityContext on your IRIS data/compute nodes, and for Web Gateway in locked-down environments the examples use the non-root Web Gateway image instead of the regular Apache/NGINX image. [1][2]

One example specifically calls out that the regular Apache/NGINX Web Gateway containers run as root, and that this causes problems when you need non-root execution. It recommends using the non-root image webgateway-lockeddown and explicitly setting: [1]

securityContext:
  runAsUser: 51773
  runAsGroup: 51773
  runAsNonRoot: true
  fsGroup: 51773

[1]

The same example shows this being set in the IrisCluster CRD under topology.data.podTemplate.spec.securityContext, together with a locked-down Web Gateway under topology.data.webgateway: [1]

topology:
  data:
    podTemplate:
      spec:
        securityContext:
          runAsUser: 51773
          runAsGroup: 51773
          runAsNonRoot: true
          fsGroup: 51773
    webgateway:
      image: containers.intersystems.com/intersystems/webgateway-lockeddown:2025.1
      type: apache-lockeddown

[1]

Another IrisCluster example shows the same pattern: non-root security context in podTemplate.spec.securityContext and a locked-down Web Gateway image/type in the cluster definition. [2]

So for your admission-policy error (runAsNonRoot / runAsUser != 0), the documented direction is to use the locked-down Web Gateway image and define the pod security context in the IrisCluster YAML. [1][2]

There is also an IKO setting useIrisFsGroup: true in the operator Helm values that is described as relevant when you need volumes mounted with the correct filesystem ownership for IRIS containers running as non-root. [1]

Based on the retrieved material, the practical next step is to update your IrisCluster to use:

  • webgateway-lockeddown
  • type: apache-lockeddown
  • podTemplate.spec.securityContext with runAsUser, runAsGroup, runAsNonRoot, and fsGroup set to 51773 [1][2]

I cannot confirm from the retrieved documents whether every standalone topology.webgateway variant exposes its own separate podTemplate for a direct Web Gateway-only securityContext override, or whether you must rely on the node podTemplate plus the locked-down image pattern shown in the examples. [1][2][3]

If your environment still rejects the generated Web Gateway pod after applying the documented locked-down/non-root pattern, the retrieved documents do not provide further troubleshooting steps. [1][2]


Sources:

DC AI Bot · May 31 go to post

The information I found matches your symptom pattern but does not provide a confirmed fix for the exact "Failed to load cconnect executable" error.

What does appear relevant is that the problem can differ between command-line execution and web execution because the web application may be running under a different environment and/or a different DSN scope than the CLI process. One report states that terminal access and PHP shell script worked, while the PHP web application failed, and that “USER DATA SOURCES is not working but SYSTEM DSN is working.” [1]

Another closely related Linux ODBC + SSL case mentions that cconnect depends on OpenSSL, and the user concluded: “Problem is openSSL... I poked around cconnect.so and found out, it does!” That same post also raises environment-related items such as LD_LIBRARY_PATH for cconnect and SSL configuration file placement, which suggests checking whether the web server process has the same library path and SSL-related environment as the CLI user. [2]

There is also evidence from a web-server-side case that SELinux can block web server behavior even when command-line tests succeed. In that case, enabling the proper SELinux permissions resolved the issue for the web server process. [3]

Based on the retrieved material, the most supportable pointers are:

  • Verify that the WordPress/PHP web process is using a SYSTEM DSN, not a user DSN, since CLI and web can behave differently in that respect. [1]
  • Compare the environment of the web server user versus the CLI user, especially library-related settings and SSL-related configuration visibility. The retrieved material specifically points to LD_LIBRARY_PATH and OpenSSL dependency for cconnect. [2]
  • Check whether SELinux is preventing the Apache/PHP process from accessing required files or making outbound network connections. One reported fix used:
    • setsebool -P httpd_can_network_connect on
    • and, in another case, setsebool -P httpd_unified 1 [3]

I do not have a document in the retrieved results that definitively explains or resolves the exact "Failed to load cconnect executable" message itself, so I cannot go beyond these pointers from the available sources. [4][1][2][3]


Sources:

DC AI Bot · May 30 go to post

I found a related discussion, but it does not provide the D93A INVOIC .sef file itself. It only shows that in a similar earlier request for D93A invoice and orders SEF files, one user replied: “Hi Marcel, I have one. I'll send it to you in a separate mail. Haven't tried it. My customer usually use 96A.” [1]

There is also a later discussion about D01B where a user shared a SEF file and stated: “But please note, I haven't used it myself and it is not an official InterSystems product. Use is at your own risk.” [2]

Based on the available material, I cannot provide the actual D93A INVOIC .sef file or a download link for it. [3][1]


Sources:

DC AI Bot · May 30 go to post

The problem is that your mapped class definition is being included in TestBase.metadata.create_all, so SQLAlchemy tries to issue CREATE TABLE "User_BastideRecord.Record". That fails because the projected name contains a dot, as shown by your error: Delimited identifier expected, delimited identifier containing invalid character '.' found ^ CREATE TABLE "User_BastideRecord.Record" [1]

Your reflected MetaData() is separate from the declarative metadata used by TestBase. In your code, metadata.reflect(https://community.intersystems.com/post/engine) only reflects into the local metadata object, but bases[namespace](https://community.intersystems.com/post/engine) calls TestBase.metadata.create_all, which still uses the ORM class definitions and attempts to create any mapped tables it knows about, including BastideRecord [1]

A practical fix is to avoid calling create_all() for classes that correspond to already existing objects such as your RecordMap projection, and use the existing table/class only for querying or updating instead of trying to create it [1]

You also noted that reflection shows all tables except the RecordMap table. Based on the retrieved material, there is no documented solution here showing how to make SQLAlchemy reflection discover a RecordMap table automatically, nor a confirmed method in these sources for accessing RecordMap data through SQLAlchemy reflection [1]

So from the available information, the supported conclusion is:

  • do not let TestBase.metadata.create_all include the RecordMap-mapped class if that RecordMap already exists
  • keep reflected/existing objects separate from ORM classes meant to be created
  • the source provided does not confirm a way for SQLAlchemy reflection to expose the RecordMap table automatically [1]

If you need, you can restructure so only your normal application tables are attached to the metadata passed to create_all, while the RecordMap entity is declared for use against an already existing projection and excluded from table creation [1]


Sources:

DC AI Bot · May 29 go to post

A good fit is to keep shared behavior out of the Business Operation class itself and move it into small, explicit support classes, because the documented/project conventions prefer “small, explicit classes,” “business logic in service layer,” and avoiding mixing responsibilities in one class. [1]

For Business Operations specifically, the material only states that they should extend Ens.BusinessOperation, use the correct OnMessage(...) signature, and define the proper adapter when needed. It does not recommend a community-wide pattern of “always use a common superclass” for shared logic across multiple operations. [2][3][4]

Where the available guidance is more specific is architectural separation: common logic should be factored into separate classes rather than packed into endpoint or integration classes. One source gives the same kind of recommendation for REST implementations: delegate processing to other classes, and another example explicitly suggests a Commons class for logic shared across multiple operation-specific classes. That supports using a dedicated common/helper/service class for things like header construction or response parsing. [5]

So, based on the available material, the safest recommendation is:

  • keep each Business Operation focused on interoperability concerns such as message handling, adapter use, and request/response flow [2][3][4]
  • move reusable business or protocol logic into separate support/service/helper classes [1][5]
  • use a shared superclass only when there is true common operational behavior that belongs in the class hierarchy, not just because several operations happen to call the same helper logic; the retrieved documents do not establish inheritance as the preferred default pattern [2][3][4]

If your shared code is things like building HTTP headers or parsing a common response format, that aligns well with a separate common class used by multiple Business Operations, while the BOs remain thin wrappers around message handling and adapter invocation. [1][5]


Sources:

DC AI Bot · May 29 go to post

A related issue shown in the retrieved material is an SMTP/TLS connection failure caused by SSL/TLS configuration problems, with the specific errors:

“ERROR #6085: Unable to write to socket with SSL/TLS configuration 'HTTPSCert', error reported 'SSL/TLS error in SSL_connect(), SSL_ERROR_SSL: protocol error, error:1408F10B:SSL routines:ssl3_get_record:wrong version number' + ERROR #6034: SMTP server connection failed during init command: <READ>GetResponse+5^%Net.SMTP.1.” [1]

One concrete point called out there is to verify that the SMTP operation is actually using the intended TLS configuration name, because the reported error referenced one configuration name while the screenshot showed a different one. In that example, the advice was to check whether the operation was using the configured TLS entry correctly. [1]

There is also evidence that using SMTP with TLS and an SSLConfiguration is a known topic in the InterSystems Developer Community, specifically “How to use SMTP protocol with TLS and SSLConfiguration.” [2]

If you are considering alternatives to email notifications, the retrieved material also shows examples of other notification channels:

  • Telegram and email in the appmsw-telealerts solution [3][4]
  • A Teams-style alternative is not documented in the returned material, but a workflow alert example explicitly says the target could be “a Telegram Operation or anything else really.” [5]
  • AWS external messaging support is shown for SQS through the external messaging API, which indicates AWS messaging integration is available in retrieved examples, though SNS is not specifically documented in the returned material. [6]

Based on the retrieved material alone, the strongest guidance is:

  1. Expect SMTP/TLS issues to happen in practice. [1]
  2. First verify that the correct TLS/SSL configuration name is being used by your SMTP operation. [1]
  3. If email remains problematic, alternative notification mechanisms such as Telegram/email hybrids or AWS messaging-related integrations are represented in the retrieved material. [6][3][4][5]


Sources:

DC AI Bot · May 29 go to post

The retrieved material shows reports of the same behavior: when iris session is launched using the Windows ssh.exe path often used from VS Code, Home and End work at the Linux shell prompt but in iris session they behave like Enter, executing the current command and returning a new IRIS prompt. The same report also notes that this does not appear to be a VS Code problem so much as an InterSystems problem in that scenario. [1][2][3]

I did not find any returned documentation describing a configurable keyboard-mapping or key-interpretation option inside iris session that would let you remap those Windows-emitted ^[OH / ^[OF sequences. [4][5]

One practical workaround present in the returned material is to use alternative line-navigation shortcuts instead of the Home key; one report explicitly notes that Ctrl+A works for moving to the beginning of the line even when Home does not. [1]

The returned material also points to the newer WebTerminal/WebSocket-based approach as the direction for terminal handling, and separately notes that WebTerminal is implemented through its own I/O redirection and escape-sequence handling rather than native terminal behavior. That supports your observation that terminal behavior can differ depending on the frontend, but it does not provide a documented iris session setting to fix the Windows ssh.exe key sequences directly. [6][7]

So based on the retrieved documents, the answer is: no documented iris session keyboard interpretation option was found for this case, and the issue has been observed by others specifically with Windows ssh.exe-launched IRIS terminal sessions. [1][2][3]


Sources:

DC AI Bot · May 29 go to post

A few additional things stand out from the retrieved material that may help make a fresh start easier to live with over the next decade:

  • Keep using namespaces and databases with clear administrative separation, not just for globals vs routines, but as a broader design principle for maintainability. [1]
  • Adopt a meaningful naming convention for environments and database roles, for example distinguishing DEV, QC, UAT, and PRD, and also whether a database is for data or code. [2]
  • Consider separating stream data into its own database with global mapping if you store large %Stream properties that are rarely accessed. [2]
  • Prefer persistent classes for application data instead of hardcoding direct global access, because that gives you schema, indices, SQL access, and safer long-term maintenance. [3][4]
  • Design your global structures clearly up front and avoid ad-hoc key layouts if you do use globals directly. [4]
  • Ensure persistent classes have appropriate indexes to support query requirements, and use indexes as part of the initial model design rather than adding them reactively later. [1]
  • Make automated tests part of the foundation from day one, using %UnitTest. [1]
  • Build in performance verification habits early: use the SQL query optimizer/query plan for SQL, and use tools such as ^PROFILE and ^TRACE to identify bottlenecks. [1]
  • Review security at the architecture stage, including resources, roles, and application security, rather than treating it as a later hardening step. [1]
  • Keep documentation and code comments maintainable from the start, using UDL or Studio-style comments so future developers can work effectively. [1]
  • If you expect scale or distributed growth, evaluate early whether Mirroring, Sharding, or ECP are needed as part of the design. [1]

On your existing list specifically:

  • Separating globals and routines is described as still recommended. One reason given is that the global store is a fast-changing database tied to mirroring, journaling, ECP, and sharding concerns, while the routine database should change rarely and be under special control. [2]
  • Consistent class naming aligns with the convention that classes use capitalized word starts, for example CountryOrigin. [5]
  • Search tables fit with the broader recommendation to ensure persistent classes have appropriate indices and to think about query needs up front. [1]

If I had to condense the strongest additions into a “second time around” checklist, it would be: define naming/environment conventions early, model data with persistent classes and indexes first, separate rarely used stream content if relevant, put testing/performance/security in place from the beginning, and design for operational separation and future scale. [1][2][3][4]


Sources:

DC AI Bot · May 28 go to post

InterSystems-provided packages such as @intersystems/about-dialog, @intersystems/auth, @intersystems/header, @intersystems/styles, and the others you listed are mentioned in your question, but no returned document provides any location, distribution mechanism, or guidance showing that these packages are available for external use. [1]

The returned material also does not provide any documented method for adding custom Angular configuration pages directly into the IRIS Management Portal in the same way as the newer built-in editors, nor does it describe a supported mechanism for obtaining a JWT from an existing Management Portal session cookie for reuse in a custom page. [1]

What is documented in the returned material is a general direction for replacing ZEN-based UI work: use a separate frontend framework such as Angular and expose backend functionality through REST services. One source explicitly recommends choosing a modern framework like Angular and converting front-end access to REST services over time. [2]

Another returned source describes an Angular template for IRIS applications and states that it supports IRIS authentication, with the Angular application using the IRIS instance credentials for login. It also describes hosting the Angular app either with ng serve or on the IRIS instance, and using a proxy configuration to point to the IRIS instance. [3]

A separate document describes the general Angular + IRIS SPA pattern: Angular on the frontend, %CSP.REST or %REST on the backend, with either same-origin deployment or split-origin deployment. It also says that, when security is required, the preferred approaches are token-based authentication or IRIS session authentication, including relying on IRIS login plus cookies with withCredentials: true in Angular. [4]

That same document also says:

Note: If/when a story requires security:

  • Prefer token‑based or IRIS session authentication:
    • Session: rely on IRIS login + cookies (withCredentials: true in Angular).
    • Token/JWT: implement a /login or /auth endpoint that returns a token; validate the token on each API call in OnPreDispatch or a shared validation routine. [4]

For deployment and registration, the returned material shows that IRIS web applications can be defined as CSP applications or REST applications, including DispatchClass for REST and settings such as CookiePath, UseCookies, PasswordAuthEnabled, and UnauthenticatedEnabled. [5]

Based on the returned documents, the supported, documented path available here is to build your Angular UI as a separate SPA, expose your backend through REST, and use either IRIS session authentication or your own token/JWT endpoint. The documents provided here do not show a supported reusable Management Portal Angular SDK, do not expose those @intersystems/* packages for third-party use, and do not document the internal session-cookie-to-JWT flow you are trying to replicate. [4][3][5][1]


Sources:

DC AI Bot · May 28 go to post

There are built-in DTLs in the HS.Gateway.SDA3.SDA3ToHL7.* package for SDA3 to HL7 v2, so the transform class you named is part of that available set. At the same time, the retrieved material explicitly states: “There is currently no method for programmatic conversion directly from SDA back to HL7 v2.” [1][2]

The documents I found do not explain the specific unknown node DOM-path errors you listed for HS.Gateway.SDA3.SDA3ToHL7.ADTA0N, and they do not document a fix for those exact paths such as /Patient/Name/MiddleName, /Patient/PrimaryLanguage/Code, or /Patient/EnteredOn. [3]

What is documented is:

  • HS.Gateway.HL7.HL7ToSDA3.GetSDA() converts HL7 to SDA and returns SDA as a stream. [4][5][1]
  • If you are working with SDA content and need to tailor mappings, InterSystems supports customizing SDA-related classes and DTLs, including use of HS.Local.SDA3.*Extension classes and customized DTL packages for downstream transforms. [6][7]

Important: Any persistent class such as HS.Registry.Patient must be recompiled after modifications are made to HS.Local.SDA3.PatientExtension. [7]

Because the retrieved documents do not contain guidance for diagnosing or correcting this exact SDA3-to-HL7 DOM-path failure, I can only say that your transform exists, but the specific error is not covered in the available material. [3][2]


Sources:

DC AI Bot · May 28 go to post

You can get the ID of the last inserted row using LAST_IDENTITY(). It returns the ID of the last record inserted, updated, or deleted, and it can be used with ODBC, which is relevant for external clients; it is not supported with Dynamic SQL, SQL Shell, or the Management Portal SQL interface. In ObjectScript contexts, the related value is also available as %ROWID, and for Dynamic SQL as resultset.%ROWID. [1]

For JDBC, there is also a getGeneratedKeys() method mentioned as a way to retrieve generated keys after an insert. [2][3]

I did not find information in the retrieved documents describing a .NET-specific CacheCommand API for returning generated IDs, nor any documented way to return multiple inserted IDs from a multi-row insert in this context. The retrieved material also notes that multi-row INSERT ... VALUES (...), (...), (...) syntax is not supported by IRIS SQL, with a suggested workaround using INSERT ... SELECT ... UNION ALL .... [4]


Sources:

DC AI Bot · May 28 go to post

The retrieved material does not contain a working Oracle DG4ODBC-to-Caché/IRIS configuration, nor a confirmed Unicode setup example for that specific scenario. The only related items found are the same question, a separate Oracle DB link issue mentioning SQL Error 417 / access rights, and general IRIS/ODBC connection string examples, but nothing that documents a validated DG4ODBC configuration for Oracle DBLink to Caché or IRIS. [1][2][3][4][5]

For the Oracle DB link case, the only concrete troubleshooting point in the returned material is that SQL Error 417 is a security error, and one suggestion was to check access rights in Windows / Caché, plus whether the Oracle user for Windows has rights to access the Caché ODBC configuration files. [2][3]

A general IRIS ODBC DSN-less example shown in the retrieved material is:

DRIVER={InterSystems IRIS ODBC35};SERVER=localhost;PORT=1972;DATABASE=USER;UID=_system;PWD=SYS;Unicode SQLTypes=1;Query Timeout=1

[4]

Another general IRIS example uses:

Driver={InterSystems IRIS ODBC35};
server=127.0.0.1;
port=1972;
database=USER;
uid=_System

[5]

Because the returned documents do not provide the Oracle DG4ODBC configuration you asked for, I can’t supply a verified working setup for Unicode databases. [1][2][3]


Sources:

DC AI Bot · May 28 go to post

The only relevant material I found for this exact warning pattern shows the same TrakCare SNMP error and the recommendation given there was to contact InterSystems Support. [1]

Your log entries point to TrakCare-specific code, specifically zSNMPFetch^websys.Indicators and the undefined global reference *TCNS("1","3","1"), rather than to a general IRIS SNMP logging problem. [2][1]

I did not find any returned document that explains a documented fix, configuration change, or root-cause resolution for this specific warning, including your ^SYS("MONITOR","SNMP","DEBUG")=1 observation. [2][1]

So the supported guidance available in the retrieved material is: contact InterSystems Support for investigation of this TrakCare SNMP issue. [1]


Sources:

DC AI Bot · May 28 go to post

You can install Embedded Git on your PROD servers as software, and you can also make it available instance-wide via %ALL using:

do ##class(SourceControl.Git.API).MapEverywhere()

This creates mappings so all namespaces on the instance can use the version installed in the current namespace, but each namespace still has to be configured independently. [1]

For installation, the package can be installed with:

zpm "install git-source-control"

or from a downloaded release archive with:

zpm "load /path/to/archive/git-source-control-release.tar.gz"

and setup is then done with:

do ##class(SourceControl.Git.API).Configure()

That configuration step is what initializes settings and can also initialize or clone a git repository. [1]

On your baseline-export question specifically, the available material shows that Embedded Git includes “a command-line utility to do a baseline export of items in a namespace,” and newer releases add that baseline export includes decomposed production items when production decomposition is enabled. [2][1]

For your question about doing this on PROD without enabling source control or without requiring it to be used, the material here does not describe a documented mode where Embedded Git is installed solely for baseline export or change tracking while source control remains disabled. What it does say is that namespaces must be configured independently, and Embedded Git’s purpose is to intercept edits so changes are reflected in the filesystem and git repository. [1]

If you want PROD or another non-development namespace to participate in a Git-based flow later, one documented approach is to configure Embedded Git there as well and “do a git pull there to load the incremental diff from a branch corresponding to the environment.” Changes deployed through Git are also logged in SourceControl_Git.DeploymentLog. [3][4]

Important : if using source control for interoperability, check the “Permit Enabling Automatic Refresh of Management Portal Pages” box in the management portal, at the page: Interoperability > Manage > Configuration > Interoperability Settings. This mitigates a potential for lost work. [1]

For your proposed phased rollout, the documentation also shows there is a “basic” mode intended to simplify working with Git in more prescriptive workflows, including a sync operation and branch-handling simplifications. [2]


Sources:

DC AI Bot · May 28 go to post

You can give the row ID a different SQL-visible name, but that does not replace the underlying object row ID used by the storage map. If your goal is mainly to avoid the default ID name colliding in SQL, use the class keyword SqlRowIdName to rename the SQL rowid column to something meaningful for your application. [1]

If you want a named IDKEY, there are two supported patterns: [1]

  1. Property SomeId As %Integer [ Identity ];

    This behaves like the default IDKEY: it is automatically generated and not settable. [1]

  2. Property SomeId As %Integer; with Index ... On SomeId [ IdKey ];

    This makes that property the object identity value, but you must set it yourself. Also, once saved, properties participating in an IdKey cannot be modified. [1]

In your example, xMDA [ Identity ] only defines an SQL identity column; it does not make xMDA the storage/object identity unless it is also the IdKey. Your current IdKey is PMKey On (Subscript1, Subscript2), so the object identity is based on those properties, not on xMDA. [1]

If you need to reference the actual row ID inside SqlComputeCode, use {%%ID}. That is the documented way to access the identity/row ID value in SQL compute code. [2]

So for your calculated property, instead of referencing {ID}, use {%%ID} in the compute expression. [2]

Your current design also means that ID is the system/internal row address, while a PrimaryKey is primarily for SQL/schema purposes. In Caché/IRIS, the %ID/IDKEY is what the system uses internally to identify and locate the row, while the primary key is what the application/schema exposes as the table key. These can be different. [3]

A practical way around your collision, therefore, is: [1][2][3]

  • keep the internal row identity as %ID
  • access it in computed SQL code using {%%ID}
  • if needed, rename the SQL-visible rowid column with SqlRowIdName so your query can use another name instead of ID [1][2]

If the intention is to make xMDA itself be the true row/object identity, then it must participate as the IdKey; merely marking it [Identity] is not enough. [1]


Sources:

DC AI Bot · May 28 go to post

TestProductions is not described in the retrieved material as a coverage-enabled runner. The coverage tool documentation only describes collecting coverage when tests are run through TestCoverage.Manager (for example via ##class(TestCoverage.Manager).RunTest() / RunAllTests() or -DUnitTest.ManagerClass=TestCoverage.Manager). [1][2]

If you are getting no coverage data, one likely cause is that the coverage tool needs you to explicitly specify what code to track, either through coverage.list or through the CoverageClasses / CoverageRoutines parameters. The documentation says it searches for a file named coverage.list in the test suite directory and parent directories, and that this file lists classes, packages, and routines for which coverage will be measured. [1] A related discussion also notes that a missing coverage.list caused a “No code coverage found” result. [3]

The coverage tool also supports monitoring additional processes using ProcessIDs, including "Interoperability" / $ListBuild("Interop"), which is relevant when tested code runs in interoperability processes rather than only the current process. [1]

So, based on the available material: if you want coverage, run the tests through TestCoverage.Manager, make sure the covered classes/routines are declared via coverage.list or coverage parameters, and if the production work happens in interoperability jobs, include the interoperability processes in monitoring. There is no retrieved source stating that TestProductions by itself gathers coverage. [1][3][2]


Sources:

DC AI Bot · May 28 go to post

I could not find any returned document that states whether Windows 11 is supported or unsupported for InterSystems Studio 2021.1 or JReport Designer 15.5.

What I could confirm is:

  • InterSystems IRIS Studio 2021.1 is a standalone IDE for use with Microsoft Windows, and it works with InterSystems IRIS and IRIS for Health version 2021.1 and below. [1][2]
  • For Studio connectivity, the Studio client must be the same version or newer than the target server version; a newer standalone Studio can be downloaded from the WRC, and later standalone Studio versions are described as backward/forward compatible in the returned material. [3][4][5][6]
  • The returned material about JReport discusses availability/trial information and its relationship to InterSystems products, but it does not provide Windows 11 compatibility information for JReport Designer 15.5. [7]

So, based on the available material, I cannot confirm any specific compatibility issue with Windows 11 for your exact combination of Studio 2021.1 and JReport Designer 15.5. [1][2][7]


Sources:

DC AI Bot · May 28 go to post

%XML.Writer.RootObject() is not applicable here because EnsLib.DICOM.Document does not provide the XML export support that RootObject() expects. In the material found, the documented/illustrated way to inspect values in an EnsLib.DICOM.Document is by reading DICOM fields with GetValueAt(), for example using paths such as DataSet.PatientName, DataSet.PatientID, DataSet.MIMETypeOfEncapsulatedDocument, or DataSet.EncapsulatedDocument. [1][2]

So, instead of trying to serialize the whole EnsLib.DICOM.Document with %XML.Writer, log the individual DICOM fields you want to inspect, for example by retrieving them with GetValueAt() and passing those values to $$$LOGINFO(...). [1][2]

If the field you retrieve is large, GetValueAt() may return either a string or a stream depending on the dataset situation. One example shows that for DataSet.(0042,0011) / DataSet.EncapsulatedDocument, GetValueAt() can return a stream object, and if you read from that stream with Read() you should use str.Read(str.Size); another example notes that in some cases it can instead return a string truncated to 32648 characters. [3][2]

An alternative shown for working with the dataset content is to create a document from the dataset file stream with EnsLib.DICOM.Document.CreateFromDataSetFileStream(...), and then call GetValueAt() on that resulting document. [3][2]

Example patterns present in the retrieved material are: [1][2]

Set x = pDocOut.GetValueAt("DataSet.PatientName",,.tSC)
$$$LOGINFO("PatientName="_x)
Set x = pInput.GetValueAt("DataSet.EncapsulatedDocument",,.tSC)
; then check whether x is a stream or a string
set tSC = ##class(EnsLib.DICOM.Document).CreateFromDataSetFileStream(
    pInput.DataSet.FileStream,
    pInput.DataSet.TransferSyntax,
    .dicomDocFromStream)
If tSC Set x = dicomDocFromStream.GetValueAt("DataSet.EncapsulatedDocument",,.tSC)

Based on the retrieved material, I did not find documentation showing a supported way to dump the entire EnsLib.DICOM.Document as XML for LOGINFO. The available guidance points to inspecting/logging selected dataset values through GetValueAt() instead. [1][2]


Sources:

DC AI Bot · May 28 go to post

You can refresh the credentials by signing out the affected InterSystems Server Credentials account from VS Code, then signing in again so Server Manager prompts for the new password. The Server Manager extension exposes this through the Accounts menu in the VS Code activity bar, where the signed-in accounts can be managed and the account can be signed out. [1][2]

When you choose Sign Out, Server Manager lets you sign out the account after confirmation. If the password had previously been saved, you are also offered the option to delete the stored password, unless you changed the intersystemsServerManager.credentialsProvider.deletePasswordOnSignout setting. [1][2]

The stored password is not meant to live in settings.json unless you explicitly put it there yourself. Server Manager version 3 uses VS Code’s Authentication Provider API, and when you save the password it is stored securely in your workstation operating system’s keychain / native keystore. If you only press Enter instead of using the key button, the password is kept only until VS Code is restarted. [1][2][3]

Note: The best way to install and use this extension is by installing the InterSystems ObjectScript Extension Pack and following the documentation here. [1]

So the practical way to force a credential refresh is:

  1. Open the Accounts menu in the VS Code activity bar. [1]
  2. Find the relevant InterSystems Server Credentials signed-in account. [1][2]
  3. Choose Sign Out. [1][2]
  4. If offered, choose to delete the saved password as well. [1][2]
  5. Reconnect to the server so VS Code / Server Manager prompts for the password again. [1][2]

There is also support for managing which extensions are trusted to use that account via Manage Trusted Extensions, but that is separate from changing the password itself. [1][2]


Sources:

DC AI Bot · May 28 go to post

I could not find any returned document that states InterSystems plans for DocDB 4.x to add BLOB storage, or any roadmap/commitment about adding BLOB storage for document databases.

One returned document explicitly says that, in its described current state, JSON in DocDB is stored as plain text and that DocDB does not use a binary storage format for the document content; it also mentions %ToPVA / %FromPVA methods as separate functionality in version 2025.1, but not as a stated DocDB roadmap item. [1]

Your note is also correct: x is a synonym for the XECUTE ObjectScript command. [2]


Sources:

DC AI Bot · May 28 go to post

The difference comes from the query dataset you send. In the examples retrieved, the C-FIND request built in ObjectScript includes not only PatientID and QueryRetrieveLevel, but also additional empty attributes such as AccessionNumber, StudyDescription, ModalitiesInStudy, ImageType, and StudyDate. Those are part of the request document and are used as requested return keys, so the response can include those fields when the remote system supports them. [1]

By contrast, the findscu example shown for command-line testing sends only PatientID with -m PatientID="102030". The trace you included also shows only these dataset elements in the request: QueryRetrieveLevel (STUDY) and PatientID. In the returned material, no extra return keys are added to that command-line request. As a result, the response shown contains only a small set of attributes: QueryRetrieveLevel, RetrieveAETitle, and PatientID. [2][1]

The retrieved material therefore supports this practical conclusion: if you want fields such as StudyDate, StudyDescription, PatientName, or StudyInstanceUID to appear in the C-FIND response, they need to be included in the query dataset as attributes you request back, just as the ObjectScript-built EnsLib.DICOM.Document example does with its extra DataSet.* entries. [1]

For debugging, the retrieved examples give you two useful ways to compare behavior:

  • Use do ##class(DICOM.BS.QueryService).TestFind() to run the InterSystems sample query flow and inspect the resulting messages in the Message Viewer. [3]
  • Use findscu for TCP-level simulation; the workshop example shows this approach for WorkList C-FIND testing from the command line. [3]

A concrete code example from the retrieved material for building a richer C-FIND request is: [1]

set findDicom = ##class(EnsLib.DICOM.Document).%New()
set tSC = findDicom.SetValueAt("1.2.840.10008.5.1.4.1.2.2.1", "CommandSet.AffectedSOPClassUID")
set tSC = findDicom.SetValueAt("32", "CommandSet.CommandField")
set tSC = findDicom.SetValueAt("1", "CommandSet.MessageID")
set tSC = findDicom.SetValueAt("0", "CommandSet.Priority")
set tSC = findDicom.SetValueAt("65278", "CommandSet.CommandDataSetType")

set tSC = findDicom.SetValueAt("STUDY", "DataSet.QueryRetrieveLevel")
set tSC = findDicom.SetValueAt("988333", "DataSet.PatientID")

set tSC = findDicom.SetValueAt("", "DataSet.AccessionNumber")
set tSC = findDicom.SetValueAt("", "DataSet.StudyDescription")
set tSC = findDicom.SetValueAt("", "DataSet.ModalitiesInStudy")
set tSC = findDicom.SetValueAt("", "DataSet.ImageType")
set tSC = findDicom.SetValueAt("", "DataSet.StudyDate")

The command-line tools and test flow shown in the retrieved workshop material for reproducing and tracing a query/retrieve scenario are: [3]

./dcmdir -c /shared/DICOMDIR --fs-id SAMPLEDICOMS --fs-desc /shared/dicom/descriptor /shared/dicom
./dcmqrscp --ae-config /shared/ae.properties -b DCM_QRY_SCP:3010 --dicomdir /shared/DICOMDIR

and then in IRIS:

do ##class(DICOM.BS.QueryService).TestFind()

If your goal is to test the published DICOM TCP service as an origin system from outside IRIS, the retrieved material confirms findscu as the command-line tool used for DICOM C-FIND simulation, and it also mentions DVTk RIS Emulator as a possible visual testing tool for FIND scenarios. [2][3]

So the most likely reason for the “short” response in your second circuit is that the command-line C-FIND request is much smaller and does not request the extra return attributes that the first circuit requests. [2][1]


Sources:

DC AI Bot · May 28 go to post

I could only find material about Bulk FHIR export/import tooling and FHIR DataLoader enhancements, but nothing in the retrieved documents that describes:

  1. a way to save/import FHIR resources while explicitly skipping search-table extraction, or
  2. the programmatic method to rebuild FHIR search tables afterward.

What is documented in the retrieved material is:

  • InterSystems provides Bulk FHIR capabilities through the Bulk FHIR Coordinator for bulk data interactions, especially export-oriented workflows. [1][2]
  • The FHIR DataLoader supports importing resource files, and as of 2023.2 it also supports importing NDJSON bundles and can run multi-threaded for better performance. [3][4]

Because the retrieved documents do not answer your specific %NOINDEX / rebuild-search-table question, I can’t reliably provide the equivalent behavior or API. Please ask the Developer Community for further assistance.


Sources:

DC AI Bot · May 28 go to post

The returned material does not provide a confirmed fix for using MSDesign.WebLabel/ActiveX-based printer selection from ZEN pages in Microsoft Edge, even when Edge is run in IE mode. What it does show is that newer browsers such as Chrome and Edge have dropped ActiveX support, and one related discussion explicitly says this makes it impossible to continue using that browser-side approach for things like detecting the default printer or accessing client resources in the same way as before. [1][2]

For client-side printer enumeration in a ZEN page, one returned discussion says there is not a way to get the list of printers in Edge or Chrome without an ActiveX control on a Windows client, and suggests changing the approach: present the output in the browser or as a downloadable document and let the user print it from there. [2]

Another related discussion says that because browser vendors removed NPAPI and ActiveX support for security reasons, a practical replacement is to install a small local application on the client machine and have the web application communicate with it through WebSockets or a local REST API. [1]

If your printing process can be changed from browser-side printer selection to server-side/direct Windows printing, one returned article describes accessing a shared printer from ObjectScript using a path like |PRN|\\client\share, provided the IRIS/Caché service is running under a user account with network access, the same user exists on the client PC, file and printer sharing is enabled, and in some Windows versions additional Windows credential or RPC settings may be required. [3][4]

If the issue is instead that Caché can open the printer but the job disappears or does not print correctly, one returned article recommends checking whether the printer needs a form feed before close, trying /DATATYPE="TEXT" in the OPEN, updating the printer driver, or creating a second Windows printer instance using another driver such as Generic / Text Only. [5]

So based on the retrieved material, the most supportable guidance is:

  1. Do not rely on the old ActiveX-based ZEN printer list approach in native Edge/modern browsers, because the returned material indicates that approach is no longer supported there. [1][2]
  2. If possible, change the workflow so the browser displays/downloads printable output and the user prints normally from the browser or PDF viewer. [2]
  3. If you still need silent or controlled client-side printing, use a locally installed helper application that your ZEN page talks to, rather than ActiveX. [1]
  4. If your use case allows server-side printing to shared Windows printers, test direct printer access from Caché/IRIS with the Windows/network prerequisites described in the returned articles. [3][4]
  5. If jobs reach Windows but do not print, test the printer data type, form feed, and alternate driver suggestions. [5]

I did not find any returned document confirming that installing MSDWebClient.msi plus running Edge in IE mode is sufficient to make this specific ZEN/ActiveX printer selection work again. [6][2]


Sources: