# Research: Structured Snapshot Rendering & Type-Agnostic Item Browser **Feature**: 130-structured-snapshot-rendering | **Date**: 2026-03-09 ## R1: Rendering architecture for mixed policy types **Decision**: Introduce a page-level `BaselineSnapshotPresenter` backed by a `SnapshotTypeRendererRegistry`, dedicated per-type renderers, and a shared fallback renderer. **Rationale**: The current detail page hardcodes summary parsing and `intuneRoleDefinition` item extraction directly inside `BaselineSnapshotResource`. The repo already favors registry and strategy patterns for type-specific logic, especially through the policy normalizer architecture. A presenter plus registry cleanly separates page composition, type-specific enrichment, and shared fallback behavior while satisfying the spec requirement that new policy types become visible without page-template edits. **Alternatives considered**: - Keep conditional rendering in `BaselineSnapshotResource`: rejected because the current problem is precisely that the page already mixes ad hoc type-specific behavior with raw payload dumping. - Build one giant generic mapper with embedded `switch ($policyType)` branches: rejected because it scales poorly as new types are added and makes regression isolation harder. ## R2: Minimum data contract for fallback rendering **Decision**: Base the fallback renderer on guaranteed fields already available from `BaselineSnapshot.summary_jsonb` and `BaselineSnapshotItem.meta_jsonb`, with the minimum item contract built from display name, category or platform hints, evidence provenance, identity hints, and optional source references. **Rationale**: Current snapshot data already includes deterministic snapshot-level counts by policy type, fidelity counts, gaps, and item metadata with evidence provenance and identity hints. That is enough to render every item without new data capture work. The fallback path therefore does not need new schema or new provider calls and can remain backward-compatible with existing snapshots. **Alternatives considered**: - Require bespoke renderers before a policy type can appear: rejected because the spec explicitly requires unknown and unsupported types to render immediately. - Depend on raw JSON payload shape for unsupported types: rejected because the goal is to stop using raw payloads as the primary operator experience. ## R3: UI composition pattern for the detail page **Decision**: Keep the view as a sectioned Filament infolist and render the summary table, grouped item browser, and technical disclosure through custom `ViewEntry` Blade components. **Rationale**: Existing repo patterns use sectioned infolists for view pages and custom Blade entries for complex grouped rendering. This fits UX-001, keeps the page view-only, and allows the grouped browser to use collapsible sections plus per-group warning or degraded-state blocks without switching to a bespoke Livewire screen. **Alternatives considered**: - Replace the view page with a custom Livewire page: rejected because the feature does not need a new interaction-heavy workflow and the repo already supports complex read-only rendering through infolist entries. - Render all content as raw Blade inside the page class: rejected because it would bypass existing Filament view composition patterns and make the detail surface harder to test structurally. ## R4: Fidelity and gap semantics **Decision**: Represent fidelity and gap states explicitly in the presentation model and route them through centralized badge semantics rather than inline `->color()` closures or one-off labels. **Rationale**: The constitution requires status-like badges to stay centralized. The current resource already has inline state coloring for snapshot completion, but Feature 130 introduces richer fidelity and gap semantics at summary and item level. Centralizing those states through badge mappers or an equivalent shared domain keeps labels and colors consistent across summary rows, group headers, and item rows. **Alternatives considered**: - Leave fidelity and gaps as plain text strings only: rejected because the spec explicitly requires them to be visible and enterprise-readable, not hidden in prose. - Add per-view ad hoc mappings: rejected because BADGE-001 forbids it and the states would drift across sections over time. ## R5: Initial type enrichments for RBAC and compliance **Decision**: Preserve RBAC as the richest type by extracting its current mapping into a dedicated renderer, and add an initial `deviceCompliancePolicy` renderer that emits first-class structured rows plus safe platform and compliance hints when metadata supports it. **Rationale**: The spec requires RBAC to stop being exclusive, not to lose richness. Extracting the current RBAC mapping into a renderer preserves that value while making it conform to the common item contract. Compliance is explicitly called out in the spec as a first-class type that must stop appearing only as counts or raw JSON, so it should be the first non-RBAC enriched renderer. **Alternatives considered**: - Ship only the fallback renderer for all types: rejected because the spec explicitly calls for RBAC richness retention and initial compliance visibility improvements. - Build rich bespoke renderers for every policy type in this spec: rejected because it expands scope too far and the fallback contract already covers near-term extensibility. ## R6: Testing strategy **Decision**: Cover the redesign with focused Pest feature tests for rendered page behavior and unit tests for presenter and renderer logic. **Rationale**: The main regression risks are grouping, fallback visibility, fidelity and gap display, authorization preservation, and safe failure isolation. Those are best protected by unit tests around the presentation layer plus feature tests against the Filament resource response. Existing snapshot visibility tests can be evolved instead of replaced wholesale. **Alternatives considered**: - Rely only on feature tests: rejected because presenter and renderer contracts need cheap, deterministic tests separate from full-page HTML assertions. - Rely only on unit tests: rejected because the feature is primarily a user-facing rendering change and needs end-to-end regression protection against the resource view surface.