## 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
20 KiB
Implementation Plan: GUID Context Resolver & Human-Readable Reference Presentation
Branch: 132-guid-context-resolver | Date: 2026-03-10 | Spec: 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
/adminand 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
OperationRunrecords 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.statusorOperationRun.outcometransitions 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.phpandapp/Support/Badges/BadgeRenderer.phpinstead 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 inbootstrap/providers.php. - Global search resource rule: PASS —
FindingResource,PolicyVersionResource,BackupSetResource, andEntraGroupResourcealready 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:assetsbehavior remains unchanged.
Project Structure
Documentation (this feature)
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)
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 sharedrelated-contextBlade 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.EntraGroupLabelResolverproves 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.OperationRunLinksand existing resourcegetUrl()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
ViewEntryrenderers 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.mdspecs/132-guid-context-resolver/contracts/reference-presentation.openapi.yamlspecs/132-guid-context-resolver/quickstart.md
Design highlights:
- Introduce
ReferenceDescriptor,ResolvedReference,ReferenceLinkTarget,ReferenceTechnicalDetail,ReferencePresentationVariant, and aReferenceResolverRegistryas 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
RelatedNavigationResolverso it produces richer reference payloads instead of today’s shallowvalue + secondaryValue + availabilitymodel. - Preserve canonical destinations through existing helpers like
OperationRunLinksand resourcegetUrl()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
EntraGroupLabelResolverinto 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
OperationRunLinksand 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:assetsbehavior 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.