diff --git a/src/shared/refine/providers/index.ts b/src/shared/refine/providers/index.ts index 1ceb7ae..849b7dd 100644 --- a/src/shared/refine/providers/index.ts +++ b/src/shared/refine/providers/index.ts @@ -7,21 +7,24 @@ * selection below, `RefineProvider`'s runtime switch. What is missing is backends. * * WHY THE FIRST ONE WAS WITHDRAWN. `@ng-org/refine-providers` was wired and - * measured, and it works as plain CRUD over SHEX shapes. But Festipod's sign-up - * model needs more than CRUD: `participantCount` counts participants this session - * cannot see, which the project derives from inbox deposits recomputed by the - * event's owner — see the requirement in `types.ts`. A counter incremented from a - * value read back out of a list is a different mechanism, it races itself, and the - * project's own brief declares it superseded. Rather than harden a counter on a - * backend that structurally cannot carry the model, the wiring was removed; the - * worked implementation is in this branch's history (`providers/nextgraph.ts`, - * up to the commit that withdrew it) and is the reference for the shape of the - * next one. + * measured, and it works as plain CRUD over SHEX shapes. It was withdrawn because + * it is not the target: what is coming is a Refine provider over NextGraph *plus + * the polyfill*, and hardening this one meanwhile buys nothing. * - * WHAT COMES NEXT, and why the seam stays: a Refine provider over NextGraph *plus - * the polyfill*, which does publish inboxes, and `@activitypods/refine-providers`. - * Festipod has to support both, so the structure is kept and only the entry is - * gone. + * NOT because it was incapable — an earlier version of this comment said so, and + * was wrong. It blamed the absence of an inbox for the participant count, having + * misread the model: every Participation is readable by everyone, only the link + * to a person is protected, so counting them is ordinary CRUD. See `types.ts`. + * What the measurements did establish is narrower and still worth knowing: the + * count must not be an incremented field, because each write would derive from a + * read of the previous one and race itself. + * + * The worked implementation is in this branch's history (`providers/nextgraph.ts`, + * up to the commit that withdrew it) and is the reference for the next one's shape. + * + * WHAT COMES NEXT, and why the seam stays: that NextGraph+polyfill provider, and + * `@activitypods/refine-providers`. Festipod has to support both, so the structure + * is kept and only the entry is gone. * * ADDING ONE is a file implementing `RefineBackend` plus a line here. What that * file must answer is in `types.ts` and cannot be guessed: how its providers are diff --git a/src/shared/refine/providers/types.ts b/src/shared/refine/providers/types.ts index 7af642b..eae4ab9 100644 --- a/src/shared/refine/providers/types.ts +++ b/src/shared/refine/providers/types.ts @@ -112,28 +112,28 @@ export interface RefineBackend { } /** - * WHAT A BACKEND MUST BE ABLE TO DO, beyond CRUD — recorded here because the - * first backend tried could NOT, and that is why it was withdrawn. + * HOW THE PARTICIPANT COUNT IS OBTAINED — a domain rule, not a backend capability. * - * `participantCount` is **the number of participants, including those this - * session cannot see**. So it is not a count of the participations we can read: - * filtering by what we are allowed to see would under-report it. The project's - * model (concept `data-layer`, brief_2026-07-20_attendance-set-model, and - * knowledge_context-internals) derives it instead: + * `participantCount` is the number of participants, and every Participation is + * READABLE BY EVERYONE: what is protected is the link to a person, not the + * record. Only a connection can read the profile a participation points at and + * recognise who it is. So the count is obtained by COUNTING the participations of + * an event — no filtering by visibility, because none is needed (concept + * `data-layer`, brief_2026-07-20_attendance-set-model). * - * - whoever signs up writes their OWN participation, then DEPOSITS a marker - * into the event's inbox; - * - the event OWNER's session watches the inboxes of its own events and - * RECOMPUTES the count from the deposits, deduped, minus the cancelled ones. - * It is the field's only writer, and the count is `|active set|`. + * This means NO backend capability is required for it: counting records is CRUD. + * An earlier version of this comment claimed the opposite — that an inbox was + * needed, and that a CRUD-only backend therefore could not carry the model. That + * was a misreading of the brief's "no filtering", and it is wrong. The inbox on + * the sibling branch is how a sign-up is DELIVERED to the event's owner so the + * owner can maintain the aggregate; it is one implementation of the count, not a + * precondition for having one. * - * Two consequences for this contract. A backend offering only CRUD over records - * — no inbox, no per-document delivery — cannot support it: incrementing a - * counter read back from a list is a different mechanism, it races itself, and - * the project's brief declares it superseded. And a backend that CAN must say so, - * because the app's sign-up path differs accordingly. - * - * Until a backend provides it, `participantCount` is whatever the record carries. + * What IS a rule, and what the race measured here proved: the count must not be + * an INCREMENTED field. Reading a stored counter out of a list, adding one and + * writing it back derives each write from a read of the previous one, which + * races itself through any data provider — and the project's brief declares that + * mutated counter superseded. */ /** Every resource name a backend serves, derived from its bindings. */