@@ -58,7 +58,7 @@ The docs page `nodes-protocol.html` renders its tables from the `nodes_spec` Jin
|
||||
| D2 | the native client is Go, one static binary per OS and architecture |
|
||||
| D3 | the extension ships as a sideloadable zip first, store submission later |
|
||||
| D4 | rewards are XP, badges and a leaderboard only: no coins, no money, nothing purchasable |
|
||||
| D5 | donors must be adults (`age_band`) |
|
||||
| D5 | donation has no age gate: any active member with consent may donate |
|
||||
| D6 | a datacenter address is not a donor: residential and mobile only, admin override |
|
||||
|
||||
## Data layer (Phase 2)
|
||||
@@ -99,7 +99,7 @@ A job is a row in `node_requests`, so any worker can ask and only the lock owner
|
||||
|
||||
## The consent choke point
|
||||
|
||||
`ConsentGate` is the only place that decides whether a member's node may exist. `allows_many(user_uids)` decides a whole set with a fixed number of queries and `allows(uid)` is the one-element case of it, so the single and batch answers cannot diverge (a test compares them). Order of reasons: `kill_switch`, `no_account`, `deletion_pending`, `account_inactive`, `suspended`, `not_adult`, `no_consent`, `not_enabled`. It is called at device registration, ticket issue, socket accept and every supervisor tick. An account whose `age_band` is empty (created before age bands existed) is refused as not adult, loudly, rather than assumed adult.
|
||||
`ConsentGate` is the only place that decides whether a member's node may exist. `allows_many(user_uids)` decides a whole set with a fixed number of queries and `allows(uid)` is the one-element case of it, so the single and batch answers cannot diverge (a test compares them). Order of reasons: `kill_switch`, `no_account`, `deletion_pending`, `account_inactive`, `suspended`, `no_consent`, `not_enabled`. It is called at device registration, ticket issue, socket accept and every supervisor tick.
|
||||
|
||||
`NodesService.reconcile` runs every `reconcile_seconds`, asks the gate once for all connected owners and loads all devices in one query, then kicks with a reason: `kill_switch`, `revoked`, `suspended`, or the gate's reason. This is why withdrawing the consent, switching donation off, deleting the device or flipping `nodes_enabled` takes effect within one tick even when the request landed on a different worker than the one holding the sockets. **Measured** (scratch SQLite, this machine, 2000 synthetic sessions): one tick costs about 110 ms; the per-session version of the same check cost about 1 ms per session, so 488 ms at 500 sessions and an extrapolated 2 s at 2000, which would have blocked the event loop for the whole tick. Do not reintroduce a per-session query in `reconcile`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user