major
#29799
Form dependencies: derived fields do not follow edited values; Java script functions cannot report what they read to the ScriptTracer
Two related gaps of the dependency tracing of a <form> in edit mode (view layer, TL 8.0.0-alpha10):
1. A derived attribute shown in a form does not follow the values entered in the same form
A <field> of a derived attribute (<storage-algorithm><query>) keeps its stored value while other fields of the same form are edited, and shows the new value only after saving - even when the derived expression reads only attributes edited in this form.
Reproduction (E-Home, catalogs/program.view.xml): the form of a placed parameter (ehome.operational:ParameterView) edits choice/`number`/`decimal`/`text` and shows the derived displayDefault ("Wirksame Vorgabe") and defaultSource ("Vorgabe von"), which read these attributes (through further derived attributes). Entering a new default leaves both unchanged until the form is saved.
Expected: a derived field in a form is recomputed over the form's overlay (OverlayLookup), the same way the constraints and the dynamic-visibility selectors are, with its dependencies traced by the ScriptTracer.
2. A TL-Script function implemented in Java cannot declare what it reads
The ScriptTracer records only the model accesses written in TL-Script. A script calling a function implemented in Java (GenericMethod) that itself navigates the model - e.g. parameterValueType($obj) reading obj.parameter.type - records no dependency, so a dynamic-visibility selector or an options-by-expression using such a function is not re-evaluated when the attribute the function reads changes in the form.
Reproduction: the dynamic-visibility of ParameterValue#decimal written as obj -> editMode -> parameterValueType($obj).instanceOf(…:FloatingPointType`). Changing the field `parameter in the form does not hide/show the field until saving; written with the navigation in TL-Script ($obj.get(…#parameter`).get(…#type)`) it reacts at once.
Expected: a way for a GenericMethod to report the attribute accesses it performs to the tracer (e.g. a tracing hook on the EvalContext passed to the method, so that tValue calls inside the method are recorded like script accesses), or a declarative "depends on" for script functions.
Workaround in E-Home: the visibility and options scripts repeat the navigation in TL-Script; the constraints and the display call the function.
Lösung
Tracing in the model read. Dependency tracing happens in the attribute read itself, not in the script interpreter. The thread-bound TracingScope (com.top_logic.model.form, next to OverlayLookup) holds a Sink<Pointer> and an OverlayLookup; it is opened with try-with-resources and nests. While a scope is open, every read of an attribute value - a script access, a tValue/`tValueByName` call from Java, a generated wrapper getter - reports its Pointer to the sink and, if the lookup has an overlay for the object, answers the overlay's value. The hook sits at the choke points of the model reads: AttributeOperations.getAttributeValue (all persistent objects), AbstractWrapper.tValue, TransientTLObjectImpl.tValue and the form overlays (FormObjectOverlay, TLObjectOverlay). A per-pointer re-entrancy guard lets an overlay read its base object without being redirected to itself again. ScriptTracer.execute opens the scope and evaluates the plain expression; the rewritten tracing expressions (TracingAccessRewriter, TracingAccess, TracingDynamicGet, TracingScriptMethod) and the tracing copies of configured script functions are gone, so there is one tracing path for TL-Script and Java alike. A function implemented in Java (GenericMethod or static TLScriptFunctions method) is traced without any cooperation; its reads see the edited values. Documented in the developer guide page on extending TL-Script.
Derived attributes computed over the form. A derived attribute of a form object is computed on the persistent base object inside a nested scope that redirects the base's reads to the overlay (TracingScope.computeOnOverlay). A storage implemented in Java therefore receives the typed persistent object, may use the generated getters, and still follows the form's edits; a chain of derived attributes (script or Java) is traced down to the stored attributes it reads.
Derived fields in the view form. An AttributeFieldModel of a derived attribute reads its value in edit mode inside a TracingScope over the form's FormValidationModel, records the attributes it depends on and recomputes when one of them changes in the form (the mechanism the options of a select field use). The recomputed value is taken as value and default, so the field is never dirty, and the change is announced to the form, so fields, options and visibilities depending on the derived attribute follow. TLObjectOverlay answers an unchanged attribute from its base through the guarded read and a derived attribute through the computation on its base. Documented in the view-layer article on forms ("Derived fields").
Demo (tl-demo-react): the module demo.tickets has generated wrappers (package-binding); the ticket form shows the script-derived statusLabel, the headline computed by the Java storage HeadlineStorage from getName() and getStatusLabel(), and the field resolution, whose dynamic-visibility calls the Java function demoTicketsIsClosed (TicketFunctions, reading the status through tValueByName). Selecting another status changes both derived fields before saving.
Limit. Typed Java code cannot take the form object itself: the form hands its overlay to its scripts in edit mode, and neither TLObjectOverlay nor a transient object implements the generated interfaces, so a script function receiving the form object declares it as TLObject. A typed overlay of the future keeps working with the tracing as long as its getters go through tValue, which the generated interfaces do. A declarative "depends on" for script functions is not provided: it could not name the object read and would be coarser than the traced access.