# Multi-Company — Write Path & Cross-Company Permissions (P6 decision)

> Status: **decision needed from product.** Reads are already multi-company on the
> flipped models; this doc settles what happens on **writes** and what a `company`
> scope authorizes. See also [tenant-registry.md](tenant-registry.md).

## The two questions

1. **Write target** — when a user with access to several companies *creates* a record,
   which company does it belong to?
2. **Cross-company authority** — does being granted access to company B let a user
   *modify/delete* B's data, or only *see* it?

These are linked: if cross-company access is read-only, writes always target the home
company and question 1 is moot.

## Recommendation — Phase 1: read-only cross-company

A `company` scope grants **visibility, not write authority**. Concretely:

| Action | Scope |
|---|---|
| List / show / export (reads) | **Accessible set** (home + granted companies + their children) — via `TenantScope` |
| Create | **Home company only** (`userCompany->id` / owner) |
| Update / delete / state-changes | **Home company only** (explicit guard) |

This is already the state of the code: every flipped model's reads go through
`TenantScope`, while `store()` stamps the home company and mutation guards
(`isUserAllowed` = `company_id === userCompany->id`) keep writes home-only.

**Why this default**
- Matches the spec's "access control delegated to the auth system" — a *read* scope is
  the simplest grant; write authority is a stronger, separate grant that shouldn't be
  implied by visibility.
- No over-privilege: a user given visibility into a partner/child company can't silently
  mutate its data.
- Zero new write-path code; ships with the read flips.
- Fits the "Final Simplified Model" — the common need ("see across my group's companies")
  is satisfied without the complexity of cross-company write arbitration.

## Phase 2 (only if product wants cross-company writes)

If writing into another accessible company is a real requirement, add — *not before*:

1. **A separate write grant in the auth system** — e.g. a `company_write` scope (or a
   per-company role), distinct from the read `company` scope. Visibility ≠ authority.
2. **Target-company selection** — an `X-Company-Id` request header (default = home),
   resolved + validated against the accessible set by `AccessibleCompanyResolver`.
   Reject if not accessible / not write-granted.
3. **Stamp the resolved target** on create instead of home; gate update/delete on the
   write grant for that record's company.

Mechanism sketch (per request): `targetCompanyId = header ?? home`; assert
`targetCompanyId ∈ accessibleCompanyIds` **and** user has `company_write` for it;
then `data['company_id'] = targetCompanyId`.

## Decision required

Confirm **Phase 1 (read-only cross-company)** as the shipping default — or tell me a
concrete case that needs cross-company writes, and I'll spec Phase 2 against it.
Until then the code stays read-only-correct and no write paths change.
