TenantAtlas/specs/277-stored-reports-surface/research.md
Ahmed Darrazi db83112edc
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 6m41s
WIP: commit changes for PR to platform-dev
2026-05-06 01:50:13 +02:00

5.4 KiB

Research: Stored Reports Surface v1

Date: 2026-05-06
Branch: 277-stored-reports-surface

Decision 1: Use one tenant-panel Filament resource with list and view pages

  • Decision: Implement the new surface as one tenant-scoped Filament resource with a register and a read-only view page.
  • Rationale: The repo already uses tenant-panel Filament resources with clickable-row inspection and infolist-style view pages for read-only registry surfaces. That keeps the slice inside the current UI contract, keeps Livewire behavior native, and avoids a bespoke report-view shell.
  • Alternatives considered:
    • Custom dashboard page or widget-only viewer: rejected because it would create a parallel navigation and interaction model for a standard read-only registry surface.
    • Edit-page-as-view workaround: rejected because the constitution requires inspection surfaces to use view/infolist semantics rather than disabled edit forms.

Decision 2: Reuse StoredReport and ArtifactTruthPresenter instead of creating new lifecycle truth

  • Decision: Keep StoredReport as the only persisted truth and reuse ArtifactTruthPresenter::forStoredReport() for current versus historical retained state.
  • Rationale: The presenter already computes retained lifecycle truth by comparing the current row to the latest same-family row for the tenant. A second status column, mirror record, or new presenter layer would duplicate truth the repo already has.
  • Alternatives considered:
    • Persist a current flag or second lifecycle column on stored_reports: rejected because current versus historical is already derivable from existing rows.
    • Introduce a new stored-report-specific presenter or envelope system: rejected because ArtifactTruthPresenter already covers stored reports.

Decision 3: Add explicit permission_posture.view instead of piggybacking on unrelated capabilities

  • Decision: Introduce one bounded permission_posture.view capability alongside the existing entra_roles.view capability.
  • Rationale: The spec requires family-aware browse and detail visibility. Reusing provider.view, review_pack.view, or evidence.view would blur ownership between the stored-report surface and downstream consumers.
  • Alternatives considered:
    • Reuse provider or evidence capabilities: rejected because the stored-report surface would become coupled to unrelated read paths.
    • Introduce one generic stored_report.view capability: rejected because the repo already has two concrete families with separate product meanings, and family-aware filtering is part of the feature value.

Decision 4: Support exactly two family summary branches and keep all other families out of v1

  • Decision: Render explicit summary branches only for permission_posture and entra.admin_roles, and keep any unexpected report family entirely outside v1 browse and detail scope.
  • Rationale: The repo has exactly two concrete stored-report families today. The narrowest correct implementation is explicit presentation for those families only. A local catch-all renderer would still need an authorization story and would widen the surface contract beyond the two repo-real families.
  • Alternatives considered:
    • Generic report-schema registry or plugin renderer: rejected because two concrete cases do not justify a framework.
    • Local catch-all renderer for unexpected families: rejected because it widens the browse/detail contract without a bounded authorization story.

Decision 5: Canonical drilldown stays on the one confirmed widget seam

  • Decision: Make the stored-report detail route the canonical drilldown target for AdminRolesSummaryWidget only.
  • Rationale: The widget is the clearest current repo-real missing launch point. The codebase does not currently expose broad Filament proof links to stored reports, so the package should not invent new local report cards or pseudo-view links just to claim convergence.
  • Alternatives considered:
    • Widget-only link with no register: rejected because it would leave stored-report browsing fragmented.
    • Add new stored-report links to every evidence or review surface up front: rejected because repo truth does not currently show broad operator-facing stored-report launch affordances there.

Decision 6: Keep proof in focused feature tests and skip browser by default

  • Decision: Plan feature coverage for register behavior, entitlement behavior, detail presentation, and widget drilldown, with no default browser lane.
  • Rationale: The surface is native Filament list and view behavior plus a widget link. The main risks are authorization and disclosure rules, not browser-only choreography.
  • Alternatives considered:
    • Browser smoke as a default requirement: rejected because the slice does not introduce a custom interaction model.
    • Large unitized presentation layers: rejected because that would create indirection just to make testing easier.

Final Research Outcome

  • One native tenant-panel Filament resource is the narrowest correct surface shape.
  • Existing stored-report truth and artifact-truth lifecycle semantics are sufficient; no new persistence or lifecycle framework is needed.
  • permission_posture.view is the only new capability required.
  • Summary rendering stays explicit for the two repo-real families and avoids a registry.
  • Canonical drilldown starts and ends in v1 with the admin-roles widget seam.
  • Focused feature tests are the honest default proving path.