TenantAtlas/apps/platform/tests/Unit/ResolutionGuidance/Spec350ResolutionCaseContractTest.php
ahmido 4cf2712f92 feat: operator resolution guidance framework v1 (spec 350) (#421)
Implemented the first version of the operator resolution guidance framework. Added new foundation classes (ResolutionCase, ResolutionAction) and a ReviewPackOutputResolutionAdapter. Updated the Customer Review Workspace and Environment Review Resource to use the new adapter. Added extensive test coverage for the framework and UI integrations.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #421
2026-06-03 15:35:25 +00:00

95 lines
3.9 KiB
PHP

<?php
declare(strict_types=1);
use App\Support\ResolutionGuidance\ResolutionAction;
use App\Support\ResolutionGuidance\ResolutionCase;
it('normalizes navigation and download actions into the shared contract shape', function (): void {
$navigation = ResolutionAction::fromArray([
'key' => 'review_output.open_review',
'label' => 'Open review',
'url' => '/admin/reviews/1',
'kind' => 'environment_link',
'icon' => 'heroicon-o-arrow-top-right-on-square',
], 'review_output.open_review');
$download = ResolutionAction::fromArray([
'key' => 'review_output.download_review_pack_with_limitations',
'label' => 'Download review pack with limitations',
'url' => '/admin/review-packs/1/download',
'kind' => 'download',
'icon' => 'heroicon-o-arrow-down-tray',
], 'review_output.download_review_pack_with_limitations');
expect($navigation['type'])->toBe(ResolutionAction::TYPE_NAVIGATION)
->and($navigation['kind'])->toBe('environment_link')
->and($download['type'])->toBe(ResolutionAction::TYPE_DOWNLOAD)
->and($download['kind'])->toBe('download');
});
it('degrades unsafe executable actions to a safe non-executable fallback', function (): void {
$action = ResolutionAction::fromArray([
'key' => 'review_output.retry_generation',
'label' => 'Retry generation',
'type' => ResolutionAction::TYPE_OPERATION_ACTION,
'url' => '/admin/operations/1',
'icon' => 'heroicon-o-arrow-path',
], 'review_output.retry_generation');
expect($action['type'])->toBe(ResolutionAction::TYPE_NAVIGATION)
->and($action['url'])->toBe('/admin/operations/1')
->and($action['capability'])->toBeNull()
->and($action['audit_event'])->toBeNull()
->and($action['requires_confirmation'])->toBeFalse()
->and($action['operation_run_type'])->toBeNull();
});
it('builds a resolution case with explicit scope and proof references', function (): void {
$case = ResolutionCase::make(
key: 'review_output.publication_blocked',
scope: [
'type' => 'review_pack',
'workspace_id' => 1,
'managed_environment_id' => 41,
'environment_review_id' => 6,
'source_surface' => 'customer_review_workspace',
],
severity: 'critical',
status: 'blocked',
title: 'Output not customer-ready',
reason: 'The published review is based on incomplete evidence.',
impact: 'Do not share the current review pack externally.',
primaryAction: ResolutionAction::fromArray([
'key' => 'review_output.resolve_review_blockers',
'label' => 'Inspect review blockers',
'url' => '/admin/reviews/6',
'kind' => 'environment_link',
], 'review_output.resolve_review_blockers'),
secondaryActions: [
ResolutionAction::fromArray([
'key' => 'review_output.open_evidence_basis',
'label' => 'Open evidence basis',
'url' => '/admin/evidence/8',
'kind' => 'environment_link',
], 'review_output.open_evidence_basis'),
],
sourceRefs: [
['type' => 'environment_review', 'id' => 6],
['type' => 'review_pack', 'id' => 8],
],
evidenceRefs: [
['type' => 'evidence_snapshot', 'id' => 8],
],
technicalDetails: [
'Review status' => 'Published',
],
);
expect($case['scope']['source_surface'])->toBe('customer_review_workspace')
->and($case['primary_action']['key'])->toBe('review_output.resolve_review_blockers')
->and($case['secondary_actions'])->toHaveCount(1)
->and($case['source_refs'])->toHaveCount(2)
->and($case['evidence_refs'])->toHaveCount(1)
->and($case['technical_details']['Review status'])->toBe('Published');
});