Estimate: 55m · Depends on: 6.14.4, 6.14.7
Lock the load-bearing guarantee: a public/non-member viewer can NEVER read a private epic’s children — via ANY read path — while a member can, and the aggregate tells never leak. On a real Postgres (the standing rule), covering:
- Server-side exclusion at EVERY read path. Make an epic private on a public project; as a cross-org NON-MEMBER viewer, assert its children are ABSENT from the PAYLOAD (not the DOM) of: the TREE projection, the DETAIL child-panel read, the 6.12 public BOARD, the 7.0 ready SET, and a 6.1 FilterAST SEARCH that matches a child’s title. A PARAMETERIZED test over the read set so adding a new public read without the predicate is caught.
- No aggregate-tell leak. Assert the private epic’s public-projection ROW carries title / kind / status + the "children-hidden" marker but OMITS child count, progress / rollup, and point total — asserted at the payload level.
- Member bypass. As a PROJECT MEMBER, assert the SAME epic’s children ARE present and the real child count / progress / points ARE returned (the exclusion is non-member-only); assert the flag is a no-op on a NON-PUBLIC project and for a member on a public project.
- The admin toggle. Assert
setEpicPrivacy flips enforcement (set → the non-member loses the children; unset → regains them); setting it on a NON-EPIC is rejected; a NON-ADMIN is rejected (403, the 6.4 check); the epic-kind + admin guards each have a direct test.
Acceptance criteria
- The exclusion is asserted at the PAYLOAD level for tree, detail child-panel, public board, ready set, AND FilterAST search for a non-member; the parameterized read-set test fails if a public read omits the predicate.
- The aggregate-tell strip (count / progress / points omitted + the marker present) and the member-bypass (children + real rollups returned) are each asserted; the non-public-project no-op is asserted.
- The admin toggle (set/unset flips enforcement), the non-epic rejection, and the non-admin 403 are asserted; new service/repository code respects the per-file coverage gate (CLAUDE.md § coverage); the epic-kind / admin / already-set guards each have a direct test; tests use the real Postgres helper.
Context refs
- 6.14.4 (the server-side enforcement under test), 6.14.7 (the admin toggle), 6.14.3 (the flag).
scripts/plan-seed/data/story-6.12.ts § 6.12.9 — the public-access test harness (cross-org viewer vs member) this extends.
motir-core/CLAUDE.md § tests-use-real-Postgres + the per-file coverage gate.
motir-core/tests/helpers/db.ts — the per-test truncation harness.