6.0 KiB
6.0 KiB
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
ReferenceDescriptorinput contract and a normalizedResolvedReferenceoutput contract with explicit state, type, label, technical detail, and optional canonical target. - Rationale: The current
RelatedContextEntrypayload 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
EntraGroupLabelResolvershould 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
BaselineSnapshotPresenterandSnapshotTypeRendererRegistrypattern 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.