Original Google Doc with Decision Record

What are your constraints?

edit
General Assumptions and Requirements Source

The person or document that this requirement comes from.

This solution does not intend to replace all the existing user preference persistence mechanisms currently utilized within the mediawiki ecosystem. It does not aim to unify the other mechanisms either. Disparate mechanisms will continue to exist within different extensions.

Our initial goal will be to provide the ability to store at very least the following preferences for anonymous users:

  • Page density (page width)
  • Accessibility settings:
    • Dark Mode
    • Font size
Security Requirements

Describe any security limitations or constraints for the proposed solutions.

Source

The person or document that this requirement comes from.

To ensure safety and security, we decided to restrict preference persistence to trusted extensions and skins. Cookie Prototype
To enable the declaration of new Preferences, ClientPreferences should incorporate a registration mechanism through skin.json or extension.json. Skins or extensions can use this mechanism to declare their own Preferences. Cookie Prototype
Privacy Requirements

Describe potential privacy limitations or constraints for the proposed solutions and how they will be mitigated.

Source

The person or document that this requirement comes from.

By using an alternative storage approaches, we can effectively address privacy concerns. We want to avoid automatically transmitting data to the server with each request and ensure that sensitive information such as user preferences and personalization data remains securely stored on the client-side. Cookie Prototype
Additional Requirements

Describe other potential limitations or constraints for the proposed solutions and how they will be mitigated.

Source

The person or document that this requirement comes from.

The solution adheres to the specified SRE-set caching restrictions.The solution has been developed in accordance with the guidelines set by the Site Reliability Engineering (SRE) team. The collaboration between the Web team and SRE has been integral to this process.

Starting from the initial meeting in April 2023, SRE's insights have been consistently considered. These inputs were not only recorded but also incorporated into the solution's development.

The ongoing interaction between the teams was facilitated through the #preference-persistence Slack channel, providing a platform for continuous contribution from SRE. This exchange of ideas in this space demonstrates a commitment to a cooperative approach in shaping the solution. Note: Slack was chosen as an initial strategic planning conversation space due to potential sensitive information and in order to minimize potential risks.

Further consultation occurred in the first week of August 2023. The feedback gathered during this consultation was integrated into the current prototype (see following column), showcasing the effort to include the most up-to-date insights and preferred approaches from SRE.

The following documentation (linked in the next column) showcases the impact of SRE in the decision-making process.

Notes - TDF Feedback: Preference Persistence For Anonymous Users, Cookie Prototype, Reading/Web/Projects/Preference persistence prototype summary, Reading/Web/Projects/Preference persistence prototype 2 summary, August 1 Meeting Notes (Timo, Moh, Jan)
The solution meets specific performance constraints.Through a series of "SLOs for Web" meetings held on May 17, 2023, and May 11, 2023, we worked towards formulating a solution for meeting specific performance constraints in the Preference Persistence prorotype. The discussions centered around the concept of performance budgets as defined by Tim Kadlec, which emphasized the importance of setting well-defined limits on performance metrics to guide our development processes. By understanding the key components of performance budgets, we were able to identify concrete strategies for ensuring our solutions adhered to both staging and production-based measurements, focusing on metrics like Time to First Byte, First Contentful Paint, Largest Contentful Paint, Total Blocking Time, and Cumulative Layout Shift. Cookie Prototype, T334770: Create a proposal around basic web team centric performance SLOs, May 11 Web SLO Meeting Notes, May 17 Web SLO Meeting Notes, Sample conversation regarding this topic
The solution is unambiguous for third-party contributors and outlines proper usage guidelines.The Web team has provided sources that provide comprehensive information and guidelines for third-party contributors, ensuring that they can effectively utilize the mw.user module while adhering to best practices and avoiding potential conflicts or unintended actions when interacting with user-related functionalities in MediaWiki. This includes:
  1. The properties and methods provided by the mw.user module in the MediaWiki JavaScript API clearly define the functionalities and capabilities available for managing user-related information. These include functions to retrieve user details, handle temporary user accounts, manage user preferences, and perform various checks related to user status and features.
  2. The documentation for mediawiki.user emphasizes the availability of the mw.user.clientPrefs feature, which allows manipulation of certain classes on the HTML element to control rendering for anonymous users. Importantly, this source provides specific guidelines on the format and naming convention of classes that can be manipulated, ensuring that unintended manipulation is avoided and serving as a clear indicator of classes subject to manipulation.
  1. See mw.user in MediaWiki Core Documentation
  2. See ResourceLoader/Core modules
The solution has a well-defined and extensible naming schema. It is also adaptable and currently integrated within the prototype. The documentation in ResourceLoader/Core modules establishes a clear and structured naming convention, ensuring a well-defined and extensible schema. ResourceLoader/Core modules

Decision

edit
Selected Option Use localStorage as the persistence layer for user preferences.
Rationale Considering the observed differences in page-load times between localStorage and cookie were negligible, along with the privacy implications of potentially fingerprinting users based on cookie values, we have opted to utilize localStorage as the persistence layer.

While LocalStorage might have a slightly more negative impact on page-load performance, it offers the advantage of accommodating lengthy preference values.

Data Cookies Test: task T331681

https://phabricator.wikimedia.org/T327798#8554853

Informing
Who Who was accountable for making this decision?

Jan Drewniak, Mohd Abualruz, Kim Sarabia

Date June 23, 2023

What are your options?

edit
Option 1: Do Nothing
Description We don’t provide anonymous users configurable experiences such as font size, limited width, dark mode without causing a layout shift or flash of unstyled content during page load
Benefits Save hours of development time and free up resources for other initiatives
Risks Anonymous users would not be able to customize their individual preferences and will have an unequal experience to logged in users. While billions of users might not be aware of the difference, it is a significant amount of people who are missing out on being able to use features they might appreciate and enjoy.
Effort None
Costs Failure to meet OKR for the Product/Web team
Testing None
Performance & Scaling No action means we would keep status quo and there would be no benchmarking/performance tasks or scaling targets
Consultations
Consulted party 1 TDF: Preference Persistence Solution Discussion Attendees: Nicholas Ray Mohd Abualruz Moriel Schottlender Nat Hillard Piotr Miazga Samuel Guebo thiemo.kreuz@wikimedia.de James Forrester Amir Sarabadani
Option 2: Implement existing cookie-based storage of anonymous user preferences
Description Adds script that allows the reading of a cookie to toggle classes on the body tag, effectively enabling/disabling "features" and give anonymous users options to toggle font-size, dark mode and to remember states such as sidebar / table of contents collapsed.
Benefits The cookie option is the most performant out of all the approaches
Risks Serious privacy impact of potentially fingerprinting users based on cookie values
Effort 1 quarter from R&D to post-deployment QA
Costs
  • Developer hours into creating the TDMP from start to finish.
  • For ongoing costs, the team would need to regularly review and update the cookie-based preference system to ensure it aligns with evolving privacy regulations.
Testing
  • Validate that the cookie storage mechanism adheres to security best practices.
  • Assess the performance impact of storing and retrieving preferences using cookies.
  • Test how preferences are applied in real-time and how the application responds when preferences are changed or updated.
Performance & Scaling The response time and resource consumption to ensure efficient cookie management
Deployment Testing and Quality Assurance in Beta and smaller language Wikis: Thoroughly test the functionality and performance of the cookie-based preference system in smaller user bases first. Validate that preferences are captured accurately, stored securely, and retrieved correctly across different scenarios and browsers before deploying changes to large language Wikis.
Rollback and reversibility Yes, it is reversible in smaller scales. Once it is deployed in larger Wikis, it will technically be possible but extremely disruptive
Operations & Monitoring Once the new solution has been deployed what data needs to be collected to monitor activity, provide feedback or report on system/service health?

Data needs to be collected on how users easily set and update their preferences, which we would measure through participation rates and speed at which they complete the action from start to finish. We would also measure the clarity of instructions and options for managing preferences, including the ability to clear or reset preferences if desired, by also measuring participation rates. This would all be done through metrics instrumentation and analysis.

Additional References Any links to additional materials or more detailed plans?

https://phabricator.wikimedia.org/T340459 Cookie Prototype

Consultations
Consulted party 1 See Option 1 party
Option 3 Implement localStorage solution to store anonymous user preferences
Description The localStorage API stores data as key-value pairs in the browser's local storage, which remains available even when the user closes and reopens the browser. The data will be a under a single key in order to minimize synchronous reads during page load.
Benefits List the positives of implementing it
Risks The page-load times for localStorage were negligible in local testing, but it remains to be seen if this will remain true in production. The performance impact of localStorage is difficult to measure because the delay that it causes early on in the rendering cycle can have downstream effects.
Effort 1 quarter from R&D to post-deployment QA
Costs Developer hours into creating the TDMP from start to finish. Possibly lower ongoing costs as localStorage is not as heavily regulated by GDP unlike cookies.
Testing
  • Assess the performance impact of storing and retrieving the single key using localStorage on small, medium, and large scales.
  • Test how preferences are applied in real-time and how the application responds when preferences are changed or updated (similar to Option 2).
Performance & Scaling As mentioned, we would need to measure the localStorage solution in different production environments because the delay that it causes early on in the rendering cycle can have different downstream effects depending on, browsers, data speed, wikis, and other circumstances not yet accounted for
Deployment Same as Option 2
Rollback and reversibility Same as Option 2
Operations & Monitoring Same as Option 2, but we will test the localStorage strategy rather than cookies
Additional References https://phabricator.wikimedia.org/T340459LocalStorage Prototype
Consultations
Consulted party 1 Same as Option 2

Important Questions

edit
Question Who can answer? Resolution, answer or action
Abijeet Patro: Does this mean that preference changes will only be applied after page reload? Jan Drewniak: The assumption is that there will be some UI to change these preferences, and when the user changes the value, it will be saved in localStorage, but also, changed in the HTML, so, assuming that the CSS to activate that option is loaded, the change will be instantly visible.
Niklas Laxström from the Language Team: How is this possible? Given that they are loaded later? What kind of risks? What kind of risks are we talking about? Jan Drewniak: The situation we want to prevent is: after a gadget loads, it modifies these localStorage values, then, on subsequent page-views, the new "unauthorized" values would be appended to the HTML.

What we're basically proposing is keeping a list of values that are modifiable on page-load. That won't really stop gadgets from modifying existing values, but it will stop them from adding new ones.

Jon Robson: Having different values implies more processing which above in the document you state you are trying to minimize computation. Why not always use an integer since these seems to cover all types of preference? Jan Drewniak: It'll certainly work for true/false & numbers. That would reduce complexity and cover our immediate needs, and we could always expand data types in the future.

Thiemo Kreuz: It's quite common in e.g. MW API calls and user options to use 0 and 1 instead of bools. This also reduces the number of bytes that need to be stored and transferred.

Re: `1` - preference value. Must be an integer.

Jon Robson: the use of numeric values implies a feature can have multiple variants. Are there any constraints on this? Seems like it could be problematic (from technical debt/security/performance/maintenance) if a font size feature allowed changing font-size to any value.

Current POC allows for reading booleans. It will translate only to true/false.
Re: `1` - preference value. Must be an integer. cont’d See patch
Jon Robson: suggestion - perhaps we could limit the number of values for now e.g 0-3 ? Each value corresponds with a class and render blocking CSS so for overall performance it's likely important we limit the amount of variants. In the case of font size, 0 might be small, 1 normal and 2 large for example.

Prototypes:

edit

While prototyping and trying out different approaches, and from gathering technical feedback, we would include in core:

Client-side preferences inline script

edit
  • It allows users to enable or disable of features/preferences without logging in or creating an account.
  • It uses existing classes on the document element to avoid adding extra HTML or JavaScript.

Client-side preferences API

edit

That provides a simple API to set and get preferences.

Resource:

edit

https://www.atlassian.com/blog/inside-atlassian/make-team-decisions-without-killing-momentum

Please check the prototypes page for more details

edit

Cookie Based: Preference persistence prototype 2 summary

LocalStorage Based: Preference persistence prototype summary