# P7-negotiation-market — findings

| | |
| --- | --- |
| Reviewer | Raheem takes the decisions; Zayed records them and locks |
| Reviewed | 23 سبتمبر 2026 — Zayed, on his own authority after the grilling of that day (Raheem's review may still overrule; an overrule is absorbed as a story and, where it changes a screen, a new P<n>) |
| Status | locked |
| Supersedes | **`P5-requests-offers`**, locked **21 سبتمبر 2026** |
| Superseded by | — |

## What this supersedes, and why

**`P5-requests-offers` was locked on 21 September 2026** and is a dated record
that will never be edited. On **22 September 2026** Raheem answered the twelve
discussion questions P5 had recorded as open, added eight requirements from a
client meeting, and ruled on four board items. This prototype exists because of
that response and replaces P5 as the negotiation surface.

**P5's four locked answers all stand and none is reopened here:**

| P5 | Answer | Rendered here |
| --- | --- | --- |
| D1 `row=headline` | the list row is a headline sentence | every row on `inbox.html` |
| D2 `counter=beside` | a request is a container of immutable offers, one open at a time | `offer.html` — and Q11 confirms it word for word |
| D3 `consent=onrecord` | the owning club's consent is an action on the approach | `offer.html`, now beside a second gate |
| D4 `dealtype=perrole` | the deal-type list is computed from the target's profile type | `index.html`, now with the third type in it |

**What made a successor necessary** is everything P5 was silent about, all of it
decided or specified on 22 September: the listing policy engine, the
`market` / `direct` route split and the freeze, value as line items, the player's
own consent gate, the routing constraint on an unlisted approach, the third deal
type, two legs and four participants, drafts, offer expiry, the per-data-type
visibility strategy, and the needs mechanism as a saved market search.

`friendly.html` is **not** rebuilt: board item #19 closes friendlies with a
backlog reference, and P5's screen stands as the dated evidence that the approach
record stretched to something that is not a transfer.

**A reader who lands on `P5-requests-offers` from an old link finds this
prototype through the registry**: P5's entry in `prototypes.json` and in the root
`index.html` reads `superseded` and names `P7-negotiation-market`.

## Outcome per decision

One row per decision id from `screens.md`. **Filled on 23 سبتمبر 2026 by Zayed**; every outcome is a decision of the record on `sports-deal-web` #39, and the screenshot named is its evidence.

| Id | Decision | Options built | Switch value | Outcome | Evidence | Writes back to |
| --- | --- | --- | --- | --- | --- | --- |
| **D1** | A restricted listing meets a mismatched offer | hard block · out-of-scope tray | `restrict=block` · `restrict=tray` | **the out-of-scope tray; a trayed offer is not work the club owes and the sender is told** (`restrict=tray`) | `screenshots/index--partial--ar--tray.png`, `screenshots/index--partial--ar--block.png`, `screenshots/inbox--default--ar--tray.png` | (a) |
| **D2** | A player offered in exchange | a linked negotiation · a valuation line | `exchange=linked` · `exchange=valuation` | **a valuation line item that references the player; no linked negotiation** (`exchange=valuation`) | `screenshots/offer--default--ar--linked.png`, `screenshots/offer--default--ar--valuation.png` | (a) |
| **D3** | What holds a draft for approval | a value threshold · the sender's role | `approval=value` · `approval=role` | **the sender's role: a non-owner's draft waits for an owner; a club switch, off by default** (`approval=role`) | `screenshots/approach--partial--ar--value.png`, `screenshots/approach--partial--ar--role.png` | (a) |
| **D4** | The position taxonomy | hierarchical · flat | `positions=tree` · `positions=flat` | **flat: the position matches or it does not; the registry owns the list** (`positions=flat`) | `screenshots/needs--default--ar--tree.png`, `screenshots/needs--default--ar--flat.png` | (a) |
| **D5** | Criteria strictness | required vs preferred · every criterion required | `criteria=weighted` · `criteria=strict` | **required vs preferred per criterion; a required miss refuses the application naming the criterion, a preferred miss is stored and shown as a flag** (`criteria=weighted`) | `screenshots/need--default--ar--weighted.png`, `screenshots/need--default--ar--strict.png` | (a) |
| **D6** | The candidate list | rank everything · a score cut-off | `rank=all` · `rank=cutoff` | **rank everything; nothing hidden — and with the percentile engine in backlog, no score is computed** (`rank=all`) | `screenshots/need--default--ar--all.png`, `screenshots/need--default--ar--cutoff.png` | (a) |
| **D7** | The visibility defaults | disclose to the counterparty · clubs equal | `visibility=disclose` · `visibility=equal` | **disclose; the counterparty audience begins when a request exists between the two clubs; combined with the read tier by AND** (`visibility=disclose`) | `screenshots/visibility--default--ar--disclose.png`, `screenshots/visibility--default--ar--equal.png` | (a) |
| **D8** | A deal agreed outside a registration window | warn at agreement · block | `registration=warn` · `registration=block` | **warn at agreement; agreed and registered are two states; registered needs an open window and the signed contract** (`registration=warn`) | `screenshots/deal--default--ar--warn.png`, `screenshots/deal--default--ar--block.png` | (a) |
| **D9** | Offer expiry | a dated expiry · stands until answered | `expiry=dated` · `expiry=manual` | **a dated expiry on every offer, sender-set with a platform default; expiry leaves the request open for a new offer** (`expiry=dated`) | `screenshots/offer--default--ar--dated.png`, `screenshots/offer--default--ar--manual.png` | (a) |
| **D10** | How the two legs bind | atomic · independent | `legs=atomic` · `legs=independent` | **atomic: one deal, both legs accepted or none; a refused leg reopens the deal and the other leg's acceptance stays as history** (`legs=atomic`) | `screenshots/deal--default--ar--atomic.png`, `screenshots/deal--default--ar--independent.png` | (a) |
| **D11** | Percentile explainability | factors inline · factors on demand | `why=inline` · `why=ondemand` | **on demand — and moot for the target: the percentile engine is backlog; the per-criterion results are stored as its factors** (`why=ondemand`) | `screenshots/need--default--ar--inline.png`, `screenshots/need--default--ar--ondemand.png` | (a) |
| **D12** | The two state machines | six on the request and seven on the offer · one reconciled vocabulary | `states=two` · `states=one` | **two machines: Q11's seven are stored on the offer, the request's state is derived from its offers and never stored, S1's six survive as the derived vocabulary; C1 resolved without touching the lock** (`states=two`) | `screenshots/states--default--ar--two.png`, `screenshots/states--default--ar--one.png`, `screenshots/states--partial--ar--two.png` | (a) **and** (c) |

### The two halves each decision also has

Recorded so the reviewer is not asked twice. Each is the second question in that
decision's paragraph in `screens.md`, and none of them is answered by a switch.

| Id | The second half |
| --- | --- |
| D1 | Is an offer in the out-of-scope tray work the club owes? |
| D2 | Is the exchanged player's consent required before the exchange is **accepted**, or only before it is **registered**? |
| D3 | Is the threshold, or the rule, the club's to set or the platform's? |
| D4 | If the tree — who owns the taxonomy, the platform's registry or the club on each need? |
| D5 | Does a required miss **hide** the candidate or **show him refused**? |
| D6 | If a cut-off — is the club told how many were removed? |
| D7 | Does the counterparty's extra sight begin at **send** or at **agreement**? |
| D8 | What is "agreed" worth if it is not registrable? |
| D9 | Does an expired offer **reopen** its request or **close** it? |
| D10 | How long does a surviving leg stand? |
| D11 | Are the factors the same four for every need, or drawn from the need's own criteria? |
| D12 | If one machine — which words survive? |

---

# Conflicts with locked decisions

**Recorded, not resolved.** Both are named on screen and neither is quietly
picked. This section exists because the rule is that a prototype which finds a
locked decision wrong records it for a successor rather than rebuilding it — and
D12 is the one case where the successor is this prototype, so the conflict is
posed as a decision instead.

## C1 — The state vocabularies do not correspond

**`S1-whole-surface`, locked 18 سبتمبر 2026**, settled **six server-enforced
approach states** — `مرسل`، `قيد المراجعة`، `عرض مقابل`، `مقبول`، `مرفوض`،
`مسحوب` — and stated that no club configures them.

**Q11 of the 22 September response** specifies an **offer** state machine of
seven: `draft → sent → accepted/rejected/withdrawn/expired/superseded`.

| Word | In S1's locked six | In Q11's seven |
| --- | --- | --- |
| مرسل / sent | ✓ | ✓ |
| **قيد المراجعة / under review** | ✓ | **absent** |
| **عرض مقابل / countered** | ✓ | **absent** |
| مقبول / accepted | ✓ | ✓ |
| مرفوض / rejected | ✓ | ✓ |
| مسحوب / withdrawn | ✓ | ✓ |
| **مسودة / draft** | **absent** | ✓ |
| **منتهٍ / expired** | **absent** | ✓ |
| **متجاوَز / superseded** | **absent** | ✓ |

**Five words do not correspond.** The charitable reading — that the six now
belong to the *request* and the seven to the *offer*, and that `عرض مقابل` has
become `superseded` on the offer it answers — is a reading, not something the
response says. It is built as `states=two`. The reconciliation is built as
`states=one` and **it changes a locked decision**, which only a reviewer may
authorise. Drawn on `states.html`; the mismatch itself is
`screenshots/states--partial--ar--two.png`.

## C2 — A1 is priced in a way T1 forbids

**A1** — نادي الصحراء → فيصل الدوسري — is the cast's fully worked approach,
declared in `FIXTURES.md`, rendered across P5's locked screens and cited by its
screenshots. Its terms are a contract starting **1 يناير 2027** carrying **بدل
انتقال 2,400,000 ريال**. فيصل الدوسري's contract with نادي النهضة ends on **31
ديسمبر 2026**, the day before.

Under **T1** that is a **move at expiry**, and *"the owning club is not a party
to the fee."* A1 pays one.

**Not repaired.** A locked prototype is a dated record and the fixture it rests
on is not rewritten under it. The two T1 outcomes are built on other people —
A6 for the move at expiry, A15 for the immediate move with compensation — and
this conflict goes to the re-plan.

## Tensions — noted, not blocking

| | |
| --- | --- |
| **Two consent gates on one record** | P5 D3 locked the **owning club's** consent on the approach; T2 adds the **player's** as a second required gate with an explicit reject path. Not contradictory, and they must be unmistakably distinct on the same screen or the locked one stops reading correctly. Drawn side by side on `offer.html?state=partial`. |
| **T3 leaves the approach with one party** | S1 locked that *an approach is one shape for both sides*. An unlisted approach has no player side at all until the owner proceeds, so the record has a phase in which "both sides" is one side. |
| **T1 and P4's renewal rule run at once** | P4 locked that a club may renew its own person on any day. Inside the final six months the owning club's renewal and the person's outbound initiation are both live, and nothing says which reads first. |
| **The platform becomes an actor in a value flow** | P5 locked *no commission anywhere; the platform is not a party*. A sell-on percentage that the platform *calculates and notifies on* makes it one. Execution is deferred under T7, so the screen captures the 30% as structured data and states that nobody calculates it. |

---

# Write-back

Three destinations, one section each. **Nothing below is written back until a
reviewer has filled the outcome table** — a finding with no evidence is not
written back, and a decision with no outcome has no finding.

**No requirement id from any parked requirement document appears anywhere below.**

## (a) New stories — appended

> **Track A is held with Zayed.** The listing policy, the route flag, value as
> line items, the two legs and the audit are all model changes, and every one of
> them is on the hand-off list rather than written into `safqa-sport`. **Nothing
> in `safqa-sport` and nothing in the Track A half of `gh-project/manifest.json`
> was edited.**

Named by what they build, because these epics do not yet exist under an id in
`gh-project/manifest.json` — the same convention P5's `findings.md` used.
Append-only: never reorder or reword a story already there.

### Track D — the listing and its policy

```
- **As a club listing a professional**, I set a deal type or leave it unset, and restrict the listing to that type or not, so that what reaches me matches what I asked for.
  - Accept: the policy is a record of its own with room for more switches, not a column; deal type is nullable; the restriction is a separate boolean.
- **As a club whose listing is restricted**, I am told what happens to an offer of another type before I publish, so that I am choosing between two behaviours rather than ticking a box.
  - Accept: the composer states the behaviour the answer to D1 selects, and names the rule and the date it changes on any refusal.
### Track D — routes and the freeze

- **As any party to a request**, I read its route, so that I know whether withdrawing a listing affects it.
  - Accept: every request carries `market` or `direct` from creation; the route is on the row and on the record.
- **As a club withdrawing a professional from the market**, the market-route drafts and pending offers freeze and the direct ones do not, so that closing a channel does not close conversations that never used it.
  - Accept: nothing is deleted; the full history is retained; every participating club is notified of the state change.
### Track D — value

- **As a club composing an offer**, I record its value as line items, so that a deal carrying instalments, a player in exchange and a sell-on percentage survives being written down.
  - Accept: fixed fee, instalments, player exchange, add-ons, sell-on percentage and other are all line-item kinds; there is no single amount column anywhere.
- **As a club holding a sell-on percentage**, it is captured as structured data and executed by nobody, so that a deferred capability is not implied by the screen.
  - Accept: the percentage, its holder and its trigger are stored; the screen states that the platform neither calculates nor executes it.
### Track D — the free window and the gates

- **As a professional inside the final six months of my contract**, the priority to open a negotiation passes to me while my club keeps my contract, so that I can arrange my own next move.
  - Accept: eligibility derives from contract state and date, not listing status; the flip is at the contract's end minus six months; the owning club retains ownership and has a defined entry point.
- **As a professional at the end of my contract**, I move at expiry with no fee to my old club, or move immediately with my old club paid compensation, so that both real outcomes are supported.
  - Accept: the immediate path opens a club-to-club leg carrying a compensation value; the expiry path opens none.
- **As a professional or an agent**, my agreement is a required approval with an explicit reject path in every state, so that a club-to-club agreement without me is not a completed deal.
  - Accept: the reject path carries a stated reason; the gate is distinct on screen from the owning club's consent; neither gate is taken from the notifications inbox.
- **As a professional who was never listed**, an approach about me between two clubs reaches me not at all until my club decides to proceed, so that a routing constraint is not confused with a visibility setting.
  - Accept: no notification, no row, no openable record; the absence is genuine and is not drawn as a refusal.
### Track D — direct and confidential approaches

- **As a club approaching another club directly**, the approach is hidden from the market, from public feeds and from every club not involved, and is audited throughout, so that confidentiality means hidden from outer parties and not from each other.
  - Accept: the person or agent is notified once the clubs have agreed; the audit records the record regardless of who can read it.
- **As an agent acting for a client**, I approach a club that is not on the platform, so that a target outside the membership is reachable.
  - Accept: the club is held as a shadow record with a contact address; delivery is by email with an invitation to join attached; the record's state in the platform stops at "invitation sent".
- **As anyone reading a club row**, a member and a non-member are told apart, so that the action offered is the one that can actually happen.
  - Accept: a member is offered a tracked in-platform offer; a non-member is offered an email and an invitation.
- **As a club member composing an offer**, I save it as a draft and return to it, so that a long offer is not composed in one sitting.
  - Accept: save and resume exists under either answer to the approval decision; the approval is a separate, optional step that is off by default.
### Track D — the deal

- **As a club**, one deal carries a leg between two clubs and a leg between a club and the person or his agent, so that a negotiation with four possible participants is one record.
  - Accept: a transaction involves the owning club, the acquiring club, the person and his agent, and nobody else; four is a maximum, not a minimum, and a deal with three renders no empty seat.
- **As a club agreeing a deal**, I am told at the moment of agreement whether it can be registered, so that a registration window is not discovered at the point of failure.
  - Accept: agreed and registered are distinct states; the earliest registrable date is named.
### Track D — needs

- **As a club publishing a need**, the need is a saved market search on the same criteria schema the listing policy uses, so that searching and publishing are one mechanism.
  - Accept: one schema, two surfaces; a saved search can be run against the market or published to the board.
- **As a club with an open need**, it is answered both by people nominating themselves and by clubs offering players they hold, so that the candidate list reflects both ways a need is actually filled.
  - Accept: the two kinds are told apart on the row and have different downstream paths; a club-offered candidate opens a request with the offering club and then that person's own consent gate.
- **As anyone inside a publishing club**, I cannot apply to my own club's need, so that the rule is enforced rather than described.
  - Accept: the control is absent for anyone on the publishing club's roster, not present-and-refused.
- **As a club reading candidates**, a percentile indicator appears in search, in suggestions and in the applicant list, and the factors behind it are stored, so that a score that will be argued with can be explained.
  - Accept: the contributing factors are recorded alongside the score whichever answer to the explainability decision is taken.
### Track D — visibility

- **As a club**, I choose what each of three audiences sees of my data — the public, other clubs, and the counterparty in an active negotiation — so that one strategy governs every data type rather than a toggle per field.
  - Accept: the counterparty is a distinct audience; whatever is withheld is absent and never a refusal; every disclosure names the negotiation that granted it.
```

## (b) Notes on existing stories

| Epic | Which story | Note |
| --- | --- | --- |
| the offer-lifecycle epic | the offer state machine | **the conflict above.** Six on the request and seven on the offer do not correspond in five words; the vocabulary is not settled until D12 is answered |
| the offer-thread epic | the owning club's consent | unchanged and still an action on the approach — and now beside a **second** gate, the person's own, which has its own reject path |
| the send-and-inbox epic | the approach list | every row carries its route, and the freeze reaches the market route only |
| the deal-closure epic | the closed deal | a deal is two legs and up to four participants, and "agreed" and "registered" are different states |
| the club-needs epic | the published need | a need is a saved market search on the listing policy's own criteria schema, and it is answered by two kinds of candidate |
| the notification-centre epic | the event list | T1, T2 and Q6 each add several event types; they are enumerated once rather than accreted per feature |
| the friendlies epic | the friendly proposal | still deferred. P5's screen stands and nothing here is built on it |

## (c) Rules for the code repo — `.ai/rules/`

Recorded with the `record-rule` tool, never pasted into `CLAUDE.md`.

| Glob | Title | Note |
| --- | --- | --- |
| `src/**/offer*` | One open offer per request, not per person | "No new offer while one is pending" is a rule **inside** a request. Parallel requests from different clubs on the same person are allowed and are the normal case. |
| `src/**/offer*` | Two state vocabularies until C1 is ruled on | Do not collapse the request's six states into the offer's seven. S1 locked the six on 18 Sep 2026 and only a reviewer may change them. |
| `src/**/request*` | The route flag is written at creation | Every request carries `market` or `direct` from its first write. The freeze reads it. It cannot be inferred later. |
| `src/**/value*` | Value is never a single amount column | Line items only, from the first table that stores one. |
| `src/**/approach*` | An unlisted approach has no player recipient | T3 is a routing constraint. Do not implement it as a visibility flag that a query might later relax. |

---

## Rejected options

| Option | Why it was rejected | Evidence |
| --- | --- | --- |
| Rebuilding P5's four decisions as switches here | All four were locked on 21 سبتمبر 2026 and Q11 and T4 confirm two of them in the response's own words. Re-asking would ask the reviewer to re-decide something with a screenshot already behind it. | `../P5-requests-offers/findings.md` |
| Splitting the needs mechanism into a prototype of its own | P5 already owns three needs screens, so a split leaves P5 with two successors; the need's criteria schema **is** the listing policy's; and a club answering a need with a player it holds is a negotiation before it is a shortlist. | `screenshots/needs--default--ar--tree.png` |
| Drawing the audit trail as a screen | It is a storage rule that cannot be backfilled and has no surface of its own. The **visible** trail is S1's locked history row and already exists. | — |
| Inventing a season-history surface | Board item #18 is deferred by him. `season_id` is a storage rule; drawing a screen would contradict the deferral. | — |
| Putting the out-of-scope tray in the count of work owed | It would answer D1's second half by arithmetic. | `screenshots/inbox--default--ar--tray.png` |

## Not settled

Each names what would settle it.

- **Does the out-of-scope tray count as work owed?** Settled by a sentence from Raheem, not by a screen.
- **When does the counterparty's extra sight begin** — at send, or at agreement? Q8 draws confidentiality's boundary at agreement; #15 does not say it is the same one.
- **Who owns the position taxonomy** under D4's tree answer — the platform's registry, or the club on each need?
- **What closes a surviving leg** under D10's independent answer? Nothing in the response says how long a player agreement attached to no transfer stands.
- **Is a permission granted per listing, or per listing and per club?** PM1 is scoped to «أي نادٍ»; the response allows named clubs and the cast holds no example, because inventing one would have answered it.
- **Does an expired offer reopen its request or close it?**
- **What happens to a negotiation opened under a permission that is then revoked?** PM1 is revocable and has not been revoked.
- **The admin toggle that gates direct approaches per actor type.** Q8 says it exists. Its editor is a P3 screen; P3 is not superseded here and the toggle is on the Track A hand-off list.

## Lock record — 23 سبتمبر 2026

Locked by Zayed on his own authority, every decision answered in the grilling of 23 September 2026 and recorded on `sports-deal-web` #39. The second halves are answered there too: the tray is not work owed; an exchanged player is a valuation, so his consent is asked in his own request; the approval rule is the club's switch, off by default; the registry owns the flat position list; a required miss refuses and says which criterion; nothing is cut off; the counterparty's sight begins at send; "agreed" means the terms bind on the platform and "registered" means the federation step is done; an expired offer leaves the request open; no leg survives alone; the factors are the need's own criteria; the request's six words are derived from the offer's seven. C1 is resolved by derivation and touches no lock. C2 stands as a dated record under the superseded P5. The Track A write-back is the re-plan of the same day: [A3.9], [A3.8], [A3.1], [A3.2], [A3.5], [A3.7], [A1.5], [A2.8], [A0.18] in `gh-project/manifest.json`. The `.ai/rules` entries in (c) are recorded by the first Track A issue in each module; the rule "two state vocabularies until C1 is ruled on" is now "the request's state is derived, never stored".
