m's go/no-go pass at 2026-05-06 15:58: "I agree with all your recommendations
- go." All 19 questions in §6 lock as the recommended answers verbatim.
§0 status flipped from READY-FOR-REVIEW to LOCKED. New "Locked m decisions
on §6" subsection captures the highlights inline so future readers don't
have to scan the whole table to know what's pinned.
§13 end-of-design line updated to reflect the lock.
Implementation phasing (§7) unchanged:
- Phase 1: bug fix on the 3 narrow service methods (no schema, ~400 LoC,
ships standalone, closes the user-visible /projects/{id} "Keine Fristen"
bug).
- Phase 2: migration 055 (partner_unit_members.unit_role,
project_partner_units, extended can_see_project()) + DerivationService +
frontend Team-tab subsections + /admin/partner-units unit_role tagging
+ project /settings/team Partner Units section. Independent of t-138.
- Phase 3: approval extension — canApprove + inbox SQL widening for
derived_peer decision_kind. Gates on cronus's t-138 (currently on
mai/cronus/inventor-dual-control @ b3401ec) landing on main.
Inventor parked. Awaiting head's coder-shift assignment.
Three coordinated sub-designs in one doc, scoped to m's locked constraints
(2026-05-06):
1. Surface-by-surface aggregation policy. Bug surface fix:
/projects/{client_id} renders "Keine Fristen" because
DeadlineService.ListForProject + AppointmentService.ListForProject +
ProjectService.ListProjectEvents all WHERE project_id=$1 exact-match
instead of walking paliad.projects.path descendants. The shipped t-124
contract (projectDescendantPredicate, deadline_service.go:133 etc.)
already aggregates correctly on the union endpoints — three legacy
narrow paths just bypass it. Per-surface decision table for events /
deadlines / termine / Verlauf / project tree counts / dashboard /
CalDAV / email / search.
2. Effective-team semantics. Three structural gaps in the issue's
premise (verified against schema):
- No project↔unit junction (partner_unit involvement on a project).
- No PA/lawyer distinction in partner_unit_members (no role column).
- No lawyer↔PA pairing anywhere — Q11's "where is it stored" → nowhere.
Proposes:
- paliad.partner_unit_members.unit_role (lead|attorney|senior_pa|pa|paralegal),
unit-scoped not firm-wide so 3-axis principle holds.
- paliad.project_partner_units junction with derive_unit_roles[]
(default {pa, senior_pa}) + derive_grants_authority bool.
- Compute-on-read derivation via extended can_see_project() — no
materialised state, no drift.
- Display-effective vs visibility-effective team are different sets;
rename ListEffectiveMembers to ListVisibilityEffectiveMembers + add
ListSubtreeMembers.
3. Approval policy × hierarchy × derivation. Coordinates with t-138
(cronus, mai/cronus/inventor-dual-control @ 7d1ddb9):
- Q10: keep cronus's no-auto-inheritance, harden UX with a "Eltern-
Politik (zur Information)" panel showing parent rules without
applying.
- Q12: derived members visibility-only by default; per-(project, unit)
opt-in flag derive_grants_authority. When opted in, decision_kind
extends with derived_peer for honest audit chronology.
- canApprove + inbox SQL extension shape spec'd; coordinates with
cronus's t-138 §3.4 / §7.4.
Locked m decisions surfaced in §0:
- Behaviour is surface-specific.
- Effective Team of a Client = direct ∪ descendants ∪ partner-unit-derived.
- PA derivation = unit-on-project trigger.
- Derivation honesty: annotated everywhere.
- paliad-only scope.
19 design questions with proposed answers in §6 for m to lock. Migration
055 specced (§5). Implementation phased into 3 PRs (§7) — Phase 1 bug fix
ships standalone if m wants quick win.
Inventor parked. Awaiting m go/no-go before coder shift.