I see 2 options

#1) 

add the ChangeItem holding the last change in addition to your list of Objects.
and add the appiopriate indices.
like this:

Class Rick.ChangeList Extends %Persistent
{
  Property Title As %String;
  Property Changes As list Of Rick.ChangeItem;
/// Last change added to list
  Property Last As Rick.ChangeItem;
  Index xlast On Last.Change;
}

 

This looks simple but it requires that any program that adds a change also 
updates the "Last" property.
If this isn't feasible you may use %OnBeforeAddToSaveSet() or similar to insert you "Last" object during %Save().
It requires more space on disk and is not redundant.
It doesn't generate entries for existent records.This requires a special update exercise.

#2)

Add the property to be indexed as SqlComputed and index it.
This is not so speedy but gives you the flexibility not just check the last element
and has no impact or dependency on any existing code using it.

Class Rick.ChangeList Extends %Persistent
{
  Property Title As %String;
  Property Changes As list Of Rick.ChangeItem;
  Property lastDate As %TimeStamp [ Calculated, SqlComputed ,
          SqlComputeCode = { set {*} = ##class(Rick.ChangeList).ChangeDate({ID}) }];

Index xdate On lastDate [ Data = lastText ];
}
ClassMethod ChangeDate(ID As %Integer)
{
  set obj=##class(Rick.ChangeList).%OpenId(ID)    
     ,item=obj.Changes.GetAt(obj.Changes.Count())
   quit item.Change
}

what you describe sounds pretty much like code management, versioning.
these tools depend on appropriate plugins to Word, EXCEL, Eclipse, ....
to trap the SAVE in the appropriate "editor"

BUT this always means to have a specific piece of code installed on your client if you expect some "automatic" upload.
This thing may upload/download your documents over HTTP, WebSockets or whatever.

browsers should NEVER be allowed to access your local machine without manual confirmation.

#1)
authentication is switched on/off  in Mgmt Portal 
 System > Security Management > Web Applications and bound to the specific WebApplication

#2)​ 
CSP has typically a persistent %session object. 
You can that switch off by a Class parameter. 

#3) You have 2 typical places for private Classmethods:

OnPreHTTP() before anything goes back to browser or similar. 
You typically place your private authentication there.
http://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?P...
OnPage() which means when you have already replied with an HTTP header...

Some Example

Class csp.NoSession Extends %CSP.Page
{

/// This parameter controls the CSP session support. By default CSP will use a persistent session
/// which holds a license until the session is ended or times out. If you override this then this
/// CSP page will use a transient session which is never persisted.
Parameter UseSession As BOOLEAN = 0;

ClassMethod OnPage() As %Status
{
    &html<<html><head></head><body><pre>
    <h3> %session dump </h3>
 >
    zwrite %session
    write "<h3> %request dump </h3>",!
    zwrite %request
    write "<h3> %response dump </h3>",!
    zwrite %response
 &html<
 </pre></server></body></html>>
    Quit $$$OK
}

/// Event handler for <b>PreHTTP</b> event: this is invoked before
/// the HTTP headers for a CSP page have been sent. All changes to the
/// <class>%CSP.Response</class> class, such as adding cookies, HTTP headers,
/// setting the content type etc. must be made from within the OnPreHTTP() method.
/// Also changes to the state of the CSP application such as changing
/// %session.EndSession or %session.AppTimeout must be made within the OnPreHTTP() method.
/// It is prefered that changes to %session.Preserve are also made in the OnPreHTTP() method
/// as this is more efficient, although it is supported in any section of the page.
/// Return <b>0</b> to prevent <method>OnPage</method> from being called.
ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]
{
   
quit $$$OK
}

}
I found method GetJWT gets called with localpriv and localpub as parameters

ClassMethod GetJWK(JWKS As %DynamicObject, Alg As %String, Kid As %String) As %DynamicObject
{
 Set arr=JWKS.keys                ;line +1
 Set iter=arr.%GetIterator()      ;line +2

But there is no array keys  and no %DynamicArray object found. 
so it fails on  %GetIterator().

              my guess {"keys":[  .... ]}  could be the solution. 

w localpriv
{ "kty": "RSA"
, "n": "s0hguxNL5Xb6_Fk3u_fnZrUXuRnjj1wIEGXlsnqbu4rptiDYeX9dEQm29eDe5fhXWjrPtU33WA_zz0Y9R5z7EaX4ZlZG7PlFlm5vu3bEu-qeuMp8Xb3hPMyND-87JGrbB1t5i-BgMpjQoelhYT8iqzE1fEtUGYyNn2dhSwIVwqIaRt4ly65oyW9Ea7VL92kmCEgUmIn-lrEfvygfbEL2H-9dW42dAMvEwLCQGM7iX1zuHRAH9Ec9kwnaBb2kfHzoSJXZm5WcuPYJIWZrvu1RbHcZBFff0GwCDTH1bfECmr6c-6BPeeUMw6resnbM4v3dTrbKD64HQbC33x4_Xs3pTQ"
, "e": "AQAB"
, "d": "FVOizh45hQ5mROaIDsAqsrkQHWDLBR65htnYPScAp4qayqOVnL5d38z8Cru5SDoGiiE83CBuL_eV1S5R09cEttC7f9D7lu0ALijs-avjM0dxoiHUMYKI7KaYkTCwJGDhtTpYdx810k8DYn9UqjDMevjbl_GOC4wAvNmbZUTWOdTDfVXm7D42vcUnh0e7nTYu7qGBRcfRrduzjBZMSddZoz8suWbJlQowUt6-bYOUPixeclML8oOKrtuQ_Y6fI-SNkaM5MrrJku-s1KXiOt5ZGXkpqE-PUQsw1DAzs6MfS6CcuFdYadlBd6sn6bOLNJN3DffDJQGHQUIUefTJ2I_YMQ"
, "p": "7CSQiUHeP_C2QBgQEsC_yF0Q1AFHmNEn9ua0lJ20LJSu7zzYCdE6E5X-j-9w37nzdzOClceEI2-2OAvV_Ukh3R78q9_-Mtc9AUk2BunwzfaAdJHl0YT0IpJEI-IluMpOX9RETTK3KXpjOFBefHOeHS0DyWLRXDaAt2k_9c1Q1Lc"
,"q": "wlvJ3Ap_i1vxt5q6zRT6JBxstvXLi0hQgHZnchvNluOfhzBTfYTSiK0n6Od-yj1c90iZt97B4XKWfps29xwd6wqS6X-QtG59AvlU0IOH4FSoYvyVy4yqpMSzAjgmhwZRi-API7XWd1KSmkTB8t-XfdxjdnC6kM62MqtsdC-Vhs"
, "dp": "WFFomV1AQUvG7fvR7yGV2Nst0wzTeU0olEg-26KL42yMbL-l0S4meXLM7YpQ_evvKfLi8R_YxOQgE6AhnYR_nNLdD29MBDnKADQgd7-BJ5b8_hwfBxihslhgEcef8hf_7glWrkS8ik_S0hoE7KjVRvYyB1zlDob35yD_IfBzPcs", "dq": "h5_NiIK65eBPGDQczicpNjGvmyyB0LuxkTMOlI3aNMS5-Xg7ioc48q8B_oAr9axERzqeKbSDznJLmiVtgZpZNj62rcGalI3VJlIeYTKnil8I8aoYTWXnXf5bNY2sTV32NQfIkHmMxOSqhqoz4Wia0a9tyfJ_FUG8urMT6dUkPKk"
, "qi": "WsLO8yNdoSMF3sYAISKhx_NJ5ua6PISaezUpYk6WgENHfUnwXXiDpDgx8AKae2vRpPaGoHhJkiih5JHTtVWNGUXB0-DItnX0jodM78NT31XefKuE4Pg6nLtrpPlQpRqL6Gj1en2FcVtQ5TblOaFO9dkBoBB-gGWK9dy0WPR5D9w"
}

w localpub
{"kty":"RSA"
,"use":"sig"
,"n":"ALaMFdNTmzUu1wnMGNmsIkBMJUS4EdMAe2HXpQ-k4aDk94znJuCi9OJnJQU4lm4nqgEWdzMVVQMlqZ3ihlXx5vpFzmb4m4EkAcmK0ULVCLL9QRqvuwbOjeXW8pJlcH-EAQKnkMzF6GbtmmDubK46bx2GaQh8rLYAfLvoIwXfyrXIday2VdRNz_3yGzLoxr5QxcFml46479mY3xXwmTSMvVNHEN4F1xPnsLQoNPH3guA104dm8S-f2z_vczHBdSrgiJibesdOP3ugYlxJvDDT3WSf3WW7cjAn8M3vZmCNTPWe6JEewsc6cDBiFWn9UUomulFUV_uucTsV_NXMd8nQ_Hs"
,"e":"AQAB"
}

just for better readability of the audience I transformed your WHEN condition that dictates speed.

(HL7.{MSH:MessageType.TriggerEvent}!="S14")
&&
(HL7.{MSH:SendingFacility.NamespaceID} CONTAINS "CASE")
&&
(
 (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} CONTAINS "OSU UH ENDO")
 ||
 (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} CONTAINS "OSU UH BRONC")
 ||
 (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} CONTAINS "OSU UHE ENDO")
 ||
 (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} CONTAINS "OSU UHE BRONC")
 ||
 (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} CONTAINS "OSU STONERIDGE ENDO")
 ||
 (
  (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} StartsWith "MER")
  &&
  GroupIDExists(HL7,"AIS","3.1","GIProvationMERProcedures")
 )
 ||
 (
  (
   (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} StartsWith "ONT ENDO")
   ||
   (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} StartsWith "GAL OR")
   ||
   (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} StartsWith "GAL ENDO")
   ||
   (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} StartsWith "BUC OR")
  )
  &&
  GroupIDExists(HL7,"AIS","3.1","GIProvationAVIProcedures")
 )
 ||
 (
  ((HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} StartsWith "HOC OR")
  ||
  (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room} StartsWith "HOC ENDO")
  )
  &&
  GroupIDExists(HL7,"AIS","3.1","GIProvationHOCProcedures")
 )

It shows me that you basically check on  (HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room}
I see not much opportunity for optimization of CONTAINS
But for your StartsWith you may try this construct:

  In(SubString((HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room},1,6),"HOC OR","HOC EN")
or
 In(SubString((HL7.{RGSgrp(1).AIL:LocationResourceID(1).Room},1,6),"ONT EN","GAL OR","GAL EN",BUC OR")

An HealthShare expert might be able to answer if it is possible to have an index on the fields of your WHEN condition.

A different approach could be to handle the whole WHEN in a Custom Utility Function

http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=...

the code is already included in the CSP example
the file comes a MIME data in %request:

for easier reading compile the CSP file and see the generated class   csp.upload.cls  in SAMPLES


<!-- As form is submitted to this page look to see if we have the stream in the %request object -->
<csp:if condition='($data(%request.MimeData("FileStream",1)))'>
<hr><br>
Submitted filename: <b>#(..EscapeHTML(%request.MimeData("FileStream",1).FileName))#</b><br>
Size of file: <b>#(..EscapeHTML(%request.MimeData("FileStream",1).Size))#</b><br>
Mime Section: <b>#(..EscapeHTML(%request.MimeData("FileStream",1).MimeSection))#</b><br>
Type of stream: <b>#(..EscapeHTML($classname(%request.MimeData("FileStream",1))))#</b><br>
Content Type: <b>#(..EscapeHTML(%request.MimeData("FileStream",1).ContentType))#</b><br>
<br>
First 200 characters of stream:<br>
<ul>
<script language="Cache" runat="server">
 

See also doc on %CSP.Request

http://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?P...

It seems you try to call ans Action that is not defined / compiled

  /// Get class name for a message descriptor class for this web method based on the SOAPAction
Method GetMsgClass(action As %String, messageChildlist As %Integer, Output methodName As %String, bodyStream As %GlobalCharacterStream = "") As %String [ Internal, ServerOnly = 1 ]
{
Set (methodName,className,msgClass,methodList)=""
Set class=$classname()

Set methodList=$get($$$SOAPParametersSoapActionList(class,action))
>>>> this is line +3   ^^^^^^^^^^^^^^^^^^^^^^^^^^^

this translates to and there is no attempt to write something. 

#define SOAPParametersSoapActionList(%class,%soapAction) ^oddCOM(%class,$$$cCLASSxmldata,"P",0,"soapAction",$select(%soapAction="":$c(0),1:%soapAction))

But finally: . . . .  stNow"),h:\dev5\</text>

Does your Caché Server Instance have access right to  the bolded directory location ????  This smells like  <PROTECT>
 

You may try to cheat it by changing the <input> tag to 

    <input type=file size=30 name=FileStream onchange="javascript: alert(this.value);">

and you get in CHROME  and Firefox

C:\fakepath\EUR_Meldung.pdf

and fakepath doesn't exist obviously

while IE11 and EDGE on Windows10 tell me the real path (!)

C:\Users\ich\Desktop\EUR\EUR_Meldung.pdf

I give no further comment related to security & privacy on products from M$

OK, you look for something different than I understood.

The CLASS REFERENCE to DocBook seems to be not directly available as in Studio.
Just by external  access to Documentation ....

Part of it is found if you have an class in your editor and move your cursor over a class name
then you get a volatile class description that you can nail down by clicking or <F2>

Its's pretty similar to the DocBook version EXCEPT that you have no further references (e.g. Data Types or %Status or  ...)
So it's not a multi level navigation like in browser!

For illustration I have done this for %Persitent.  For %Populate, %XML.Adaptor you have do again and again.

 

To my understanding the structure of your global is irrelevant in this context.
If you want to use sharding forget about ALL global access.
You only access works over SQL !  (at least at the moment, objects may follow in some future)
It's the decision of the sharing logic where and how data are stored in globals.
If you ignore this and continue with direct global access you have a good chance to break it.