# `Profile` Convergence Roadmap

This document is the execution entrypoint for closing the remaining `Profile` umbrella problem after the merged repair / validation tracks.

## Current State

Completed repair / validation tracks:

1. `validation-01-system-permission-ssot-backfill.md`
   - fixed the `PermissionSet.Permissions* -> _System_PermissionSetPermission` gap
   - restored Setup gating for system-permission-driven entries

2. `validation-02-setup-object-permission-repair.md`
   - fixed the `restored system grants -> missing setup-object ObjectPermissions / FieldPermissions` gap
   - restored setup-object projection for `User`-management style forms

3. `validation-03-full-profile-gap-inventory.md`
   - converted the remaining `Profile` discussion into a concrete inventory
   - separated setup-object recovery from broader business-object drift

4. `validation-04-business-object-permission-reconciliation.md`
   - added reconciliation for partially seeded business-object `ObjectPermissions` / `FieldPermissions`
   - fixed forward correctness in the repair path for historical migrated drift

5. `validation-05-repair-path-business-permission-convergence.md`
   - wired the business-permission reconciliation logic into standalone `setup repair`
   - aligned the production repair entrypoint with the profile convergence path

6. `validation-06-verify-guardrail-for-profile-drift.md`
   - added a deep-verify guardrail for profile business-permission coverage drift
   - made profile coverage machine-checkable in the control-plane verify path

7. `validation-07-staging-final-acceptance.md`
   - validated the repaired profile path on staging with SQL + headless UI evidence
   - confirmed the main `#1806` repair cycle can remain treated as processed

These tracks solved the original `#1806` user-visible migration gap. The remaining work is now **post-convergence follow-up**, not a re-open of the original umbrella.

Additional profile-adjacent parity track discovered after the main convergence passes:

3. `PermissionSet` shadow/standalone semantics
   - profile-owned shadow permission sets (`IsOwnedByProfile=true`) must remain visible for internal/profile resolution paths
   - those same shadow permission sets must **not** be assignable through `PermissionSetAssignment`
   - admin-facing pickers should default to standalone permission sets, but raw/query/debug paths still need an explicit escape hatch

## Current Remaining Issues

After the merged repair cycle, the remaining profile-adjacent work is:

1. `#1919` — centralized admin-facing `PermissionSet` filtering semantics
   - current known leak sites can be patched individually
   - the remaining work is to establish one durable admin-facing default so new call sites do not forget the shadow-filter rule

2. implicit-child permission parity
   - `#1993` established the row-level baseline and the current product-form-parity runtime verdict for the row-level-proven children
   - the remaining `#1970` closure work splits objects into:
     - row-level-proven children (`QuoteLineItem`, `OpportunityLineItem`, `OrderItem`, `PricebookEntry`)
     - composite-access objects (`OpportunityContactRole`)
     - delegated/special-surface objects (`CaseComment`)
   - the current `profile-refactor-design.md` is execution-ready for the first two buckets, while `CaseComment` stays as an explicit deferred follow-up
   - `CaseComment` owner-model design is tracked separately in `docs/design/permission-system/casecomment-delegated-access-policy.md`
   - `ControlledByParent` proves row-level visibility / RLS, not automatic CRUD / FLS inheritance
   - closing this line now requires explicit per-object verdicts plus runtime + seeder + repair + verify alignment, not only another metadata entry or test

3. `#1920` — clearer profile verify / guardrail signal
   - the deep-verify helper exists
   - the remaining work is to make profile readiness easier to classify when unrelated environment drift is also present

## Working Model

Treat the remaining `Profile` work as three layers:

1. **Historical backfill**
   - repair already-broken migrated data
2. **Forward correctness**
   - ensure new environments and new metadata changes do not recreate the same drift
3. **Audit / detection**
   - make future drift visible before business users discover it

The merged `validation-01` through `validation-07` tracks mainly converged layer 1 and enough of layer 2 to restore the accepted user-visible profile behavior.

For the `PermissionSet` shadow/standalone semantics track, use a separate three-layer model:

1. **API parity**
   - reject invalid `PermissionSetAssignment` rows that target profile-owned shadow permission sets
2. **Admin-list correctness**
   - exclude shadow permission sets from admin-facing pickers and setup lists by default
3. **Declarative/default-query model**
   - centralize the default filter so future call sites do not need to remember it manually

## Remaining Questions

The historical migration-gap questions were answered by `validation-03` through `validation-07`.

The remaining questions are now narrower:

1. For `#1919`, what is the smallest durable centralization point for admin-facing `PermissionSet` filtering?
2. For the implicit-child permission line, which objects belong to the metadata-only bucket, and which ones need composite/delegated access modeling before runtime and profile convergence can treat them as closed?
3. For `#1920`, what operator-facing verify path gives a profile-specific pass/fail signal without being obscured by unrelated staging drift?

## Execution Plan

### Phase 1 — Completed Historical Repair / Validation

Goal:

- converge the original `#1806` profile migration gap with durable evidence

Completed outputs:

- `validation-01` through `validation-07`
- staging acceptance screenshots and SQL evidence
- `setup repair` / `setup verify` execution notes

Result:

- original profile migration symptoms are repaired and accepted
- remaining work moves to narrower post-convergence issues

### Phase 2 — `#1919` Admin-Facing `PermissionSet` Filtering

Goal:

- centralize the admin-facing default behavior for `PermissionSet` selection so shadow rows stop leaking through scattered query call sites

Scope:

- current known admin-facing leak sites such as setup lists and assignment pickers
- preserve explicit internal/profile-resolution readers that intentionally need `IsOwnedByProfile=true`

Expected output:

- one centralized admin-facing query path or equivalent durable mechanism
- tests for both the filtered admin path and the explicit shadow-reading path
- validation note under `docs/profile/` if the UI surface changes materially

Exit criteria:

- current admin-facing `PermissionSet` lists do not show profile-owned shadow rows by default
- internal/profile-resolution paths still work
- future contributors have one documented place to reuse instead of hand-adding the filter

### Phase 3 — Implicit-Child Permission Parity

Goal:

- close the current execution-ready stage of `#1970` without leaking unsupported CRUD/FLS inheritance or leaving seeder/verify tails behind

Scope:

- keep metadata-only row-level behavior for the already-approved children
- keep the accepted product-form-parity verdicts for the row-level-proven bucket unless a future design-doc PR changes them
- add the generic metadata-authored composite-access primitive needed by `OpportunityContactRole`
- execute `OpportunityContactRole` against the already-frozen owner model, and treat `CaseComment` as a separate dedicated design/implementation follow-up under `docs/design/permission-system/casecomment-delegated-access-policy.md`
- align seeder / repair / verify expectations with whichever objects stop owning self permission rows
- keep destructive cleanup in `data-specs/` only after the steady-state owner model is approved

Why this shape is intentionally more flexible:

- row-level parity can land without pre-committing CRUD/FLS inheritance
- metadata-only children can preserve their admin-authored surface
- composite/delegated objects can gain the correct product boundary without object-name branches
- the closure work can converge all layers, not only runtime behavior

Exit criteria:

- row-level-proven children keep the proven row-level behavior and stay covered by explicit product-form-parity verdicts
- `OpportunityContactRole` no longer depends on the fake generic self-owned model
- `CaseComment` remains an explicitly tracked follow-up until its dedicated owner-model design is implemented and validated
- runtime, seeder, repair, and verify all agree on the same ownership model

### Phase 4 — `#1920` Verify / Guardrail Signal Quality

Goal:

- make future profile validation easier to classify when unrelated verify noise exists

Candidates:

- narrower profile-specific verify mode
- clearer classification of existing deep-verify output
- documented fallback path when staging has unrelated global verify failures

Exit criteria:

- profile convergence can be checked with a signal that is easier to interpret than the current all-or-nothing staging verify output
- the chosen validation method is documented in `docs/profile/`

## Recommended Order

Run the remaining work in this order:

1. `#1919` — centralize admin-facing `PermissionSet` filtering semantics
2. implicit-child permission parity — execute the staged closure plan in `profile-refactor-design.md`, starting from the proven row-level baseline and finishing only after the composite/delegated objects plus convergence layers are closed
   - execute against `profile-refactor-design.md`
   - do not treat the line as closed until the composite/delegated objects and convergence layers are also resolved
3. `#1920` — refine the profile verify / guardrail signal once the remaining runtime semantics are stable

This order matters:

- `#1919` removes the most likely recurrence path on live admin-facing surfaces
- the implicit-child permission line now carries an execution-ready staged closure design and must converge runtime, seed, repair, and verify together for the in-scope buckets
- `#1920` should harden the validation signal after the remaining runtime semantics are settled

## What Not To Mix In

Do **not** mix these into the next `Profile` convergence PR unless the evidence shows they are truly the same root cause:

- approval-runtime security-context issues
- pure field-capability bugs such as `createable=false / updateable=false`
- unrelated frontend rendering bugs without permission evidence

These may interact with the same symptoms, but they are different repair classes.

## Definition of Done for the Follow-Up Line

The post-`#1806` profile follow-up line should be considered converged when all of the following are true:

- admin-facing `PermissionSet` selection semantics are centralized and do not leak shadow rows by default
- implicit-child follow-up work respects the rule that `ControlledByParent` alone proves row-level behavior, not automatic CRUD/FLS inheritance, and it closes the in-scope object classes through a generic metadata-authored model rather than one-off branches while keeping deferred buckets explicit
- profile-related verification can produce a clearer machine-checkable signal even when broader environment drift exists
- any remaining profile-adjacent symptoms can be mapped to non-profile root causes or separately tracked issues

Until then, treat the `Profile` line as **main migration gap repaired, follow-up hardening still in progress**.
