mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
feat(profile): move profile timezone from staff to an experiment (#3011)
This commit is contained in:
@@ -38,6 +38,7 @@ Missing settings use the defaults documented below. Invalid stored configuration
|
||||
| push_relay | [push relay configuration](#push-relay-configuration-object) object | Operator consent to the Fluxer-run push relay |
|
||||
| domain_migration | [domain migration configuration](#domain-migration-configuration-object) object | Web domain migration rollout |
|
||||
| altcha_captcha | [ALTCHA captcha configuration](#altcha-captcha-configuration-object) object | ALTCHA proof-of-work captcha rollout |
|
||||
| profile_timezone | [profile timezone configuration](#profile-timezone-configuration-object) object | Profile timezone rollout |
|
||||
| experiment_delivery | [experiment delivery configuration](#experiment-delivery-configuration-object) object | Cadence every client polls the experiments route on |
|
||||
| registration | [registration configuration](#registration-configuration-object) object | Registration policy, issued URLs, and pending registrations |
|
||||
| self_hosted | boolean | Whether the deployment runs in self-hosted mode |
|
||||
@@ -194,6 +195,27 @@ Each challenge hides its counter between half of `max_counter` and `max_counter`
|
||||
|
||||
The rollout only changes which provider answers a captcha that is already required. While the instance captcha provider is `none`, it has no effect.
|
||||
|
||||
## Profile timezone configuration object
|
||||
|
||||
The instance rollout that lets an account set a profile timezone and show its local time on its profile. [Experiments](/http-api/experiments/#profile-timezone-assignment-object) defines what a client resolves from it.
|
||||
|
||||
### Structure
|
||||
|
||||
| Field | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| enabled | boolean | Whether the rollout runs at all (default false) |
|
||||
| config_version | integer | Revision counter, raised by Fluxer and never accepted from a request |
|
||||
| rollout_basis_points | integer | Share of accounts the rollout selects, in basis points (0-10000, default 0) |
|
||||
| rollout_salt | string | Salt of the sampling hash (1-64 printable ASCII characters, default `profile-timezone-v1`) |
|
||||
| included_user_ids | array[snowflake] | Accounts the rollout always selects, up to 1000 entries (default empty) |
|
||||
| excluded_user_ids | array[snowflake] | Accounts the rollout never selects, up to 1000 entries (default empty) |
|
||||
|
||||
Every field is present on read. An absent document or missing field uses the defaults above.
|
||||
|
||||
`excluded_user_ids` is applied before `included_user_ids`, so the rollout never selects an account in both.
|
||||
|
||||
An account that leaves the rollout keeps its stored timezone, but Fluxer stops showing it on the profile and refuses changes to it until the account is selected again.
|
||||
|
||||
## Experiment delivery configuration object
|
||||
|
||||
How often a client polls [Get experiment assignments](/http-api/experiments/#get-experiment-assignments), and how widely those polls are spread. The setting is instance-wide and applies to every experiment at once, so adding an experiment adds no second cadence to tune.
|
||||
@@ -605,6 +627,7 @@ The body has one optional object for each section. Fluxer leaves an absent secti
|
||||
| push_relay? | object | `relay_consent_accepted` from the [push relay configuration](#push-relay-configuration-object) |
|
||||
| domain_migration? | object | Any subset of the [domain migration](#domain-migration-configuration-object) fields |
|
||||
| altcha_captcha? | object | Any subset of the [ALTCHA captcha](#altcha-captcha-configuration-object) fields |
|
||||
| profile_timezone? | object | Any subset of the [profile timezone](#profile-timezone-configuration-object) fields |
|
||||
| experiment_delivery? | object | Any subset of the [experiment delivery](#experiment-delivery-configuration-object) fields |
|
||||
| registration? | object | `mode` and `admin_registration_urls_enabled` |
|
||||
| app_public?<sup>2</sup> | object | `branding`, `setup`, `legal`, and `registration` sub-objects, each merged field by field |
|
||||
@@ -624,6 +647,8 @@ The body has one optional object for each section. Fluxer leaves an absent secti
|
||||
|
||||
`altcha_captcha` works the same way, over the [ALTCHA captcha configuration](#altcha-captcha-configuration-object) fields and its own `config_version`.
|
||||
|
||||
`profile_timezone` works the same way, over the [profile timezone configuration](#profile-timezone-configuration-object) fields and its own `config_version`.
|
||||
|
||||
`experiment_delivery` takes both [experiment delivery configuration](#experiment-delivery-configuration-object) fields, each bound as documented there. It is a section of its own, so a write to it changes no `config_version` and changes no assignment, only the cadence on which clients ask for one.
|
||||
|
||||
<sup>3</sup> A secret such as `klipy_api_key`, `api_key`, `hcaptcha_secret_key`, `turnstile_secret_key`, or the SMTP `password` is written when supplied and left alone when absent. `integrations.bluesky.keys` is the only way to write the Bluesky signing keys counted as `bluesky.key_count`. It takes up to 8 entries of `kid` (1-255 characters) and nullable `private_key` (up to 10000 characters), and replaces the stored key set outright
|
||||
@@ -660,7 +685,7 @@ Fluxer skips URL validation while the merged configuration leaves single sign-on
|
||||
| 400 | [error response](/admin-api/#error-response) | A policy transition is refused, returned as `INSTANCE_POLICY_TRANSITION_NOT_ALLOWED` |
|
||||
|
||||
:::caution[Sections are applied one after another]
|
||||
The order is `gateway_rollout`, `voice_noise_suppression`, `push_relay`, `domain_migration`, `altcha_captcha`, `experiment_delivery`, `sso`, `registration`, `app_public` branding, legal, and registration fields, `integrations`, `media`, `policy`, and finally `app_public.setup`. A failure part way through leaves the earlier sections written.
|
||||
The order is `gateway_rollout`, `voice_noise_suppression`, `push_relay`, `domain_migration`, `altcha_captcha`, `profile_timezone`, `experiment_delivery`, `sso`, `registration`, `app_public` branding, legal, and registration fields, `integrations`, `media`, `policy`, and finally `app_public.setup`. A failure part way through leaves the earlier sections written.
|
||||
:::
|
||||
|
||||
### Side effects
|
||||
|
||||
@@ -6,7 +6,7 @@ description: The experiment assignments envelope, the revalidation and polling c
|
||||
|
||||
import RouteHeader from '@/components/RouteHeader.astro';
|
||||
|
||||
An experiment is an instance-wide rollout that an operator configures. For each account, Fluxer works out from that configuration whether the account is in the rollout and which settings the account receives. The single route on this page resolves every experiment the server defines and returns them in one envelope, together with the polling cadence they share. This server defines `voice_noise_suppression`, whose placement protocol [Voice](/voice/) defines, `domain_migration` and `altcha_captcha`.
|
||||
An experiment is an instance-wide rollout that an operator configures. For each account, Fluxer works out from that configuration whether the account is in the rollout and which settings the account receives. The single route on this page resolves every experiment the server defines and returns them in one envelope, together with the polling cadence they share. This server defines `voice_noise_suppression`, whose placement protocol [Voice](/voice/) defines, `domain_migration`, `altcha_captcha` and `profile_timezone`.
|
||||
|
||||
Every assignment is advice. A client that ignores one behaves as it does with the rollout off, and no route and no Gateway event reports what a client actually ran.
|
||||
|
||||
@@ -35,6 +35,7 @@ One entry per experiment. The envelope reports this object even when it is empty
|
||||
| voice_noise_suppression? | [noise suppression assignment](#noise-suppression-assignment-object) object | The caller's noise suppression assignment |
|
||||
| domain_migration? | [domain migration assignment](#domain-migration-assignment-object) object | The caller's web domain migration assignment |
|
||||
| altcha_captcha? | [ALTCHA captcha assignment](#altcha-captcha-assignment-object) object | The caller's captcha provider assignment |
|
||||
| profile_timezone? | [profile timezone assignment](#profile-timezone-assignment-object) object | The caller's profile timezone assignment |
|
||||
|
||||
Ignore unknown experiments and treat a missing experiment as off.
|
||||
|
||||
@@ -131,6 +132,20 @@ A caller is drawn either by the operator's allowlist or by the sampled share of
|
||||
|
||||
The assignment is informational. The server applies the same resolution to every request that needs a captcha and names the provider in the [captcha error](/topics/captcha/#altcha-proof-of-work), so a client needs no copy of this value to answer a challenge.
|
||||
|
||||
## Profile timezone assignment object
|
||||
|
||||
One resolution of the instance profile timezone rollout against one account. This server version writes the key on every response.
|
||||
|
||||
### Structure
|
||||
|
||||
| Field | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| enabled | boolean | Whether the caller can set a profile timezone and show it on their profile |
|
||||
|
||||
A caller is drawn either by the operator's allowlist or by the sampled share of the account population. `enabled` is false in every other case, the rollout being off included.
|
||||
|
||||
The server applies the same resolution on its own. [Modify current user](/http-api/users/current-user/#modify-current-user) drops `timezone` and `timezone_privacy_flags` for an account outside the rollout, and a [user profile](/http-api/users/#get-user-profile) reports `timezone_offset` as null for a target outside it.
|
||||
|
||||
## Get experiment assignments
|
||||
|
||||
<RouteHeader method="GET" path="/v1/experiments" bot />
|
||||
|
||||
@@ -161,7 +161,7 @@ The private representation of the current account, returned by [Get current user
|
||||
|
||||
<sup>6</sup> Always null
|
||||
|
||||
<sup>7</sup> The pair is present only while the account has the staff flag, and it is absent for every other account
|
||||
<sup>7</sup> This server version writes the pair for every account. Whether the account can change it is decided by the [profile timezone assignment](/http-api/experiments/#profile-timezone-assignment-object)
|
||||
|
||||
<sup>8</sup> The banner hash is not returned at all while the account lacks the animated banner entitlement, which every profile banner requires
|
||||
|
||||
@@ -565,7 +565,7 @@ The profile read returned by [Get user profile](#get-user-profile) for one targe
|
||||
|
||||
<sup>4</sup> The array is empty when the profile is restricted. It otherwise holds only verified connections whose [profile field privacy flags](#profile-field-privacy-flags) admit the caller
|
||||
|
||||
<sup>5</sup> The value is null unless the profile is unrestricted, the target has the staff flag, the target has stored a timezone, and its [profile field privacy flags](#profile-field-privacy-flags) admit the caller
|
||||
<sup>5</sup> The value is null unless the profile is unrestricted, the [profile timezone assignment](/http-api/experiments/#profile-timezone-assignment-object) of the target is enabled, the target has stored a timezone, and its [profile field privacy flags](#profile-field-privacy-flags) admit the caller
|
||||
|
||||
<sup>6</sup> The field is present only on a restricted read
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ Modifies the current account and returns the resulting [user](/http-api/users/#u
|
||||
|
||||
<sup>9</sup> The value is matched against the instance profile substring blocklist like `username`, `global_name`, and `bio`
|
||||
|
||||
<sup>10</sup> The pair is staff-only. A request from an account without the [`STAFF`](/http-api/users/#public-user-flags) flag has both fields dropped before the update runs
|
||||
<sup>10</sup> A request from an account whose [profile timezone assignment](/http-api/experiments/#profile-timezone-assignment-object) is not enabled has both fields dropped before the update runs
|
||||
|
||||
<sup>11</sup> An unrecognised identifier is rejected with `INVALID_TIMEZONE_IDENTIFIER`. Setting a first timezone without `timezone_privacy_flags` sets those flags to `EVERYONE`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user