Every pond created through the api now carries one, and the matrix pond
is created that way. The start page is an ordinary page with no grant of
its own, so it follows the pond-wide permissions: the three member
subjects each see one more, the label-restricted editor too, and the
outsider — who reaches only the explicitly public page — still sees one.
The 429 in the same run was the login rate limit, reached through the
retries of this failure rather than on its own.
The permission-matrix pack now covers comments: reading follows page
read, writing follows the pond's commentPolicy, label-restricted editors
cannot see a secret page's thread, all under the 404-vs-403 policy. A
new API-level social pack runs the two-user watch → notify flows: the
watcher is notified, the actor never, read-all sticks server-side, a
revoked watcher receives nothing new, and the digest job runs end to end
through the system panel's manual trigger. The digest mail's structure
is pinned by a normalized vitest snapshot (grouping, counts, actors,
unsubscribe framing) — changing the mail requires an explicit snapshot
update. Both packs ran flaky-free across five consecutive local rounds.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1
Permissions cut across every M2–M5 feature; this pack pins the security-relevant
subject × surface combinations so a weakened guard is caught.
- `apps/web/e2e/permission-matrix.spec.ts`: an API-level (the UI adds nothing
over the resolved status code) parameterized suite over the subjects — site
admin, pond admin/owner, editor, the same editor label-restricted by a
`secret`-label deny, reader, public (anonymous), and the foreign user (new
`fixture-outsider`, a member of nothing) — across the surfaces: page read,
edit (collab-token `rw`/`ro`), sidebar list, search, versions, media, and the
public HTML endpoint. It enforces the 404-vs-403 policy: an unauthorized read
is 404 (existence hidden), an unauthorized write on something readable is 403.
- wired into the pipeline as its own CI step; documented in
`apps/web/e2e/README.md` (with the subject/surface list) so later features
extend the matrix rather than writing bespoke permission tests.
- seeded-regression check (acceptance criterion): temporarily forcing the
collab-token to always `rw` (ignoring write permission) makes the pack go red
on the "reader gets `ro`" and public/foreign cells — verified locally, then
reverted. Runs in ~1 s (well under the 10-minute budget).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1