test/docs(ownership): §7 apply_ownership journey + design/CLAUDE updates

End-to-end coverage of the M1 ownership claim through the real CLI + server:
claim-on-first-apply + owner column, idempotent re-apply by the owner, a
second project refused (409, naming the owner), --takeover by an admin,
app-inheritance from the nearest claimed ancestor (owning project ok; foreign
or absent project refused), and the capability gate — a member with only an
editor GROUP role can reconcile but is refused --takeover (needs group-admin),
with ownership unchanged after the failed takeover.

- tests/apply_ownership.rs (registered in cli.rs); a grant_group_membership
  helper in tests/common/member.rs (group-level, mirroring the app one).
- design doc §7 gains an M1-shipped status note; CLAUDE.md records §7 M1 and
  re-points 'Next' at M2 (attach ceiling) + M3 (blast-radius / pic projects ls).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-06 20:49:31 +02:00
parent b33c87e5c4
commit 5bd72956b1
5 changed files with 257 additions and 1 deletions

View File

@@ -764,6 +764,22 @@ non-orphaning:
**Corollary:** don't co-own a node — split config downward. Shared config lives *higher* (owned by a
platform/shared repo attaching at root); team-specific bits go into subgroups each team owns.
**Status — M1 shipped (the ownership claim).** The `owner_project` seam (0047) is now live, backed by a
first-class `projects` table (`0066`, UUID pk + unique slug; `owner_project` FKs it `ON DELETE SET NULL`).
A `[project]` block (slug + optional name) in the repo's root manifest declares identity; the first apply
with a new slug registers the project and **claims** each group node it touches. The claim is a gate run
inside the apply transaction, under the per-node advisory lock, *before* the diff — so a conflict
short-circuits with a 409 before any write. Pure policy (`decide_group_claim` / `decide_app_owner` in
`apply_service`): unclaimed→claim, owner→no-op, foreign→conflict unless `--takeover` (which additionally
requires `GroupAdmin` — ownership ⟂ RBAC), no-project-into-a-claimed-subtree→conflict. Apps carry no
`owner_project`; an app inherits ownership from its **nearest claimed ancestor group** (the ancestor walk
is the boundary), and an unclaimed subtree stays open (backward-compatible — nothing changes until a repo
first declares `[project]`). Visibility: `pic groups ls` shows an `owner` column; `--takeover` on `pic
apply`. Pinned by `apply_service` unit tests + the `apply_ownership` journey. **Deferred:** point 2's
attach-point *ceiling* (M2 — `[project] parent_group`), and the plan-time cross-repo blast-radius preview +
`pic projects ls` (M3). The **structural-divergence** detection of §6 and declarative group create/reparent
(lifting "groups pre-exist") remain later work.
---
## 8. Diagrams