Commit Graph

3 Commits

Author SHA1 Message Date
Ben Stull c9fd1c535e §22 S4: scope-role invitation backend + capability flags (@S4 C.2)
The Owner-only scope-role grant surface (Part E S4 / Part C.2). An Owner
grants {owner, contributor} at a scope their reach covers — the project or
one collection within it — to an existing account looked up by email; the
grant writes a `memberships` row immediately and §15-notifies the grantee
(direct grant, no accept round-trip — the C.2 scenarios name existing
accounts and write the row directly).

- auth.can_invite_at_project / can_invite_at_collection — the Owner-reach
  invite gates (is_project_superuser / is_collection_superuser).
- memberships.py — grant (with the C.2.6 broader-supersedes-narrower prune,
  preserving a stronger child grant — no negative override), revoke, list,
  user_by_email.
- api_memberships.py — GET/POST/DELETE /api/projects/:id/members, the single
  POST keying on optional collection_id so the invite UI's one control maps
  to one endpoint; reach bounded by the inviter's Owner reach (C.2.3);
  contributors refused (C.2.4); a pending grantee's row is recorded but
  confers no write (C.2.7, the §6 floor).
- notify.notify_scope_role_granted + render_summary — the §15 personal-direct
  notification naming the project and role.
- api_collections — surface viewer capabilities (can_create_collection,
  can_invite, can_contribute, role) on the project/collection GETs to drive
  the C.3 role-aware empty states.

Acceptance: test_s4_invitations_vertical.py covers C.2.1–C.2.7 over the HTTP
surface + resolver, plus the C.3 (@S4) capability flags. Full suite green
(504 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 23:47:28 -07:00
Ben Stull c2f566512a §22 S3: scope-role enforcement + collection-grain visibility (@S3) — v0.42.0
Implement slice S3 of the §22 three-tier refactor: the four-layer
most-permissive scope-role resolver (§B.2) over {owner, contributor}
grants at {global, project, collection}, with the §22.5 visibility gate
enforced at the collection grain.

- migration 030: memberships.scope_type += 'global' (the global RFC
  Contributor tier; sentinel scope_id '*').
- auth.effective_scope_role folds global → project → collection,
  most-permissive, no negative override; can_read_collection /
  can_contribute_in_collection / is_collection_superuser /
  can_create_collection gate reads, writes, admin, and create.
- collection-grain visibility: a gated collection is hidden from the
  public (404, omitted from the directory) yet visible+listed for a
  scope-role holder; a collection may be set only as strict or stricter
  than its project (public < unlisted < gated), validated at create and
  clamped at the mirror.
- entry-scoped authority (mark-reviewed, graduate, branch read/contribute,
  PR/discussion/contribution moderation) re-pointed from the project grain
  to the entry's collection.
- create-collection authority widened to a project/global-scope grant
  holder (§B.1), not only a deployment owner/admin.

Keystone reconciliation (session 0076): a plain granted account is a
granted *account*, not a write-everywhere global role; the implicit-public
write baseline is grandfathered onto the migration-seeded `default`
collection only, so the N=1 deployment loses no capability. Reinterprets
§B.1/§B.3 literally — flagged for the SPEC merge (S6).

Completes @S3 (C1.1–C1.8). Tests: test_s3_scope_roles_vertical.py (8 C.1
scenarios + visibility/strictness), test_migration_030_global_scope.py.
Full backend suite 493 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 18:07:51 -07:00
Ben Stull 0c654b173d §22 S2: create-collection endpoint (bot commit + registry refresh)
POST /api/projects/<id>/collections, owner/admin-gated, commits a
.collection.yaml to the content repo main via bot.create_collection, then
re-mirrors the registry so the collections row appears (§22.2). Adds GET
list/one collection routes. Extends FakeGitea to model directory listings so
the mirror's content-repo walk is exercised end to end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 13:10:09 -07:00