Description
With the introduction of the core.Config controller in v10, a regression bug was identified that affects batched updates. When updating multiple configs simultaneously using instance.set({a: 'newA', b: 'newB'}), the beforeSet hooks for one config could not reliably access the new, pending value of other configs in the same batch.
This behavior is a departure from the pre-v10 system and breaks the atomicity of set() operations. The issue was identified in test/siesta/tests/ClassSystem.mjs.
Root Cause
The regression was traced to the interaction between the new core.Config instances and the existing autoGenerateGetSet function in Neo.mjs. The getter for a config was retrieving its oldValue directly from the Config instance, while the setter logic created race conditions where pending values in configSymbol were either deleted too early or not available during nested hook calls.
Solution
The generated setter in Neo.mjs#autoGenerateGetSet was refactored to restore the expected behavior, following a robust, four-step transactional process:
- Prevent Recursion: The pending value is immediately removed from
configSymbol.
- Temporary State: The new value is temporarily assigned to the private backing field (e.g.,
this._a = 'newA'). This makes the new value available to all other getters during the beforeSet phase.
- Restore State: After the
beforeSet hook runs, the private backing field is reverted to its original value. This is critical to ensure that the final change detection works correctly.
- Finalize Change:
config.set() is called. It compares the new value against the now-restored original value, correctly detects the change, and triggers the afterSet hooks.
This fix restores the pre-v10 atomicity of set() operations, ensuring that all beforeSet hooks within a batch see a consistent, updated view of all pending changes.
Description
With the introduction of the
core.Configcontroller in v10, a regression bug was identified that affects batched updates. When updating multiple configs simultaneously usinginstance.set({a: 'newA', b: 'newB'}), thebeforeSethooks for one config could not reliably access the new, pending value of other configs in the same batch.This behavior is a departure from the pre-v10 system and breaks the atomicity of
set()operations. The issue was identified intest/siesta/tests/ClassSystem.mjs.Root Cause
The regression was traced to the interaction between the new
core.Configinstances and the existingautoGenerateGetSetfunction inNeo.mjs. The getter for a config was retrieving itsoldValuedirectly from theConfiginstance, while the setter logic created race conditions where pending values inconfigSymbolwere either deleted too early or not available during nested hook calls.Solution
The generated setter in
Neo.mjs#autoGenerateGetSetwas refactored to restore the expected behavior, following a robust, four-step transactional process:configSymbol.this._a = 'newA'). This makes the new value available to all other getters during thebeforeSetphase.beforeSethook runs, the private backing field is reverted to its original value. This is critical to ensure that the final change detection works correctly.config.set()is called. It compares the new value against the now-restored original value, correctly detects the change, and triggers theafterSethooks.This fix restores the pre-v10 atomicity of
set()operations, ensuring that allbeforeSethooks within a batch see a consistent, updated view of all pending changes.