# P8-identity-contracts — screen inventory

| | |
| --- | --- |
| Title (ar) | الهوية والعقود |
| Title (en) | Identity, contracts and the free window |
| Owning epic | D8.0 |
| Reviewer | Raheem takes the decisions; Zayed records them and locks |
| Timebox | 3 days |
| Opened | 2026-09-22 |
| Reviewed | — |
| Locked | — |
| Status | draft |
| Supersedes | the registration and claim half of `P2-onboarding-profile`, and the roster and contract half of `P4-club-admin`, both locked 21 سبتمبر 2026 |

## What this supersedes, and why it is one prototype and not two

Two locked prototypes are each superseded **in part**:

- **`P2-onboarding-profile`** — its registration and claim screens. Its form
  shape, its control-per-data-type answer, its agent area, its mobile
  navigation, its session expiry, its account shape and its notifications inbox
  are untouched and are **not** superseded.
- **`P4-club-admin`** — its roster and contract screens. Its season control, its
  structure drill-down, its squad refusal and its attach-or-create answer are
  untouched and are **not** superseded.

They are superseded together because Raheem's response of **22 September 2026**
treats them as one thing. His own build order has a single first phase —
accounts, registration and claim, the profile registry, and the contract entity
with `contract_type` and a nullable `end_date` — and the reason they are one
phase is visible on one screen here: **an amateur is an identity fact and a
contract fact at the same time.** مهند العسيري has no contract end date, which is
a contract question, and he is registered to a club, which is an identity one,
and T5 cannot be judged unless both are in front of the reviewer at once.

The precedent is P2 itself, which folded in three screens from build tickets
that had no prototyping ticket rather than let them be built undrawn.

### What is carried from the two locked prototypes and is not re-asked

| From | Answer | Rendered here as |
| --- | --- | --- |
| P2 D3 `claim=separate` | the claim search is a second path the person takes himself, showing **every** match with its state, and a held profile can be challenged | `claim.html`, now with T6's documents on it |
| P2 D3 | eight profile types; coach speciality is a **per-sport** catalogue | `registry.html`, now with `is_transactable` beside each |
| P2 D1 `form=steps`, D2 `control=rich` | a step per registry group; the option count decides the control | `index.html`'s registry step |
| P4 D4 `attach=one` | one box, with the unique identifiers checked again before anything is created | `claim.html` and `company.html` both obey it |
| P4 D1 `season=area` | the season is chosen once for the club area | the roster and contract screens sit inside it |
| P4 D2 | the contracts list has sport and team filters, renewal for the club's own people, and expiry horizons at one and two years | `roster.html`, now with a third horizon |
| P4 D3 `refusal=row` | a refusal is on the person's row | carried, and the free window is **not** a refusal |

## The question

Everything downstream of this prototype assumes it knows **who somebody is** and
**what holds them**. His response changed both, and neither change had a screen.

- **Identity has two keys, not one.** A Saudi is keyed on a national ID and
  carries a name in both scripts; a non-Saudi is keyed on a passport and carries
  a name in English. The cast holds three non-Saudis and had declared neither
  key for anyone.
- **Registration is open and verification is at the claim.** Anyone may sign up.
  Everything that proves who you are happens when you take hold of a profile,
  and it requires a document, specifically to stop somebody seizing a known
  player's profile.
- **A club registers as a club**, in one submission carrying credentials, entity
  identity and claim evidence at once, with the owner designated on approval.
- **An amateur has no contract end date**, is commonly well over 23, and is
  handled like a free player. Every date-derived rule must be conditional on
  `professional` rather than returning null.
- **The signed contract comes back into the platform as an upload**, and its
  dates are what every window and every expiry alert is computed from.
- **The free window is an initiation flip**, and the roster is where a club
  first learns one of its people has entered it.

## Decisions to settle

Seven. **Two of them — D3 and D4 — are questions this prototype is posing, not
questions he asked.** They are marked as such here and in `findings.md`, because
a decision attributed to the wrong person is worse than an open question.

| Id | Decision | Options built | Switch |
| --- | --- | --- | --- |
| **D1** | **Does an amateur's club registration constrain his movement?** T5 resolves the negotiation question — he is handled like a free player — and he asks explicitly whether the registration he already holds still binds him. مهند العسيري is registered to نادي الصحراء and holds no contract. | a) **unrestricted** — he initiates and moves on any day, and the registration is a record of where he plays — `amateur=free` b) **still bound** — a notice period and the federation's registration window apply to him as they do to anyone — `amateur=registered` | `amateur` |
| **D2** | **The referee, and profile types that are not transacted.** Board item #20. P5 locked that the deal-type list is computed from the profile type and that a referee's is empty. | a) **a flag on the reference data** — `is_transactable`, false for حكم and **true for مترجم، أخصائي علاج، إعلامي**, who are contracted and moved — `transactable=flag` b) **drop the type** — حكم stops being a profile type at all — `transactable=drop` | `transactable` |
| **D3** | **One search box, two key sets.** *(Posed here, not by him.)* T6 says a Saudi is searched **in Arabic** and a non-Saudi's name is stored **in English**. It does not say how one box finds both, and Mateo Ferreira has no Arabic form of record at all. | a) **detect the script** and search the matching key set, saying which it searched — `search=detect` b) **choose nationality first**, then one box against one key set — `search=scoped` | `search` |
| **D4** | **What an open, unclaimed account holds.** *(Posed here, not by him.)* Registration is open and all verification is at the claim, so there is a gap between the two and the response does not say what sits in it. | a) **nothing** — the account browses, holds no profile and appears in no search — `unclaimed=none` b) **a provisional profile**, self-created and marked unverified, which is claimable and challengeable like any other — `unclaimed=provisional` | `unclaimed` |
| **D5** | **The commercial-registration lookup hits a club that already has an owner.** ماجد بن طلال submits نادي صقور الحجاز's CR. #14 requires duplicate prevention on the CR even when the user chose "create new"; it does not say what the user is then offered. | a) **a challenge** — the same record type P2 D3 locked for a held profile, filed with a document and a reason and worked by the platform — `crhit=challenge` b) **a join request** — routed to the sitting owner, who grants a seat or refuses — `crhit=join` | `crhit` |
| **D6** | **The signed contract upload.** T7 puts drafting and signing outside the platform and brings the signed document back in with its dates. It does not say whether the deal waits for it. | a) **a gate** — the deal does not close until the signed contract and its dates are in — `upload=gate` b) **a follow-up** — the deal closes and the upload is work owed afterwards — `upload=followup` | `upload` |
| **D7** | **The free window on the roster.** Four of نادي الصحراء's people are inside theirs today. P4 locked three contract queues and horizons at one and two years; the window is a fourth horizon and a different kind of fact. | a) **a state on the person's row**, beside the contract dates — `window=row` b) **a queue of its own**, alongside the three P4 locked — `window=queue` | `window` |

### What the reviewer must answer

- **D1** — Unrestricted follows his own resolution to its end and is the simpler
  model: no contract, no dates, no rules. Still bound is the reading his own
  ❓ raises — the transcript describes an amateur registered to a club and
  possibly registered to another in the same division before being acquired,
  which sounds like something that has a procedure. Answer: which, and **if he is
  still bound, by what** — a notice period the club sets, or the federation's
  registration window, because those are two different rules with two different
  owners.
- **D2** — The flag is his own proposal and it is the only one that also says
  something true about مترجم، أخصائي علاج and إعلامي, who **are** contracted and
  moved and were added to the profile types by his own 19 September review.
  Dropping the referee is simpler and it deletes the evidence P5's D4 rests on.
  Answer: which, and — if it is the flag — **what a non-transactable profile is
  for**, which is the question board item #20 has carried open since 21
  سبتمبر and which the flag names without answering.
- **D3** — *Posed here.* Detecting the script is one box and it will be wrong
  about a Saudi whose name somebody typed in Latin. Choosing nationality first
  is two steps and is unambiguous, and it asks a stranger to classify himself
  before he has been told why it matters. Answer: which, and **what the box does
  with a name it cannot place** — because under either answer that case exists
  and neither option describes it.
- **D4** — *Posed here.* Nothing is safe and it means an open registration
  produces an account that can do nothing at all until an administrator works a
  queue, which is a strange thing to call open. A provisional profile makes the
  account immediately useful and it manufactures exactly the duplicates the
  claim search exists to prevent. Answer: which, and **whether a provisional
  profile is searchable by other people** — because if it is, it is a duplicate,
  and if it is not, it is nearly the first answer.
- **D5** — A challenge reuses a record type that is already locked, already
  drawn and already has a queue behind it, and it treats a club's owner as
  somebody who might be wrong. A join request treats him as somebody who is
  right and makes the second applicant wait on a person rather than on the
  platform. Answer: which, and **what happens when the sitting owner never
  answers**, because a join request with no answer is an application that fails
  silently and #14 is explicitly about not letting that happen.
- **D6** — The gate is the only answer under which a closed deal always has a
  document behind it, and it means a deal agreed today stays open for however
  long two legal departments take. The follow-up closes the deal when the
  parties think it is closed, and it creates a class of closed deals with no
  contract, which is what the free window and every expiry alert are computed
  from. Answer: which, and **what the dates are before the upload arrives** —
  because under the follow-up answer T1 has nothing to read.
- **D7** — The row is where P4 put a refusal and the window is not a refusal,
  which is the argument against putting it there: a club scanning rows for
  problems will read it as one. A queue of its own says what it is — four people
  whose initiative has passed to them — and it is a fourth queue in a screen
  that already has three. Answer: which, and **whether the window is shown on a
  person whose club has no intention of losing him**, because today that is all
  four of them.

## Not up for debate — carried, and rendered as given

- **S1, locked 18 سبتمبر 2026** — the two shells, the rail, no role switcher,
  the club as an area with its name and status at the head of every screen in
  it, the one refusal pattern, and dates in Arabic sentences with a month name.
- **P2 and P4's answers** in the table above.
- **A field the person may read and not change is not a refusal.** S1 settled
  it; the contract a club owns and the verification tier the platform owns both
  render as owned fields and never as refusals.
- **A club under review browses and transacts nothing.** P4's condition, carried.
- **The registry decides the fields.** The form is not hand-drawn.
- **Uniqueness is checked again before a record is created**, even when the user
  insisted on creating one. P4 D4, locked, and #14 restates it for the CR.

## Screens

`p8.js` is `p7.js` with this prototype's switches and its own `HERE`, and the
same S1 navigation. Two screens are **outside** the application shell —
`index.html` and `claim.html` under an unauthenticated read — which is S1's
second shell arriving from the other side, exactly as P2 drew it.

| # | Screen | File | Purpose | Actor | Settles |
| --- | --- | --- | --- | --- | --- |
| 1 | Register | `index.html` | Open registration on two key sets: Mateo Ferreira on a passport with an English-only name, and a Saudi on a national ID with both scripts. What the account holds before it claims anything. | Stranger | **D3**, **D4**, T6 |
| 2 | Find and claim a profile | `claim.html` | The claim search carried from P2 D3 — every match with its state — now with the document T6 requires, and the duplicate guard catching a collision the user walked past. | Stranger, new member | **D3**, **D4**, T6 |
| 3 | Register a club | `company.html` | #14's single submission: credentials, entity identity and claim evidence at once. The CR lookup, and the collision on نادي صقور الحجاز. | فهد الزهراني, ماجد بن طلال | **D5**, #14 |
| 4 | The profile registry | `registry.html` | Eight profile types with `is_transactable` beside each, the per-sport coaching catalogue carried from P2, and the referee under both answers. | هند الشمري | **D2**, #20 |
| 5 | Roster and contracts | `roster.html` | Twenty-four people, three contract queues, the amateur with no end date, and four people inside their free window. | ناصر العمري | **D1**, **D7**, T5, T1 |
| 6 | One contract | `contract.html` | `contract_type`, a nullable end date, the signed upload and the dates it carries, and the history that is never deleted. | ناصر العمري | **D1**, **D6**, T5, T7 |
| 7 | Clubs on and off the platform | `clubs.html` | نادي رمال القصيم beside forty-six members: what the platform holds about a club that has no account, and what may be done with it. | ناصر العمري, هند الشمري | the member indicator |

### Why seven, and why `clubs.html` is here rather than in P7

The member/non-member indicator is a property of a **club record**, and a club
record is this prototype's. What the indicator *does* — an in-platform offer or
an invitation by email — is a fork between two buttons and is judged in P7,
where both buttons exist. So the record is drawn here and the decision is taken
there, and neither screen pretends to do the other's job.

`contract.html` and `roster.html` both exist because the amateur is legible on
neither alone: the roster shows that he is not one of the three with no contract
recorded, and the contract screen shows what he has instead.

## Switches carried in the URL

| Parameter | Values | Screens | What it changes |
| --- | --- | --- | --- |
| `locale` | `ar` (default), `en` | all | handled by `shared/proto.js` |
| `theme` | `light` (default), `dark` | all | handled by `shared/proto.js` |
| `state` | see below | all | handled by `shared/proto.js` |
| `amateur` | `free` (default), `registered` | `roster.html`, `contract.html` | **D1** |
| `transactable` | `flag` (default), `drop` | `registry.html` | **D2** |
| `search` | `detect` (default), `scoped` | `index.html`, `claim.html` | **D3** |
| `unclaimed` | `none` (default), `provisional` | `index.html`, `claim.html` | **D4** |
| `crhit` | `challenge` (default), `join` | `company.html` | **D5** |
| `upload` | `gate` (default), `followup` | `contract.html` | **D6** |
| `window` | `row` (default), `queue` | `roster.html` | **D7** |
| `mobile` | `drawer` (default), `bar` | all | **Inherited from P2's D5.** |
| `seat` | `owner` (default), `member` | all | carried |
| `role` | `club` (default), `pro`, `agent`, `admin` | all | Who is signed in. |
| `drawer` | `open` | all | Opens the mobile drawer. |

## States per screen

| Screen | default | loading | empty | error | partial | no-permission | What the non-obvious ones are |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `index.html` | ✓ | ✓ | | ✓ | ✓ | | `partial`: registered on a passport with the English-only name accepted and nothing claimed yet, which is D4's whole subject; `error`: **the email is already registered**, told in the one way that does not disclose who is registered. **No `no-permission`** — the screen is outside the shell and anyone may reach it |
| `claim.html` | ✓ | ✓ | ✓ | ✓ | ✓ | | `default`: ماجد الحربي's three matches with متاح / مملوك / قيد التحقق, carried from P2; `partial`: **the duplicate guard firing after the user chose "create new"** — the national ID matched and nothing was created; `error`: a claim refused with its reason; `empty`: the ordinary no-match |
| `company.html` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | `partial`: **ماجد بن طلال's CR collision**, which is D5; `error`: the submission was refused for a document that does not match the entity; `no-permission`: an account already in a club, carried from P4 |
| `registry.html` | ✓ | ✓ | | ✓ | ✓ | ✓ | `partial`: a type whose transactability is set and whose deal types are not yet configured; `no-permission`: a club member who reached an administration route |
| `roster.html` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | `partial`: **the three with no contract recorded beside the one with a contract and no end date**, which is the distinction P4's roster cannot draw; `no-permission`: نادي واحة الخرج, pending |
| `contract.html` | ✓ | ✓ | | ✓ | ✓ | ✓ | `default`: عمر الشهراني, whose contract history is the cast's only one; `partial`: **مهند العسيري — عقد هاوٍ, no end date, every date-derived rule stated as not applying** rather than as null; `error`: the uploaded contract was rejected |
| `clubs.html` | ✓ | ✓ | ✓ | ✓ | ✓ | | `partial`: **نادي رمال القصيم** — a shadow record with a contact address and nothing else; `empty`: a filter matching no club |

## Fixture world

The shared cast in [`../FIXTURES.md`](../FIXTURES.md), **Stage 3** section.

| | |
| --- | --- |
| Today | **18 سبتمبر 2026** |
| The amateur | **مهند العسيري** — 27, نادي الصحراء, عقد هاوٍ from 1 أغسطس 2026, **no end date**, one of the twenty-four |
| The non-Saudi | **Mateo Ferreira** — passport FK7719203, **English name only**, registered 17 سبتمبر 2026 |
| The Saudi keys | فيصل الدوسري 1078342915 · سلطان الرشيد 1093771204 · ماجد الحربي 1066520384 · مهند العسيري 1081447706 |
| The claim subject | **ماجد الحربي** — three matches on his name and date of birth, carried from P2 |
| The corporate applicant | **فهد الزهراني / نادي واحة الخرج**, CR 4030299871, one submission, 14 سبتمبر 2026 |
| The CR collision | **ماجد بن طلال** submits نادي صقور الحجاز's CR 4030118742 on 16 سبتمبر 2026 |
| Inside the free window | **فيصل الدوسري، تركي الحربي، خالد بن سالم** and, at another club, **عماد الغانم** |
| Window shut | **ثامر القرني** (opens 1 يوليو 2027) and **سعد الغامدي** (opens 1 يناير 2028) |
| The non-member club | **نادي رمال القصيم**, shadow record, 11 سبتمبر 2026 |

## Out of scope

- **The form shape and the control per data type.** P2's D1 and D2, locked.
- **The agent area, the account, auth and notifications.** P2's D4, D6, D7, D8 —
  untouched and not superseded.
- **The season control, the structure drill-down, the squad refusal and
  attach-or-create.** P4's four, locked.
- **The negotiation.** Everything a contract is *used for* is P7's.
- **The notification event catalogue.** An enumeration with no surface.
- **The audit trail.** A storage rule. The visible trail is S1's history row and
  already exists.
- **Season history.** Board item #18, deferred.

## Open questions

1. **What is a non-transactable profile for?** Board item #20 has carried this
   open since 21 سبتمبر and `is_transactable` names it without answering it.
2. **What does the search box do with a name it cannot place?** Neither answer
   to D3 describes it and the cast holds no example, on purpose.
3. **Who owns an amateur's notice period**, if D1 is answered "still bound" —
   the club, or the federation?
4. **What are a deal's dates before the contract is uploaded**, under D6's
   follow-up answer? T1 reads those dates and they do not exist yet.
5. **Does a provisional profile appear in another person's claim search?** Under
   D4's second answer it is either a duplicate or it is invisible, and the
   response does not choose.

## Not built

- **The second non-member club.** نادي رمال القصيم is one record and the screen
  does not claim a shape for forty-six of them.
- **An amateur at a club that is not نادي الصحراء.** The roster is the club's
  own and the cross-club amateur case — his registration moving between two
  clubs in one division, which is what the transcript describes — has no screen.
- **A passport that expires.** The key is the number; nothing here renews it.
