TenantAtlas/specs/132-guid-context-resolver/research.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

57 lines
6.0 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.

# Phase 0 Research: GUID Context Resolver & Human-Readable Reference Presentation
## Decision 1: Extend the existing shared navigation layer instead of replacing it
- Decision: Build the new reference semantics on top of the current shared related-context/navigation foundation rather than starting from a second unrelated abstraction.
- Rationale: The codebase already has `RelatedNavigationResolver`, `CrossResourceNavigationMatrix`, `RelatedContextEntry`, shared related-context Blade rendering, and canonical route helpers. Reusing those extension points reduces migration risk and keeps Spec 131 and Spec 132 aligned.
- Alternatives considered:
- Replace the navigation layer entirely with a new reference-only stack: rejected because it would duplicate route, availability, and action-label logic that already exists and is already wired into multiple resources.
- Keep page-level arrays and only restyle the Blade partial: rejected because it would not satisfy the specs requirement for explicit reference classes, shared semantics, and distinct degraded states.
## Decision 2: Model references through explicit input and output contracts
- Decision: Introduce a structured `ReferenceDescriptor` input contract and a normalized `ResolvedReference` output contract with explicit state, type, label, technical detail, and optional canonical target.
- Rationale: The current `RelatedContextEntry` payload is useful for immediate rendering but too shallow for the broader semantics required here. A descriptor plus resolved-reference pair makes support for partial resolution, unsupported classes, and future providers predictable and testable.
- Alternatives considered:
- Continue passing free-form arrays between resources and partials: rejected because it invites page-specific drift and makes regression testing weak.
- Resolve everything directly inside Blade partials: rejected because presentation should not own resolution logic or authorization decisions.
## Decision 3: Keep render-time resolution DB-only and best-effort
- Decision: Resolve references at render time using existing relations, local model lookups, current workspace or tenant context, stored fallback labels, and existing helper services only; do not make live Microsoft Graph or provider calls.
- Rationale: The constitution and current architecture keep monitoring and governance views DB-only at render time. Best-effort local resolution is sufficient for the target surfaces and avoids latency, availability, and authorization leakage problems.
- Alternatives considered:
- Make on-demand provider calls to improve labels: rejected because it violates the DB-only rendering expectation, adds latency, and complicates authorization.
- Cache external labels aggressively in new tables: rejected because the spec explicitly avoids introducing new persistent models solely for resolution.
## Decision 4: Use two shared presentation variants with one semantic payload
- Decision: Provide a compact variant for dense tables and a detailed variant for related-context or infolist sections, both powered by the same resolved-reference payload.
- Rationale: Some target surfaces are list-dense and cannot absorb a full detail block without becoming noisy, while detail pages need more explanatory context and degraded-state messaging. One semantic contract with two renderers keeps the hierarchy stable while fitting each surface.
- Alternatives considered:
- Force one heavy component everywhere: rejected because it would make list screens noisy and reduce scanability.
- Allow each page to design its own variant independently: rejected because it would recreate the inconsistency the spec is meant to solve.
## Decision 5: Authorization controls linkability first, label disclosure second
- Decision: Canonical targets become actionable only when current policy allows access; label and state disclosure must degrade to inaccessible or unresolved only to the extent policy allows.
- Rationale: The products 404-vs-403 semantics and deny-as-not-found rules are already explicit. The reference layer must not accidentally leak object existence or friendly labels just because it has enough data to resolve them internally.
- Alternatives considered:
- Hide every unauthorized reference completely: rejected because some surfaces legitimately need to preserve the existence of a reference without allowing navigation.
- Always show the resolved label even when navigation is forbidden: rejected because that can leak protected detail.
## Decision 6: Upgrade narrow label helpers into structured resolver collaborators
- Decision: Existing helpers such as `EntraGroupLabelResolver` should become collaborators that feed structured resolution outputs rather than emitting final UI labels.
- Rationale: Current helpers return a single string like `Name (…token)`, which is not enough to separate primary label, type/context, state, and technical detail. They remain useful, but inside a richer resolver contract.
- Alternatives considered:
- Leave helpers untouched and parse their formatted strings back into UI parts: rejected because it is brittle and loses state intent.
- Rewrite all provider-backed label logic from scratch: rejected because the current local lookup behavior is already useful and should be preserved.
## Decision 7: Leverage the repos existing registry-and-DTO pattern
- Decision: Mirror the `BaselineSnapshotPresenter` and `SnapshotTypeRendererRegistry` pattern by using immutable value objects, registry dispatch, and fallback behavior for references.
- Rationale: The repo already favors registry-driven support layers for normalization and rendering. Following that pattern keeps the reference system familiar, testable, and consistent with current architecture.
- Alternatives considered:
- Put the entire resolution switch in one large service class: rejected because explicit per-class resolvers are easier to extend and test.
- Encode resolution rules in configuration only: rejected because authorization-aware destination logic and best-effort lookup behavior require application code.