## 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
57 lines
6.0 KiB
Markdown
57 lines
6.0 KiB
Markdown
# 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 spec’s 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 product’s 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 repo’s 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. |