v4.10 — Accountability Partner Goal Sharing
A user can now share one specific goal with their accountability partner, without making it public — off by default, reversible, and never retroactive.
Summary
Before this milestone, a confirmed accountability partner could only ever see a user's public goals — their private goals stayed invisible even to the one person explicitly trusted for accountability. OBJ-1567 surfaced this gap when a partner-focused public-profile feature (partnerGoals) was first built: its naive draft fixed the gap by returning every private goal to any confirmed partner, which would have silently widened the privacy boundary a user sets the moment they accept a partner request.
v4.10 rejects that naive fix. It ships a shared_with_partner flag on individual goals, independent of the existing private flag, so a user opts a specific private goal into partner visibility one goal at a time. A confirmed partner sees the union of a user's public goals and their explicitly-shared private goals — on the public profile and in the missed-day accountability alert — through one shared read-time rule that can't drift between the two surfaces. Everything else about a goal's privacy is unchanged, and turning sharing off restores full privacy instantly.
The work shipped in three sequential phases — data model and backend rule, sharing UI and profile surface, then this documentation pass — all merged to master on 2026-07-21. Staging-only for now; production promotion rides the next Wednesday 08:00 CT release train per standard beta-ship policy.
Goal
Let a user opt in specific goals to visibility with their accountability partner via a new
shared_with_partnerflag on goals — independent ofprivate. A confirmed partner sees the watched user's public OR explicitly-shared goals on the public profile and in the missed-day alert job; a private goal stays private until the owner explicitly shares it. Consent stays explicit, matching the anti-dark-pattern / privacy posture indocs/product/privacy-controls-prd.md.
Scope — What Shipped
- New
shared_with_partner:booleancolumn ongoals(defaultfalse, indexed, additive migration — no retroactive exposure) Goal.partner_visiblescope (private = false OR shared_with_partner = true) — the single rule consumed identically by the public profile and the missed-day alert job- Owner-only
GoalTracking::SetGoalPartnerSharinginteraction +setGoalPartnerSharingGraphQL mutation PublicProfileTypegainedpartnerGoalsandviewerIsAccountabilityPartnerfields, populated only for a confirmed active accountability partnerSocial::GeneratePartnerMissedDayAlertsJobswitched from a public-only scan to.partner_visible- Frontend
GoalPartnerSharingCard.vueon Goal Detail — the per-goal sharing toggle - Public profile "Shared with you" section, gated on
viewerIsAccountabilityPartnerrather than array length (defense-in-depth against ever rendering an empty partner section as if it were populated) - Docs:
docs/features/accountability-partners.md§ Per-goal partner sharing,docs/features/allies.md§ Accountability partners see more than regular allies,docs/product/privacy-controls-prd.md§ Per-goal accountability-partner sharing (v4.10) - Both
CHANGELOG.mdandionic_frontend/CHANGELOG.mdupdated
Phases
| Phase | Name | Status | Plans | Highlights |
|---|---|---|---|---|
| 1 | Data model + backend partner-visibility rule | Shipped | 1 | shared_with_partner column, Goal.partner_visible scope, setGoalPartnerSharing mutation, partnerGoals/viewerIsAccountabilityPartner resolver fields, missed-day job switched to the shared scope. PR #1644. |
| 2 | Sharing UI + public-profile surface | Shipped | 1 | GoalPartnerSharingCard.vue on Goal Detail; "Shared with you" profile section gated on partner status, not array length. PR #1677. |
| 3 | Docs + CHANGELOG | Shipped | 1 | Feature docs, privacy PRD alignment, both CHANGELOGs. PR #1681. |
Key Decisions
- Per-goal opt-in over global override — rejected "any confirmed partner sees all private goals" because the missed-day job already never surfaced private goals to partners; a global override would have newly leaked them against the app's explicit-consent privacy posture.
- Coexist, not unify, the two visibility models — public-goal visibility and the new private-goal opt-in run side by side, unified only at the read layer by one scope (
Goal.partner_visible) applied identically everywhere a partner's goal list is computed, so the two surfaces cannot silently diverge. - Frontend gate on partner status, not list length —
PublicProfile.vuerenders the "Shared with you" section based onviewerIsAccountabilityPartner, never on whetherpartnerGoalshappens to be non-empty. Independently re-verified against the backend resolver during both Phase 2 review and this milestone's audit. - Toggle lives on Goal Detail, not a global settings page — a per-goal control matching the per-goal data model, so sharing reads as a decision about this goal, not an account-wide setting.
Requirements Coverage
8 / 8 requirements satisfied (per .planning/milestones/v4.10-partner-goal-sharing-MILESTONE-AUDIT.md).
| Category | Count | Status |
|---|---|---|
| Backend (BE-1–BE-6) | 6 | All satisfied |
| Frontend (UI-1, FE-1, FE-2) | 3 grouped as 2 tracked items | All satisfied |
| Docs (DOCS-1, DOCS-2) | 2 | All satisfied |
Full checklist: v4.10-partner-goal-sharing-ROADMAP.md on GitHub.
Outcomes
A user can now trust their accountability partner with exactly as much visibility as they choose, one goal at a time — never all-or-nothing, never retroactive, and always reversible. The partner relationship becomes more useful without widening anyone's privacy boundary by default: a partner who previously saw only public goals can now also see the specific private goals a user has chosen to open up, both on the public profile and in the missed-day nudge that makes the partnership actually work day to day.
Tech Debt
- (Phase 2) ARIA
role="switch"button used onGoalPartnerSharingCard.vueinstead of the UI-SPEC's<ion-toggle>; non-blocking. - (Phase 2) A state-merge omission on mutation success, and a test-coverage gap for the no-partner gate — both flagged by review as non-blocking nits, not fixed in this milestone.
- (Milestone-wide) CI's "Capture UI Evidence" job only captured
/dashboardacross all three phases; the new Goal Detail and profile surfaces were exercised functionally (Cypress/Playwright/a11y) but never appear in the visual-evidence artifact. - (Follow-up candidate, future milestone)
AccountabilityPartnerGoalExclusion— the public-goal opt-out mechanism this milestone's planning assumed already existed — turns out to be a phantom: a factory and adefined?-guarded dead branch with no backing model or table. Either build it or remove the dead code path.
Related Artifacts
- Roadmap: v4.10-partner-goal-sharing-ROADMAP.md
- Milestone Audit: v4.10-partner-goal-sharing-MILESTONE-AUDIT.md
- PRD context: Privacy Controls PRD (§ Per-goal accountability-partner sharing, v4.10 addendum — broader "Go It Alone"/Private Mode scope in that PRD is unrelated to this milestone and remains unbuilt)
- Git tag: not yet cut — staging-only, rides the next Wednesday release train
- Merge PRs: #1644 · #1677 · #1681
Related Commits
f437a74a— feat(public-profile): add viewer-relative partnerGoals field (OBJ-1572) (#1644)668da974— feat(goals): per-goal accountability-partner sharing UI (OBJ-1585) (#1677)344a8895— docs(v4.10): document per-goal accountability-partner sharing (#1681)
Last updated: 2026-08-04 Version: v4.10