TenantAtlas/specs/132-guid-context-resolver/plan.md
ahmido 8ee1174c8d feat: add resolved reference presentation layer (#161)
## Summary
- add the shared resolved-reference foundation with registry, resolvers, presenters, and badge semantics
- refactor related context, assignment evidence, and policy-version assignment rendering toward label-first reference presentation
- add Spec 132 artifacts and focused Pest coverage for reference resolution, degraded states, canonical linking, and tenant-context carryover

## Verification
- `vendor/bin/sail bin pint --dirty --format agent`
- focused Pest verification was marked complete in the task artifact

## Notes
- this PR is opened from the current session branch
- `specs/132-guid-context-resolver/tasks.md` reflects in-progress completion state for the implemented tasks

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #161
2026-03-10 18:52:52 +00:00

261 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Implementation Plan: GUID Context Resolver & Human-Readable Reference Presentation
**Branch**: `132-guid-context-resolver` | **Date**: 2026-03-10 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/132-guid-context-resolver/spec.md`
## Summary
Replace GUID-first reference display on core enterprise surfaces by extending the existing shared related-context/navigation work into a broader reference-resolution foundation. The implementation will introduce explicit reference descriptor and resolved-reference contracts, a resolver registry for internal and provider-backed references, and shared compact/detail rendering patterns so findings, baseline snapshots, operation runs, assignments, and related-context sections show names first, type and state second, and technical IDs only as secondary evidence.
## Technical Context
**Language/Version**: PHP 8.4.15 / Laravel 12
**Primary Dependencies**: Filament v5, Livewire v4.0+, Tailwind CSS v4
**Storage**: PostgreSQL via Laravel Sail plus existing workspace and tenant context, existing Eloquent relations, and provider-derived identifiers already stored in domain records
**Testing**: Pest v4 feature and unit tests on PHPUnit 12
**Target Platform**: Laravel Sail web application with workspace-admin routes under `/admin`, tenant-context routes under `/admin/t/{tenant}/...`, and shared Filament infolist/table rendering patterns
**Project Type**: Laravel monolith / Filament web application
**Performance Goals**: Reference rendering remains DB-only at page render time, uses bounded eager loading and batched local lookups, introduces no render-time Graph/provider calls, and avoids new N+1 patterns on dense list surfaces
**Constraints**: No schema changes, no new Graph calls, no unauthorized existence leakage, no page-specific fallback logic for supported classes, no broken pages when a resolver is missing, preserve 404 vs 403 semantics, and keep technical IDs visibly secondary
**Scale/Scope**: One shared resolver registry and value-object model, 8 to 10 initial reference classes, compact plus detailed presentation variants, 5 primary target surface families, and focused regression coverage for state rendering, linking, and authorization-aware degradation
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
- Inventory-first: PASS — the feature changes reference presentation only; inventory, snapshot, and backup persistence semantics remain unchanged.
- Read/write separation: PASS — no write flow or new mutation is introduced; the feature is read-only UI and support-layer work.
- Graph contract path: PASS — no new Microsoft Graph calls are introduced, and reference resolution must stay DB-only or source-context-only at render time.
- Deterministic capabilities: PASS — linkability and degraded-state behavior can be derived from existing gates, policies, capability registries, and current route helpers.
- RBAC-UX planes and isolation: PASS — the feature spans workspace-admin `/admin` and tenant-context `/admin/t/{tenant}/...` surfaces but must preserve 404 for non-members and 403 for in-scope capability denial.
- Workspace isolation: PASS — workspace membership remains the visibility boundary for workspace-level reference labels and canonical destinations.
- RBAC-UX destructive confirmation: PASS / N/A — the feature introduces no destructive actions.
- RBAC-UX global search: PASS — touched resources either already have view pages or explicitly disable global search; the feature must not create new search dead ends.
- Tenant isolation: PASS — tenant-owned references must enforce current tenant entitlement before exposing protected labels or links.
- Run observability: PASS / N/A — existing `OperationRun` records may be displayed as resolved references, but no new run creation or lifecycle mutation occurs.
- Ops-UX 3-surface feedback: PASS / N/A — no new operation-start or completion flow is introduced.
- Ops-UX lifecycle and summary counts: PASS / N/A — no `OperationRun.status` or `OperationRun.outcome` transitions are introduced.
- Ops-UX guards and system runs: PASS / N/A — existing operations behavior remains unchanged.
- Automation: PASS / N/A — no queued or scheduled workflow changes are required.
- Data minimization: PASS — reference presentation uses already-authorized labels, IDs, and source hints only; no secrets or raw payload dumps are introduced.
- Badge semantics (BADGE-001): PASS — if reference-state badges are added or refined, they must map through `app/Support/Badges/BadgeCatalog.php` and `app/Support/Badges/BadgeRenderer.php` instead of page-specific label/color logic.
- UI naming (UI-NAMING-001): PASS — operator-facing reference copy remains domain-first, such as “Policy,” “Baseline snapshot,” “Operation run,” “Group,” or “Role definition,” and technical ID terminology stays secondary.
- UI naming (UI-NAMING-001): PASS — operator-facing reference copy remains domain-first, such as “Policy,” “Baseline snapshot,” “Operation run,” “Group,” or “Role definition,” and technical ID terminology stays secondary across labels, helper text, link labels, empty states, and degraded-state copy.
- Filament UI Action Surface Contract: PASS — touched resources already expose list/view surfaces; the feature upgrades inspect affordances and related-context rows without introducing destructive or noisy action sprawl, and touched resources or relation managers must keep their `actionSurfaceDeclaration()` coverage current where applicable.
- Filament UI UX-001: PASS — modified detail pages will continue to use sectioned infolists or read-only layouts, while list surfaces keep search/sort/filter behavior and adopt compact shared reference rendering.
- Filament v5 / Livewire v4 compliance: PASS — the plan remains inside the existing Filament v5 / Livewire v4 application surfaces.
- Provider registration (`bootstrap/providers.php`): PASS — no new panel provider is introduced; existing providers remain registered in `bootstrap/providers.php`.
- Global search resource rule: PASS — `FindingResource`, `PolicyVersionResource`, `BackupSetResource`, and `EntraGroupResource` already have view pages; workspace-level resources touched by the feature that are not globally searchable remain disabled.
- Asset strategy: PASS — no heavy frontend asset bundle is required; shared Blade partials and existing Filament assets are sufficient, and deploy-time `php artisan filament:assets` behavior remains unchanged.
## Project Structure
### Documentation (this feature)
```text
specs/132-guid-context-resolver/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│ └── reference-presentation.openapi.yaml
├── checklists/
│ └── requirements.md
└── tasks.md
```
### Source Code (repository root)
```text
app/
├── Filament/
│ ├── Resources/
│ │ ├── FindingResource.php # existing related-context + list action consumer
│ │ ├── PolicyVersionResource.php # existing related-context + policy lineage consumer
│ │ ├── BackupSetResource.php # existing related-context + run linkage consumer
│ │ ├── OperationRunResource.php # canonical run detail consumer
│ │ ├── EntraGroupResource.php # current GUID-heavy directory reference surface
│ │ ├── BaselineProfileResource/
│ │ │ └── RelationManagers/
│ │ │ └── BaselineTenantAssignmentsRelationManager.php # concrete assignment-like target surface
│ │ └── BaselineSnapshotResource/
│ │ └── Pages/ViewBaselineSnapshot.php # snapshot detail related-context consumer
│ └── Widgets/
│ └── Dashboard/ # reference-heavy summary surfaces to keep aligned later
├── Models/
│ ├── Policy.php
│ ├── PolicyVersion.php
│ ├── BaselineProfile.php
│ ├── BaselineSnapshot.php
│ ├── BackupSet.php
│ ├── OperationRun.php
│ ├── Finding.php
│ ├── EntraGroup.php
│ ├── EntraRoleDefinition.php
│ └── Tenant.php
├── Services/
│ ├── Baselines/
│ │ └── SnapshotRendering/ # existing registry + DTO pattern to mirror
│ └── Directory/
│ └── EntraGroupLabelResolver.php # existing narrow provider-backed label resolver
├── Support/
│ ├── Navigation/
│ │ ├── CrossResourceNavigationMatrix.php # existing source/surface matrix
│ │ ├── RelatedNavigationResolver.php # existing entry-point to evolve or wrap
│ │ ├── RelatedContextEntry.php # current shallow view payload model
│ │ └── CanonicalNavigationContext.php # canonical link context helper
│ ├── OperationRunLinks.php # canonical run route helper
│ └── References/ # NEW shared reference descriptor/registry/value objects
resources/
└── views/
└── filament/
└── infolists/
└── entries/
├── related-context.blade.php # current reusable related-context renderer
└── resolved-reference*.blade.php # NEW compact/detail variants
tests/
├── Feature/
│ ├── Filament/ # resource view/list rendering tests
│ ├── Monitoring/ # canonical operations link tests
│ └── Rbac/ # authorization-aware visibility/degradation tests
└── Unit/
├── Support/
│ └── References/ # NEW resolver registry / DTO / state tests
└── Services/
└── Directory/ # existing label resolver tests that may be upgraded
```
**Structure Decision**: Keep the feature inside the existing Laravel/Filament monolith and extend the current shared navigation support rather than creating a parallel page-only solution. Introduce a dedicated reference-resolution layer under `app/Support/References`, then adapt the current `RelatedNavigationResolver`, related-context partials, and target resources to consume the richer reference semantics.
## Complexity Tracking
> No Constitution Check violations. No justifications needed.
| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| — | — | — |
## Phase 0 — Research (DONE)
Output:
- `specs/132-guid-context-resolver/research.md`
Key findings captured:
- The repo already has a first-generation shared navigation layer through `RelatedNavigationResolver`, `CrossResourceNavigationMatrix`, `RelatedContextEntry`, and the shared `related-context` Blade partial, but that layer models only availability plus links, not explicit descriptor classes, multi-state resolution, or controlled technical detail presentation.
- `BaselineSnapshotPresenter`, `SnapshotTypeRendererRegistry`, and the rendered snapshot DTOs show a strong existing pattern for registry-driven resolution with immutable value objects and fallback behavior, which maps well to a shared reference resolver registry.
- `EntraGroupLabelResolver` proves provider-backed label enrichment is already needed, but today it collapses unresolved and resolved references into a single label string instead of returning structured reference states.
- `OperationRunLinks` and existing resource `getUrl()` helpers already encode canonical destinations, so Spec 132 should centralize richer label/state handling around those helpers instead of inventing new route families.
- Filament v5 supports custom `ViewEntry` renderers and rich table layouts, so compact and detailed reference variants can remain shared without publishing internal Filament views or introducing a heavy frontend rewrite.
- The highest-value target surfaces already expose related-context sections or reference-heavy infolist/table entries, making incremental adoption practical without a schema migration.
## Phase 1 — Design & Contracts (DONE)
Outputs:
- `specs/132-guid-context-resolver/data-model.md`
- `specs/132-guid-context-resolver/contracts/reference-presentation.openapi.yaml`
- `specs/132-guid-context-resolver/quickstart.md`
Design highlights:
- Introduce `ReferenceDescriptor`, `ResolvedReference`, `ReferenceLinkTarget`, `ReferenceTechnicalDetail`, `ReferencePresentationVariant`, and a `ReferenceResolverRegistry` as the canonical shared contracts for reference semantics.
- Keep reference resolution DB-only and best-effort at render time by combining existing relations, local model lookups, stored source metadata, and narrow provider-backed label resolvers such as `EntraGroupLabelResolver`; no external provider call is allowed during page render.
- Extend or wrap the current `RelatedNavigationResolver` so it produces richer reference payloads instead of todays shallow `value + secondaryValue + availability` model.
- Preserve canonical destinations through existing helpers like `OperationRunLinks` and resource `getUrl()` methods while making linkability capability-aware and non-ambiguous.
- Add shared compact and detailed reference renderers so list rows and detail sections preserve the same semantic order even when the visual density differs, and map reference-state badges through the shared badge system.
- Add shared compact and detailed reference renderers so list rows and detail sections preserve the same semantic order even when the visual density differs, map reference-state badges through the shared badge system, and preserve domain-consistent operator copy.
- Roll out incrementally by first covering internal model-backed references, then security/provider-backed references, and finally upgrading existing related-context sections and table cells on the target surfaces.
## Phase 1 — Agent Context Update (DONE)
Run:
- `.specify/scripts/bash/update-agent-context.sh copilot`
## Phase 2 — Implementation Outline (tasks created in `/speckit.tasks`)
### Step 1 — Define the shared reference contracts and registry
Goal: implement FR-132-02, FR-132-03, FR-132-05, FR-132-16, and FR-132-23.
Changes:
- Add the shared descriptor, state, technical-detail, and resolved-reference value objects.
- Add a registry or dispatcher that maps explicit reference classes to concrete resolvers.
- Define a fallback resolver for unsupported or unresolved classes that still keeps the reference visible.
Tests:
- Add unit coverage for registry dispatch, unsupported-class fallback, value-object normalization, and reference-state serialization.
### Step 2 — Implement the initial model-backed resolvers
Goal: implement FR-132-01, FR-132-04, FR-132-09, FR-132-10, FR-132-13, and FR-132-21.
Changes:
- Add resolvers for policies, policy versions, baseline profiles, baseline snapshots, operation runs, and backup sets.
- Resolve primary labels, type/context labels, canonical targets, and secondary technical details from local records and already-known relationships.
- Batch or eager-load where needed so detail and list surfaces avoid N+1 lookups.
Tests:
- Add unit coverage for each core resolver, including resolved, partially resolved, missing, and unsupported cases.
### Step 3 — Implement governance, security, and provider-backed resolvers
Goal: implement FR-132-04, FR-132-08, FR-132-10, FR-132-14, and FR-132-28.
Changes:
- Add resolvers for role definitions, Entra groups, principal-like references, assignment targets, and tenant-linked external object references that are already surfaced today.
- Upgrade narrow helpers like `EntraGroupLabelResolver` into structured resolver collaborators instead of raw label string formatters.
- Differentiate inaccessible, unresolved, deleted or missing, and external-only limited-context states explicitly.
Tests:
- Add unit coverage for provider-backed label reuse, inaccessible-state degradation, fallback labels, and deleted-object behavior.
### Step 4 — Create shared presentation variants and state vocabulary
Goal: implement FR-132-06, FR-132-07, FR-132-08, FR-132-12, FR-132-18, FR-132-19, and FR-132-20.
Changes:
- Add compact and detailed shared reference renderers for infolists, related-context sections, and dense tables.
- Keep the visual order consistent: label first, type/context second, state next, technical ID last.
- Centralize state badges and unavailable-state copy instead of letting each resource improvise labels.
Tests:
- Add feature coverage proving technical IDs stay secondary, unresolved states remain visible, and clickable vs non-clickable rendering is unambiguous.
### Step 5 — Refactor target surfaces to consume the shared reference layer
Goal: implement FR-132-15, FR-132-24, FR-132-25, FR-132-26, and FR-132-27.
Changes:
- Refactor findings, baseline snapshots, operation runs, policy versions, backup sets, the baseline tenant assignments relation manager, and assignment-evidence sections on finding, policy-version, and baseline-snapshot surfaces to use the shared resolver/presentation layer.
- Replace GUID-heavy infolist/table fields and ad hoc related-context arrays with structured resolved references.
- Ensure existing canonical links continue to flow through `OperationRunLinks` and resource route helpers while touched Filament resources preserve explicit inspect affordances, row-action caps, and documented exemptions.
- Ensure tenant-context entry into canonical workspace destinations preserves visible originating-tenant meaning via filters, context badges, or source-context metadata where relevant.
Tests:
- Add or update Filament feature coverage for findings, baseline snapshots, operation runs, and assignment-like surfaces to prove label-first rendering and canonical links.
### Step 6 — Enforce authorization-aware degradation and regression safety
Goal: implement FR-132-11, FR-132-14, FR-132-17, FR-132-22, and the acceptance criteria around safe degradation.
Changes:
- Ensure the shared layer differentiates non-member 404 semantics from in-scope capability denial and never leaks protected labels where policy forbids it.
- Keep unsupported or partially known references visible without breaking pages.
- Audit touched resources for remaining GUID-first output and remove page-specific formatting branches for supported classes.
- Lock the rollout boundary so the surfaces named in the spec fully adopt the shared pattern now, while dashboard summary widgets and other out-of-scope views are explicitly allowed to remain on older formatting until a later spec.
- Add regression coverage for domain-consistent operator copy and tenant-context carryover on migrated canonical destinations.
Tests:
- Add positive and negative authorization coverage proving inaccessible references are non-clickable, protected destinations stay guarded, and unsupported resolvers do not hide the underlying reference.
- Add regression coverage preventing raw GUIDs from reappearing as the primary visible value on supported target surfaces.
## Constitution Check (Post-Design)
Re-check result: PASS.
- Livewire v4.0+ compliance: preserved because the design stays inside the existing Filament v5 / Livewire v4 surfaces.
- Provider registration location: unchanged; existing panel providers remain registered in `bootstrap/providers.php`.
- Globally searchable resources: touched searchable resources already expose view pages, and non-searchable resources remain explicitly disabled, so the Filament global-search rule remains satisfied.
- Destructive actions: no new destructive actions are introduced; existing destructive behavior remains subject to current confirmation and authorization rules.
- Asset strategy: no new heavy assets are introduced; shared Blade partials and existing Filament view infrastructure are sufficient, and deploy-time `php artisan filament:assets` behavior remains unchanged.
- Testing plan: add focused Pest unit coverage for registry dispatch, resolver behavior, shared badge mapping, state normalization, and authorization-aware link generation, plus focused Filament feature coverage for findings, baseline snapshots, operation runs, the baseline tenant assignments relation manager, assignment-evidence surfaces, tenant-context carryover on canonical destinations, domain-consistent copy, and degraded-reference rendering.