feat: clean up managed environment terminology copy
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 6m50s
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 6m50s
This commit is contained in:
parent
3ec582a182
commit
5cad4eb8fd
@ -200,7 +200,7 @@ class BaselineCompareMatrix extends Page implements HasForms
|
||||
public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
|
||||
{
|
||||
return ActionSurfaceDeclaration::forPage(ActionSurfaceProfile::ListOnlyReadOnly)
|
||||
->satisfy(ActionSurfaceSlot::ListHeader, 'Header actions keep bounded navigation plus confirmation-gated compare fan-out for visible assigned tenants.')
|
||||
->satisfy(ActionSurfaceSlot::ListHeader, 'Header actions keep bounded navigation plus confirmation-gated compare fan-out for visible assigned environments.')
|
||||
->exempt(ActionSurfaceSlot::InspectAffordance, 'The matrix intentionally forbids row click; only explicit tenant, subject, cell, and run drilldowns are rendered.')
|
||||
->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'The matrix does not use a row-level secondary-actions menu.')
|
||||
->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'The matrix has no bulk actions.')
|
||||
@ -341,11 +341,11 @@ protected function getHeaderActions(): array
|
||||
$profile = $this->getRecord();
|
||||
|
||||
$compareAssignedTenantsAction = Action::make('compareAssignedTenants')
|
||||
->label('Compare assigned tenants')
|
||||
->label('Compare assigned environments')
|
||||
->icon('heroicon-o-play')
|
||||
->requiresConfirmation()
|
||||
->modalHeading('Compare assigned tenants')
|
||||
->modalDescription('Simulation only. This starts the normal tenant-owned baseline compare path for the visible assigned set. No workspace umbrella run is created.')
|
||||
->modalHeading('Compare assigned environments')
|
||||
->modalDescription('Simulation only. This starts the normal environment-owned baseline compare path for the visible assigned set. No workspace umbrella run is created.')
|
||||
->disabled(fn (): bool => $this->compareAssignedTenantsDisabledReason() !== null)
|
||||
->tooltip(fn (): ?string => $this->compareAssignedTenantsDisabledReason())
|
||||
->action(fn (): mixed => $this->compareAssignedTenants());
|
||||
@ -734,11 +734,11 @@ private function compareAssignedTenantsDisabledReason(): ?string
|
||||
$reference = is_array($this->matrix['reference'] ?? null) ? $this->matrix['reference'] : [];
|
||||
|
||||
if (($reference['referenceState'] ?? null) !== 'ready') {
|
||||
return 'Capture a complete baseline snapshot before comparing assigned tenants.';
|
||||
return 'Capture a complete baseline snapshot before comparing assigned environments.';
|
||||
}
|
||||
|
||||
if ((int) ($reference['visibleTenantCount'] ?? 0) === 0) {
|
||||
return 'No visible assigned tenants are available for compare.';
|
||||
return 'No visible assigned environments are available for compare.';
|
||||
}
|
||||
|
||||
return $this->compareStartReasonMessage($this->compareAssignedTenantsReasonCode());
|
||||
@ -768,10 +768,10 @@ private function compareAssignedTenantsReasonCode(): ?string
|
||||
private function compareStartReasonMessage(?string $reasonCode): ?string
|
||||
{
|
||||
return match ($reasonCode) {
|
||||
BaselineReasonCodes::COMPARE_INVALID_SCOPE => 'The assigned baseline scope is invalid and must be reviewed before comparing assigned tenants.',
|
||||
BaselineReasonCodes::COMPARE_INVALID_SCOPE => 'The assigned baseline scope is invalid and must be reviewed before comparing assigned environments.',
|
||||
BaselineReasonCodes::COMPARE_UNSUPPORTED_SCOPE => 'The selected governed subjects are not supported by any compare strategy yet.',
|
||||
BaselineReasonCodes::COMPARE_MIXED_SCOPE => 'The selected governed subjects span multiple compare strategy families and must be narrowed before comparing assigned tenants.',
|
||||
'tenant_sync_required' => 'You need tenant sync access for each visible tenant before compare can start.',
|
||||
BaselineReasonCodes::COMPARE_MIXED_SCOPE => 'The selected governed subjects span multiple compare strategy families and must be narrowed before comparing assigned environments.',
|
||||
'tenant_sync_required' => 'You need environment sync access for each visible environment before compare can start.',
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
@ -65,12 +65,12 @@ class FindingsHygieneReport extends Page implements HasTable
|
||||
public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
|
||||
{
|
||||
return ActionSurfaceDeclaration::forPage(ActionSurfaceProfile::ListOnlyReadOnly, ActionSurfaceType::ReadOnlyRegistryReport)
|
||||
->satisfy(ActionSurfaceSlot::ListHeader, 'Header controls keep the hygiene scope fixed and expose only fixed reason views plus tenant-prefilter recovery when needed.')
|
||||
->satisfy(ActionSurfaceSlot::ListHeader, 'Header controls keep the hygiene scope fixed and expose only fixed reason views plus environment-prefilter recovery when needed.')
|
||||
->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ClickableRow->value)
|
||||
->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'The hygiene report stays read-only and exposes row click as the only inspect path.')
|
||||
->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'The hygiene report does not expose bulk actions.')
|
||||
->satisfy(ActionSurfaceSlot::ListEmptyState, 'The empty state stays calm and only offers a tenant-prefilter reset when the active tenant filter hides otherwise visible issues.')
|
||||
->exempt(ActionSurfaceSlot::DetailHeader, 'Repair remains on the existing tenant finding detail surface.');
|
||||
->satisfy(ActionSurfaceSlot::ListEmptyState, 'The empty state stays calm and only offers an environment-prefilter reset when the active environment filter hides otherwise visible issues.')
|
||||
->exempt(ActionSurfaceSlot::DetailHeader, 'Repair remains on the existing environment finding detail surface.');
|
||||
}
|
||||
|
||||
public function mount(): void
|
||||
@ -93,7 +93,7 @@ protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Action::make('clear_tenant_filter')
|
||||
->label('Clear tenant filter')
|
||||
->label('Clear environment filter')
|
||||
->icon('heroicon-o-x-mark')
|
||||
->color('gray')
|
||||
->visible(fn (): bool => $this->currentTenantFilterId() !== null)
|
||||
@ -259,11 +259,11 @@ public function emptyState(): array
|
||||
{
|
||||
if ($this->tenantFilterAloneExcludesRows()) {
|
||||
return [
|
||||
'title' => 'No hygiene issues match this tenant scope',
|
||||
'body' => 'Your current tenant filter is hiding hygiene issues that are still visible elsewhere in this workspace.',
|
||||
'title' => 'No hygiene issues match this environment scope',
|
||||
'body' => 'Your current environment filter is hiding hygiene issues that are still visible elsewhere in this workspace.',
|
||||
'icon' => 'heroicon-o-funnel',
|
||||
'action_name' => 'clear_tenant_filter_empty',
|
||||
'action_label' => 'Clear tenant filter',
|
||||
'action_label' => 'Clear environment filter',
|
||||
'action_kind' => 'clear_tenant_filter',
|
||||
];
|
||||
}
|
||||
@ -278,7 +278,7 @@ public function emptyState(): array
|
||||
|
||||
return [
|
||||
'title' => 'No visible hygiene issues right now',
|
||||
'body' => 'Visible broken assignments and stale in-progress work are currently calm across the entitled tenant scope.',
|
||||
'body' => 'Visible broken assignments and stale in-progress work are currently calm across the entitled environment scope.',
|
||||
'icon' => 'heroicon-o-wrench-screwdriver',
|
||||
];
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ protected function getHeaderActions(): array
|
||||
}
|
||||
|
||||
$actions[] = Action::make('clear_tenant_filter')
|
||||
->label('Clear tenant filter')
|
||||
->label('Clear environment filter')
|
||||
->icon('heroicon-o-x-mark')
|
||||
->color('gray')
|
||||
->visible(fn (): bool => $this->currentTenantFilterId() !== null)
|
||||
@ -251,18 +251,18 @@ public function emptyState(): array
|
||||
{
|
||||
if ($this->tenantFilterAloneExcludesRows()) {
|
||||
return [
|
||||
'title' => 'No intake findings match this tenant scope',
|
||||
'body' => 'Your current tenant filter is hiding shared intake work that is still visible elsewhere in this workspace.',
|
||||
'title' => 'No intake findings match this environment scope',
|
||||
'body' => 'Your current environment filter is hiding shared intake work that is still visible elsewhere in this workspace.',
|
||||
'icon' => 'heroicon-o-funnel',
|
||||
'action_name' => 'clear_tenant_filter_empty',
|
||||
'action_label' => 'Clear tenant filter',
|
||||
'action_label' => 'Clear environment filter',
|
||||
'action_kind' => 'clear_tenant_filter',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'title' => 'Shared intake is clear',
|
||||
'body' => 'No visible unassigned findings currently need first routing across your entitled tenants. Open your personal queue if you want to continue with claimed work.',
|
||||
'body' => 'No visible unassigned findings currently need first routing across your entitled environments. Open your personal queue if you want to continue with claimed work.',
|
||||
'icon' => 'heroicon-o-inbox-stack',
|
||||
'action_name' => 'open_my_findings_empty',
|
||||
'action_label' => 'Open my findings',
|
||||
|
||||
@ -72,7 +72,7 @@ class MyFindingsInbox extends Page implements HasTable
|
||||
public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
|
||||
{
|
||||
return ActionSurfaceDeclaration::forPage(ActionSurfaceProfile::ListOnlyReadOnly, ActionSurfaceType::ReadOnlyRegistryReport)
|
||||
->satisfy(ActionSurfaceSlot::ListHeader, 'Header actions keep the assigned-to-me scope fixed and expose only a tenant-prefilter clear action when needed.')
|
||||
->satisfy(ActionSurfaceSlot::ListHeader, 'Header actions keep the assigned-to-me scope fixed and expose only an environment-prefilter clear action when needed.')
|
||||
->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ClickableRow->value)
|
||||
->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'The personal findings inbox exposes row click as the only inspect path and does not render a secondary More menu.')
|
||||
->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'The personal findings inbox does not expose bulk actions.')
|
||||
@ -110,7 +110,7 @@ protected function getHeaderActions(): array
|
||||
}
|
||||
|
||||
$actions[] = Action::make('clear_tenant_filter')
|
||||
->label('Clear tenant filter')
|
||||
->label('Clear environment filter')
|
||||
->icon('heroicon-o-x-mark')
|
||||
->color('gray')
|
||||
->visible(fn (): bool => $this->currentTenantFilterId() !== null)
|
||||
@ -127,7 +127,7 @@ public function table(Table $table): Table
|
||||
->persistFiltersInSession()
|
||||
->columns([
|
||||
TextColumn::make('tenant.name')
|
||||
->label('ManagedEnvironment'),
|
||||
->label('Managed environment'),
|
||||
TextColumn::make('subject_display_name')
|
||||
->label('Finding')
|
||||
->state(fn (Finding $record): string => $record->resolvedSubjectDisplayName() ?? 'Finding #'.$record->getKey())
|
||||
@ -154,7 +154,7 @@ public function table(Table $table): Table
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('managed_environment_id')
|
||||
->label('ManagedEnvironment')
|
||||
->label('Managed environment')
|
||||
->options(fn (): array => $this->tenantFilterOptions())
|
||||
->searchable(),
|
||||
Filter::make('overdue')
|
||||
@ -207,7 +207,7 @@ public function availableFilters(): array
|
||||
],
|
||||
[
|
||||
'key' => 'tenant',
|
||||
'label' => 'ManagedEnvironment',
|
||||
'label' => 'Managed environment',
|
||||
'fixed' => false,
|
||||
'options' => collect($this->visibleTenants())
|
||||
->map(fn (ManagedEnvironment $tenant): array => [
|
||||
@ -261,11 +261,11 @@ public function emptyState(): array
|
||||
{
|
||||
if ($this->tenantFilterAloneExcludesRows()) {
|
||||
return [
|
||||
'title' => 'No assigned findings match this tenant scope',
|
||||
'body' => 'Your current tenant filter is hiding assigned work that is still visible elsewhere in this workspace.',
|
||||
'title' => 'No assigned findings match this environment scope',
|
||||
'body' => 'Your current environment filter is hiding assigned work that is still visible elsewhere in this workspace.',
|
||||
'icon' => 'heroicon-o-funnel',
|
||||
'action_name' => 'clear_tenant_filter_empty',
|
||||
'action_label' => 'Clear tenant filter',
|
||||
'action_label' => 'Clear environment filter',
|
||||
'action_kind' => 'clear_tenant_filter',
|
||||
];
|
||||
}
|
||||
@ -275,10 +275,10 @@ public function emptyState(): array
|
||||
if ($activeTenant instanceof ManagedEnvironment) {
|
||||
return [
|
||||
'title' => 'No visible assigned findings right now',
|
||||
'body' => 'Nothing currently assigned to you needs attention in the visible tenant scope. You can still open tenant findings for broader context.',
|
||||
'body' => 'Nothing currently assigned to you needs attention in the visible environment scope. You can still open environment findings for broader context.',
|
||||
'icon' => 'heroicon-o-clipboard-document-check',
|
||||
'action_name' => 'open_tenant_findings_empty',
|
||||
'action_label' => 'Open tenant findings',
|
||||
'action_label' => 'Open environment findings',
|
||||
'action_kind' => 'url',
|
||||
'action_url' => FindingResource::getUrl('index', tenant: $activeTenant),
|
||||
];
|
||||
@ -286,10 +286,10 @@ public function emptyState(): array
|
||||
|
||||
return [
|
||||
'title' => 'No visible assigned findings right now',
|
||||
'body' => 'Nothing currently assigned to you needs attention across the visible tenant scope. Choose a tenant to continue working elsewhere in the workspace.',
|
||||
'body' => 'Nothing currently assigned to you needs attention across the visible environment scope. Choose an environment to continue working elsewhere in the workspace.',
|
||||
'icon' => 'heroicon-o-clipboard-document-check',
|
||||
'action_name' => 'choose_tenant_empty',
|
||||
'action_label' => 'Choose a tenant',
|
||||
'action_label' => 'Choose an environment',
|
||||
'action_kind' => 'url',
|
||||
'action_url' => route('filament.admin.pages.choose-tenant'),
|
||||
];
|
||||
|
||||
@ -219,7 +219,7 @@ public function isActiveRegisterState(string $registerState): bool
|
||||
public function emptyStateHeading(): string
|
||||
{
|
||||
if ($this->tenantFilterAloneExcludesRows()) {
|
||||
return 'This tenant filter is hiding other visible decision follow-through';
|
||||
return 'This environment filter is hiding other visible decision follow-through';
|
||||
}
|
||||
|
||||
if ($this->registerState === 'recently_closed') {
|
||||
@ -232,20 +232,20 @@ public function emptyStateHeading(): string
|
||||
public function emptyStateDescription(): string
|
||||
{
|
||||
if ($this->tenantFilterAloneExcludesRows()) {
|
||||
return 'The current tenant scope is calm, but other visible tenants in this workspace still have open governance decisions.';
|
||||
return 'The current environment scope is calm, but other visible environments in this workspace still have open governance decisions.';
|
||||
}
|
||||
|
||||
if ($this->registerState === 'recently_closed') {
|
||||
return 'Switch back to open decisions to continue the current follow-through lane, or widen the tenant scope if you were filtering the register.';
|
||||
return 'Switch back to open decisions to continue the current follow-through lane, or widen the environment scope if you were filtering the register.';
|
||||
}
|
||||
|
||||
return 'Try widening the tenant scope or switch to recently closed decisions if you are checking what was just finished.';
|
||||
return 'Try widening the environment scope or switch to recently closed decisions if you are checking what was just finished.';
|
||||
}
|
||||
|
||||
public function emptyStateActionLabel(): ?string
|
||||
{
|
||||
if ($this->tenantFilterAloneExcludesRows()) {
|
||||
return 'Clear tenant filter';
|
||||
return 'Clear environment filter';
|
||||
}
|
||||
|
||||
if ($this->registerState === 'recently_closed') {
|
||||
|
||||
@ -145,9 +145,9 @@ public function calmEmptyState(): array
|
||||
{
|
||||
if ($this->tenantFilterAloneExcludesRows()) {
|
||||
return [
|
||||
'title' => 'This tenant filter is hiding other visible attention',
|
||||
'body' => 'The current tenant scope is calm, but other visible tenants in this workspace still have governance attention.',
|
||||
'action_label' => 'Clear tenant filter',
|
||||
'title' => 'This environment filter is hiding other visible attention',
|
||||
'body' => 'The current environment scope is calm, but other visible environments in this workspace still have governance attention.',
|
||||
'action_label' => 'Clear environment filter',
|
||||
'action_url' => $this->pageUrl(['tenant' => null]),
|
||||
];
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
|
||||
->satisfy(ActionSurfaceSlot::ListHeader, 'Header actions keep workspace approval scope visible and expose selected exception review actions.')
|
||||
->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ViewAction->value)
|
||||
->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'Exception decisions are reviewed one record at a time in v1 and do not expose bulk actions.')
|
||||
->satisfy(ActionSurfaceSlot::ListEmptyState, 'Empty state explains when the approval queue is empty and keeps navigation back to tenant findings available.')
|
||||
->satisfy(ActionSurfaceSlot::ListEmptyState, 'Empty state explains when the approval queue is empty and keeps navigation back to environment findings available.')
|
||||
->satisfy(ActionSurfaceSlot::DetailHeader, 'Selected exception detail exposes approve, reject, and related-record navigation actions in the page header.');
|
||||
}
|
||||
|
||||
@ -232,7 +232,7 @@ protected function getHeaderActions(): array
|
||||
});
|
||||
|
||||
$actions[] = Action::make('view_tenant_register')
|
||||
->label('View tenant register')
|
||||
->label('View environment findings')
|
||||
->icon('heroicon-o-arrow-top-right-on-square')
|
||||
->color('gray')
|
||||
->visible(fn (): bool => $this->filteredTenant() instanceof ManagedEnvironment)
|
||||
@ -254,7 +254,7 @@ protected function getHeaderActions(): array
|
||||
->url(fn (): string => $this->queueUrl(['exception' => null])),
|
||||
|
||||
Action::make('open_selected_exception')
|
||||
->label('Open tenant detail')
|
||||
->label('Open environment detail')
|
||||
->icon('heroicon-o-arrow-top-right-on-square')
|
||||
->color('gray')
|
||||
->visible(fn (): bool => $this->selectedFindingException() instanceof FindingException)
|
||||
|
||||
@ -440,7 +440,7 @@ public static function table(Table $table): Table
|
||||
|
||||
if (! $tenant instanceof ManagedEnvironment) {
|
||||
Notification::make()
|
||||
->title('No tenant selected')
|
||||
->title('No environment selected')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
@ -511,7 +511,7 @@ public static function table(Table $table): Table
|
||||
|
||||
if (! $tenant instanceof ManagedEnvironment) {
|
||||
Notification::make()
|
||||
->title('No tenant selected')
|
||||
->title('No environment selected')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
@ -728,7 +728,7 @@ public static function table(Table $table): Table
|
||||
|
||||
if (! $tenant instanceof ManagedEnvironment) {
|
||||
Notification::make()
|
||||
->title('No tenant selected')
|
||||
->title('No environment selected')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
@ -825,7 +825,7 @@ public static function table(Table $table): Table
|
||||
|
||||
if (! $tenant instanceof ManagedEnvironment) {
|
||||
Notification::make()
|
||||
->title('No tenant selected')
|
||||
->title('No environment selected')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
|
||||
@ -465,7 +465,7 @@ public static function table(Table $table): Table
|
||||
->label('Version')
|
||||
->placeholder('—'),
|
||||
TextColumn::make('tenant_assignments_count')
|
||||
->label('Assigned tenants')
|
||||
->label('Assigned environments')
|
||||
->counts('tenantAssignments'),
|
||||
TextColumn::make('current_snapshot_truth')
|
||||
->label('Current snapshot')
|
||||
|
||||
@ -311,11 +311,11 @@ private function compareNowAction(): Action
|
||||
private function compareAssignedTenantsAction(): Action
|
||||
{
|
||||
$action = Action::make('compareAssignedTenants')
|
||||
->label('Compare assigned tenants')
|
||||
->label('Compare assigned environments')
|
||||
->icon('heroicon-o-play')
|
||||
->requiresConfirmation()
|
||||
->modalHeading('Compare assigned tenants')
|
||||
->modalDescription('Simulation only. This starts the normal tenant-owned baseline compare path for the visible assigned set. No workspace umbrella run is created.')
|
||||
->modalHeading('Compare assigned environments')
|
||||
->modalDescription('Simulation only. This starts the normal environment-owned baseline compare path for the visible assigned set. No workspace umbrella run is created.')
|
||||
->disabled(fn (): bool => $this->compareAssignedTenantsDisabledReason() !== null)
|
||||
->tooltip(fn (): ?string => $this->compareAssignedTenantsDisabledReason())
|
||||
->action(function (): void {
|
||||
@ -489,11 +489,11 @@ private function compareAssignedTenantsDisabledReason(): ?string
|
||||
$profile = $this->getRecord();
|
||||
|
||||
if (! $this->profileHasConsumableSnapshot()) {
|
||||
return 'Capture a complete baseline snapshot before comparing assigned tenants.';
|
||||
return 'Capture a complete baseline snapshot before comparing assigned environments.';
|
||||
}
|
||||
|
||||
if ($this->visibleAssignedTenantCount($profile) === 0) {
|
||||
return 'No visible assigned tenants are available for compare.';
|
||||
return 'No visible assigned environments are available for compare.';
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@ -27,7 +27,7 @@ class BaselineTenantAssignmentsRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'tenantAssignments';
|
||||
|
||||
protected static ?string $title = 'ManagedEnvironment assignments';
|
||||
protected static ?string $title = 'Environment assignments';
|
||||
|
||||
/**
|
||||
* @var array<int, array{baseline_profile_id:int, baseline_profile_name:string}>|null
|
||||
@ -37,11 +37,11 @@ class BaselineTenantAssignmentsRelationManager extends RelationManager
|
||||
public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
|
||||
{
|
||||
return ActionSurfaceDeclaration::forRelationManager(ActionSurfaceProfile::RelationManager)
|
||||
->satisfy(ActionSurfaceSlot::ListHeader, 'Header action: Assign tenant (manage-gated).')
|
||||
->satisfy(ActionSurfaceSlot::ListHeader, 'Header action: Assign environment (manage-gated).')
|
||||
->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ClickableRow->value)
|
||||
->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'v1 assignments have no row-level actions beyond delete.')
|
||||
->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'No bulk mutations for assignments in v1.')
|
||||
->satisfy(ActionSurfaceSlot::ListEmptyState, 'Empty state encourages assigning a tenant.');
|
||||
->satisfy(ActionSurfaceSlot::ListEmptyState, 'Empty state encourages assigning an environment.');
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
@ -51,7 +51,7 @@ public function table(Table $table): Table
|
||||
->paginated(\App\Support\Filament\TablePaginationProfiles::relationManager())
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('tenant.name')
|
||||
->label('ManagedEnvironment')
|
||||
->label('Managed environment')
|
||||
->searchable(),
|
||||
Tables\Columns\TextColumn::make('assignedByUser.name')
|
||||
->label('Assigned by')
|
||||
@ -68,8 +68,8 @@ public function table(Table $table): Table
|
||||
->actions([
|
||||
$this->removeAssignmentAction(),
|
||||
])
|
||||
->emptyStateHeading('No tenants assigned')
|
||||
->emptyStateDescription('Assign a tenant to compare its state against this baseline profile.')
|
||||
->emptyStateHeading('No environments assigned')
|
||||
->emptyStateDescription('Assign an environment to compare its state against this baseline profile.')
|
||||
->emptyStateActions([
|
||||
$this->assignTenantAction()->name('assignEmpty'),
|
||||
]);
|
||||
@ -78,12 +78,12 @@ public function table(Table $table): Table
|
||||
private function assignTenantAction(): Action
|
||||
{
|
||||
return Action::make('assign')
|
||||
->label('Assign ManagedEnvironment')
|
||||
->label('Assign environment')
|
||||
->icon('heroicon-o-plus')
|
||||
->visible(fn (): bool => $this->hasManageCapability())
|
||||
->form([
|
||||
Select::make('managed_environment_id')
|
||||
->label('ManagedEnvironment')
|
||||
->label('Managed environment')
|
||||
->options(fn (): array => $this->getTenantOptions())
|
||||
->disableOptionWhen(fn (string $value): bool => array_key_exists((int) $value, $this->getTenantAssignmentSummaries()))
|
||||
->required()
|
||||
@ -114,10 +114,10 @@ private function assignTenantAction(): Action
|
||||
$assignedBaselineName = $this->getAssignedBaselineNameForTenant($tenantId);
|
||||
|
||||
Notification::make()
|
||||
->title('ManagedEnvironment already assigned')
|
||||
->title('Environment already assigned')
|
||||
->body($assignedBaselineName === null
|
||||
? 'This tenant already has a baseline assignment in this workspace.'
|
||||
: "This tenant is already assigned to baseline: {$assignedBaselineName}.")
|
||||
? 'This environment already has a baseline assignment in this workspace.'
|
||||
: "This environment is already assigned to baseline: {$assignedBaselineName}.")
|
||||
->warning()
|
||||
->send();
|
||||
|
||||
@ -134,7 +134,7 @@ private function assignTenantAction(): Action
|
||||
$this->auditAssignment($profile, $assignment, $user, 'created');
|
||||
|
||||
Notification::make()
|
||||
->title('ManagedEnvironment assigned')
|
||||
->title('Environment assigned')
|
||||
->success()
|
||||
->send();
|
||||
|
||||
@ -150,8 +150,8 @@ private function removeAssignmentAction(): Action
|
||||
->color('danger')
|
||||
->visible(fn (): bool => $this->hasManageCapability())
|
||||
->requiresConfirmation()
|
||||
->modalHeading('Remove tenant assignment')
|
||||
->modalDescription('Are you sure you want to remove this tenant assignment? This will not delete any existing findings.')
|
||||
->modalHeading('Remove environment assignment')
|
||||
->modalDescription('Are you sure you want to remove this environment assignment? This will not delete any existing findings.')
|
||||
->action(function (BaselineTenantAssignment $record): void {
|
||||
$user = auth()->user();
|
||||
|
||||
|
||||
@ -225,10 +225,10 @@ private function lifecycleActionForContext(
|
||||
destructive: true,
|
||||
requiresConfirmation: true,
|
||||
auditActionId: AuditActionId::TenantRestored,
|
||||
successNotificationTitle: 'ManagedEnvironment restored',
|
||||
successNotificationBody: 'The tenant is available again in normal tenant management flows and can be selected as active context.',
|
||||
modalHeading: 'Restore tenant',
|
||||
modalDescription: 'Restore this archived tenant so it can be selected again in normal tenant management flows.',
|
||||
successNotificationTitle: 'Environment restored',
|
||||
successNotificationBody: 'The environment is available again in normal environment management flows and can be selected as active context.',
|
||||
modalHeading: 'Restore environment',
|
||||
modalDescription: 'Restore this archived environment so it can be selected again in normal environment management flows.',
|
||||
group: $group,
|
||||
);
|
||||
}
|
||||
@ -250,10 +250,10 @@ private function lifecycleActionForContext(
|
||||
destructive: true,
|
||||
requiresConfirmation: true,
|
||||
auditActionId: AuditActionId::TenantArchived,
|
||||
successNotificationTitle: 'ManagedEnvironment archived',
|
||||
successNotificationBody: 'The tenant remains available for inspection and audit history, but it is no longer selectable as active context.',
|
||||
modalHeading: 'Archive tenant',
|
||||
modalDescription: 'Archive this tenant to retain it for inspection and audit history while removing it from active management flows.',
|
||||
successNotificationTitle: 'Environment archived',
|
||||
successNotificationBody: 'The environment remains available for inspection and audit history, but it is no longer selectable as active context.',
|
||||
modalHeading: 'Archive environment',
|
||||
modalDescription: 'Archive this environment to retain it for inspection and audit history while removing it from active management flows.',
|
||||
group: $group,
|
||||
);
|
||||
}
|
||||
|
||||
@ -973,15 +973,15 @@ private function emptyState(
|
||||
|
||||
if ((int) ($reference['assignedTenantCount'] ?? 0) === 0) {
|
||||
return [
|
||||
'title' => 'No assigned tenants',
|
||||
'body' => 'Assign tenants to this baseline profile to build the visible compare set.',
|
||||
'title' => 'No assigned environments',
|
||||
'body' => 'Assign environments to this baseline profile to build the visible compare set.',
|
||||
];
|
||||
}
|
||||
|
||||
if ($visibleTenantsCount === 0) {
|
||||
return [
|
||||
'title' => 'No visible assigned tenants',
|
||||
'body' => 'This baseline has assigned tenants, but none are visible in your current tenant scope.',
|
||||
'title' => 'No visible assigned environments',
|
||||
'body' => 'This baseline has assigned environments, but none are visible in your current environment scope.',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -92,7 +92,7 @@ private function __construct(
|
||||
public static function forTenant(?ManagedEnvironment $tenant): self
|
||||
{
|
||||
if (! $tenant instanceof ManagedEnvironment) {
|
||||
return self::empty('no_tenant', 'No tenant selected.');
|
||||
return self::empty('no_tenant', 'No environment selected.');
|
||||
}
|
||||
|
||||
$findingAttentionCounts = self::findingAttentionCounts($tenant);
|
||||
|
||||
@ -256,7 +256,7 @@ private function findingExceptionsSection(
|
||||
),
|
||||
'entries' => $entries,
|
||||
'empty_state' => $selectedTenant instanceof ManagedEnvironment
|
||||
? 'No finding exceptions match this tenant filter right now.'
|
||||
? 'No finding exceptions match this environment filter right now.'
|
||||
: 'No finding exceptions need review right now.',
|
||||
];
|
||||
}
|
||||
@ -315,7 +315,7 @@ private function assignedFindingsSection(
|
||||
),
|
||||
'entries' => $entries,
|
||||
'empty_state' => $selectedTenant instanceof ManagedEnvironment
|
||||
? 'No assigned findings match this tenant filter right now.'
|
||||
? 'No assigned findings match this environment filter right now.'
|
||||
: 'No assigned findings are visible right now.',
|
||||
];
|
||||
}
|
||||
@ -358,7 +358,7 @@ private function intakeFindingsSection(
|
||||
),
|
||||
'entries' => $entries,
|
||||
'empty_state' => $selectedTenant instanceof ManagedEnvironment
|
||||
? 'No intake findings match this tenant filter right now.'
|
||||
? 'No intake findings match this environment filter right now.'
|
||||
: 'No intake findings are visible right now.',
|
||||
];
|
||||
}
|
||||
@ -409,7 +409,7 @@ private function operationsSection(
|
||||
),
|
||||
'entries' => $entries,
|
||||
'empty_state' => $selectedTenant instanceof ManagedEnvironment
|
||||
? 'No stale or terminal follow-up operations match this tenant filter right now.'
|
||||
? 'No stale or terminal follow-up operations match this environment filter right now.'
|
||||
: 'No stale or terminal follow-up operations are visible right now.',
|
||||
];
|
||||
}
|
||||
@ -456,7 +456,7 @@ private function alertsSection(
|
||||
),
|
||||
'entries' => $entries,
|
||||
'empty_state' => $selectedTenant instanceof ManagedEnvironment
|
||||
? 'No failed alert deliveries match this tenant filter right now.'
|
||||
? 'No failed alert deliveries match this environment filter right now.'
|
||||
: 'No failed alert deliveries are visible right now.',
|
||||
];
|
||||
}
|
||||
@ -554,7 +554,7 @@ private function reviewFollowUpSection(
|
||||
: $this->appendQuery(CustomerReviewWorkspace::getUrl(panel: 'admin'), $navigationContext?->toQuery() ?? []),
|
||||
'entries' => array_slice($rawEntries, 0, self::PREVIEW_LIMIT),
|
||||
'empty_state' => $selectedTenant instanceof ManagedEnvironment
|
||||
? 'No review follow-up is visible for this tenant filter right now.'
|
||||
? 'No review follow-up is visible for this environment filter right now.'
|
||||
: 'No review follow-up is visible right now.',
|
||||
];
|
||||
}
|
||||
|
||||
@ -252,9 +252,9 @@ private function translateBaselineReason(string $reasonCode, array $context = []
|
||||
],
|
||||
BaselineReasonCodes::COMPARE_NO_ELIGIBLE_TARGET => [
|
||||
'No eligible compare target',
|
||||
'No assigned tenant with compare access is currently available for this baseline profile.',
|
||||
'No assigned environment with compare access is currently available for this baseline profile.',
|
||||
'prerequisite_missing',
|
||||
'Assign this baseline to a tenant you can compare, or use an account with access to an assigned tenant.',
|
||||
'Assign this baseline to an environment you can compare, or use an account with access to an assigned environment.',
|
||||
],
|
||||
BaselineReasonCodes::COMPARE_INVALID_SNAPSHOT => [
|
||||
'Selected snapshot unavailable',
|
||||
|
||||
@ -309,10 +309,10 @@ public static function rules(): array
|
||||
reasonPolicy: GovernanceReasonPolicy::Required,
|
||||
dangerPolicy: 'required',
|
||||
canonicalLabel: 'Archive',
|
||||
modalHeading: 'Archive tenant',
|
||||
modalDescription: 'Archive this tenant. TenantPilot keeps it available for inspection and audit history but removes it from active management flows.',
|
||||
successTitle: 'ManagedEnvironment archived',
|
||||
auditVerb: 'archive tenant',
|
||||
modalHeading: 'Archive environment',
|
||||
modalDescription: 'Archive this environment. TenantPilot keeps it available for inspection and audit history but removes it from active management flows.',
|
||||
successTitle: 'Environment archived',
|
||||
auditVerb: 'archive environment',
|
||||
serviceOwner: 'TenantResource',
|
||||
surfaceKeys: ['tenant_index_row', 'view_tenant', 'edit_tenant'],
|
||||
),
|
||||
@ -323,10 +323,10 @@ public static function rules(): array
|
||||
reasonPolicy: GovernanceReasonPolicy::None,
|
||||
dangerPolicy: 'none',
|
||||
canonicalLabel: 'Restore',
|
||||
modalHeading: 'Restore tenant',
|
||||
modalDescription: 'Restore this tenant so it becomes available again in normal management flows.',
|
||||
successTitle: 'ManagedEnvironment restored',
|
||||
auditVerb: 'restore tenant',
|
||||
modalHeading: 'Restore environment',
|
||||
modalDescription: 'Restore this environment so it becomes available again in normal management flows.',
|
||||
successTitle: 'Environment restored',
|
||||
auditVerb: 'restore environment',
|
||||
serviceOwner: 'TenantResource',
|
||||
surfaceKeys: ['tenant_index_row', 'view_tenant', 'edit_tenant'],
|
||||
),
|
||||
|
||||
@ -1017,7 +1017,7 @@ private function summaryMetrics(
|
||||
category: 'backup_health',
|
||||
description: $this->reviewSummaryMetricDescription(
|
||||
family: PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH,
|
||||
baseDescription: 'Visible tenants with non-healthy backup posture.',
|
||||
baseDescription: 'Visible environments with non-healthy backup posture.',
|
||||
triageReviewSummaries: $triageReviewSummaries,
|
||||
),
|
||||
color: $backupAttentionTenantCount > 0 ? 'danger' : 'gray',
|
||||
@ -1034,7 +1034,7 @@ private function summaryMetrics(
|
||||
category: 'recovery_evidence',
|
||||
description: $this->reviewSummaryMetricDescription(
|
||||
family: PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE,
|
||||
baseDescription: 'Visible tenants with weakened or unvalidated recovery evidence.',
|
||||
baseDescription: 'Visible environments with weakened or unvalidated recovery evidence.',
|
||||
triageReviewSummaries: $triageReviewSummaries,
|
||||
),
|
||||
color: $recoveryAttentionTenantCount > 0 ? 'warning' : 'gray',
|
||||
@ -1397,7 +1397,7 @@ private function calmnessState(
|
||||
'is_calm' => false,
|
||||
'checked_domains' => $checkedDomains,
|
||||
'title' => 'Workspace activity still needs review',
|
||||
'body' => 'Backup health or recovery evidence still needs follow-up, or activity remains open in the visible workspace, but your current scope does not expose a more specific tenant drill-through here. Review operations first.',
|
||||
'body' => 'Backup health or recovery evidence still needs follow-up, or activity remains open in the visible workspace, but your current scope does not expose a more specific environment drill-through here. Review operations first.',
|
||||
'next_action' => $this->operationsIndexTarget(null, $navigationContext, 'active'),
|
||||
];
|
||||
}
|
||||
@ -1405,7 +1405,7 @@ private function calmnessState(
|
||||
return [
|
||||
'is_calm' => false,
|
||||
'checked_domains' => $checkedDomains,
|
||||
'title' => 'Visible tenants still need attention',
|
||||
'title' => 'Visible environments still need attention',
|
||||
'body' => 'Backup health or recovery evidence still needs follow-up, or governance and activity remain open in this workspace.',
|
||||
'next_action' => $attentionItems[0]['destination'] ?? $this->chooseTenantTarget(),
|
||||
];
|
||||
|
||||
@ -45,23 +45,23 @@
|
||||
'switch_environment' => 'Umgebung wechseln',
|
||||
'clear_environment_scope' => 'Umgebungskontext löschen',
|
||||
'back_to_environment_registry' => 'Zur Umgebungsregistrierung zurück',
|
||||
'tenant_scope' => 'Tenant-Kontext',
|
||||
'select_tenant' => 'Tenant auswählen',
|
||||
'selected_tenant' => 'Ausgewählter Tenant',
|
||||
'no_tenant_selected' => 'Kein Tenant ausgewählt',
|
||||
'switch_tenant' => 'Tenant wechseln',
|
||||
'clear_tenant_scope' => 'Tenant-Kontext löschen',
|
||||
'tenant_scope' => 'Umgebungskontext',
|
||||
'select_tenant' => 'Umgebung auswählen',
|
||||
'selected_tenant' => 'Ausgewählte Umgebung',
|
||||
'no_tenant_selected' => 'Keine Umgebung ausgewählt',
|
||||
'switch_tenant' => 'Umgebung wechseln',
|
||||
'clear_tenant_scope' => 'Umgebungskontext löschen',
|
||||
'context_unavailable' => 'Kontext nicht verfügbar',
|
||||
'context_unavailable_workspace' => 'Der angeforderte Kontext konnte nicht wiederhergestellt werden. Die Shell zeigt stattdessen einen gültigen Workspace-Kontext.',
|
||||
'context_unavailable_no_workspace' => 'Wählen Sie einen Workspace aus, um mit einem gültigen Admin-Kontext fortzufahren.',
|
||||
'no_active_environments' => 'Keine aktiven Umgebungen verfügbar',
|
||||
'no_active_environments_description' => 'In diesem Workspace sind keine auswählbaren aktiven Umgebungen für den normalen Betriebskontext verfügbar. Workspace-weite Seiten funktionieren weiterhin ohne ausgewählte Umgebung, und Sie können Onboarding- oder archivierte Einträge über Managed Environments prüfen.',
|
||||
'view_managed_environments' => 'Managed Environments anzeigen',
|
||||
'no_active_tenants' => 'In diesem Workspace sind keine aktiven Tenants für den Standardbetrieb verfügbar.',
|
||||
'view_managed_tenants' => 'Managed Tenants anzeigen',
|
||||
'workspace_wide_available' => 'Kein Tenant ausgewählt. Workspace-weite Seiten bleiben verfügbar; ein Tenant setzt nur den normalen aktiven Betriebskontext.',
|
||||
'no_active_tenants' => 'In diesem Workspace sind keine aktiven Umgebungen für den Standardbetrieb verfügbar.',
|
||||
'view_managed_tenants' => 'Managed Environments anzeigen',
|
||||
'workspace_wide_available' => 'Keine Umgebung ausgewählt. Workspace-weite Seiten bleiben verfügbar; eine Umgebung setzt nur den normalen aktiven Betriebskontext.',
|
||||
'search_environments' => 'Umgebungen suchen...',
|
||||
'search_tenants' => 'Tenants suchen...',
|
||||
'search_tenants' => 'Umgebungen suchen...',
|
||||
'choose_workspace_first' => 'Wählen Sie zuerst einen Workspace aus.',
|
||||
],
|
||||
'workspace' => [
|
||||
@ -81,7 +81,7 @@
|
||||
'auth' => [
|
||||
'microsoft_not_configured' => 'Microsoft-Anmeldung ist nicht konfiguriert.',
|
||||
'sign_in_microsoft' => 'Mit Microsoft anmelden',
|
||||
'tenant_admin_membership_required' => 'ManagedEnvironment-Admin-Zugriff erfordert eine ManagedEnvironment-Mitgliedschaft.',
|
||||
'tenant_admin_membership_required' => 'Admin-Zugriff erfordert eine Umgebungsmitgliedschaft.',
|
||||
],
|
||||
'navigation' => [
|
||||
'findings' => 'Findings',
|
||||
@ -96,7 +96,7 @@
|
||||
'dashboard' => 'Dashboard',
|
||||
],
|
||||
'dashboard' => [
|
||||
'tenant_title' => 'Tenant-Dashboard',
|
||||
'tenant_title' => 'Umgebungs-Dashboard',
|
||||
'environment_title' => 'Umgebungs-Dashboard',
|
||||
'system_title' => 'System-Dashboard',
|
||||
'more_actions' => 'Mehr',
|
||||
@ -139,7 +139,7 @@
|
||||
'open_external_ticket' => 'Externes Ticket öffnen',
|
||||
'open_support_diagnostics' => 'Supportdiagnosen öffnen',
|
||||
'support_diagnostics' => 'Supportdiagnosen',
|
||||
'support_diagnostics_description' => 'Redaktionell bereinigter Tenant-Kontext aus bestehenden Datensätzen.',
|
||||
'support_diagnostics_description' => 'Redaktionell bereinigter Umgebungskontext aus bestehenden Datensätzen.',
|
||||
'close' => 'Schließen',
|
||||
'time_window' => 'Zeitfenster',
|
||||
'window' => 'Fenster',
|
||||
@ -150,7 +150,7 @@
|
||||
'overview' => [
|
||||
'page_subheading' => 'Umgebungs-Governance-Übersicht',
|
||||
'context_workspace' => 'Aktueller Workspace',
|
||||
'context_no_tenant' => 'Kein Tenant ausgewählt',
|
||||
'context_no_tenant' => 'Keine Umgebung ausgewählt',
|
||||
'context_no_environment' => 'Keine Umgebung ausgewählt',
|
||||
'context_workspace_chip' => 'Workspace: :workspace',
|
||||
'context_provider_chip' => ':provider-Umgebung',
|
||||
@ -162,15 +162,15 @@
|
||||
'status_not_ready' => 'Nicht bereit',
|
||||
'status_evidence_available' => 'Nachweise verfügbar',
|
||||
'status_needs_action' => 'Aufmerksamkeit erforderlich',
|
||||
'tenant_context_unavailable_headline' => 'Tenant-Kontext ist nicht verfügbar.',
|
||||
'tenant_context_unavailable_summary' => 'Wählen Sie einen Tenant aus, um die entscheidungsorientierte Dashboard-Übersicht anzuzeigen.',
|
||||
'tenant_context_unavailable_headline' => 'Umgebungskontext ist nicht verfügbar.',
|
||||
'tenant_context_unavailable_summary' => 'Wählen Sie eine Umgebung aus, um die entscheidungsorientierte Dashboard-Übersicht anzuzeigen.',
|
||||
'environment_context_unavailable_headline' => 'Umgebungskontext ist nicht verfügbar.',
|
||||
'environment_context_unavailable_summary' => 'Wählen Sie eine Umgebung aus, um die entscheidungsorientierte Dashboard-Übersicht anzuzeigen.',
|
||||
'posture_blocked_headline' => 'Provider-Berechtigungen blockieren Tenant-Workflows.',
|
||||
'posture_blocked_headline' => 'Provider-Berechtigungen blockieren Umgebungs-Workflows.',
|
||||
'posture_blocked_summary' => 'Erforderliche Anwendungsberechtigungen fehlen. Provider-gestützte Abläufe können deshalb nicht als bereit bewertet werden.',
|
||||
'posture_calm_headline' => 'Kein unmittelbarer Tenant-Blocker ist sichtbar.',
|
||||
'posture_calm_headline' => 'Kein unmittelbarer Umgebungs-Blocker ist sichtbar.',
|
||||
'posture_calm_summary' => 'Aktuelle Findings, Berechtigungen, Wiederherstellungsstatus und letzte Vorgänge zeigen derzeit keinen dringenden Folgeschritt.',
|
||||
'posture_action_needed_fallback_summary' => 'Der Tenant benötigt noch Operator-Nachverfolgung, bevor die Startseite als ruhig gelten kann.',
|
||||
'posture_action_needed_fallback_summary' => 'Die Umgebung benötigt noch Operator-Nachverfolgung, bevor die Startseite als ruhig gelten kann.',
|
||||
'section_recommended_actions' => 'Empfohlene nächste Aktionen',
|
||||
'section_governance_status' => 'Governance-Status',
|
||||
'section_readiness' => 'Review- und Nachweisbereitschaft',
|
||||
@ -180,9 +180,9 @@
|
||||
'label_reason' => 'Grund',
|
||||
'label_impact' => 'Auswirkung',
|
||||
'empty_recommended_actions_headline' => 'Derzeit wartet keine unmittelbare Aktion.',
|
||||
'empty_recommended_actions_summary' => 'Der Tenant wirkt aktuell ruhig. Nutzen Sie die Status- und Bereitschaftsbereiche unten, um zu bestätigen, was gesund ist und was lediglich nicht verfügbar ist.',
|
||||
'empty_recommended_actions_summary' => 'Die Umgebung wirkt aktuell ruhig. Nutzen Sie die Status- und Bereitschaftsbereiche unten, um zu bestätigen, was gesund ist und was lediglich nicht verfügbar ist.',
|
||||
'empty_recent_operations_headline' => 'Noch keine letzten Vorgänge.',
|
||||
'empty_recent_operations_summary' => 'Sobald Tenant-Vorgänge laufen, erscheint hier der letzte Ausführungskontext, ohne die erste Entscheidungsebene zu übernehmen.',
|
||||
'empty_recent_operations_summary' => 'Sobald Umgebungs-Vorgänge laufen, erscheint hier der letzte Ausführungskontext, ohne die erste Entscheidungsebene zu übernehmen.',
|
||||
'kpi_high_severity_label' => 'Findings mit hoher Kritikalität',
|
||||
'kpi_high_severity_description' => 'Hohe oder kritische Findings warten noch auf Prüfung.',
|
||||
'kpi_high_severity_tendency' => ':count aktiv',
|
||||
@ -193,13 +193,13 @@
|
||||
'kpi_overdue_tendency' => ':count aktuell überfällig',
|
||||
'kpi_overdue_tendency_none' => 'Nichts überfällig',
|
||||
'kpi_missing_permissions_label' => 'Fehlende Berechtigungen',
|
||||
'kpi_missing_permissions_description' => 'Für diesen Tenant fehlen derzeit providerseitig erforderliche Berechtigungen.',
|
||||
'kpi_missing_permissions_description' => 'Für diese Umgebung fehlen derzeit providerseitig erforderliche Berechtigungen.',
|
||||
'kpi_missing_permissions_tendency_split' => ':app App · :delegated delegiert fehlen',
|
||||
'kpi_missing_permissions_tendency_app_only' => ':count App-Berechtigungen fehlen',
|
||||
'kpi_missing_permissions_tendency_delegated_only' => ':count delegierte Berechtigungen fehlen',
|
||||
'kpi_missing_permissions_tendency_none' => 'Berechtigungen vollständig',
|
||||
'kpi_active_operations_label' => 'Vorgänge mit Aufmerksamkeitsbedarf',
|
||||
'kpi_active_operations_description' => 'Vorgangsläufe, die noch Follow-up benötigen, bevor der Tenant als gesund gelten kann.',
|
||||
'kpi_active_operations_description' => 'Vorgangsläufe, die noch Follow-up benötigen, bevor die Umgebung als gesund gelten kann.',
|
||||
'kpi_active_operations_tendency' => ':count Vorgänge erfordern Aufmerksamkeit',
|
||||
'kpi_active_operations_tendency_window' => ':count Vorgänge erfordern Aufmerksamkeit',
|
||||
'kpi_active_operations_tendency_one' => '1 Vorgang benötigt Follow-up',
|
||||
@ -230,18 +230,18 @@
|
||||
'reason_missing_application_permissions' => ':count Anwendungsberechtigung(en) fehlen noch.',
|
||||
'impact_missing_application_permissions' => 'Provider-gestützte Inventarisierung, Verifikation und Berichte bleiben blockiert, bis die Zustimmung wiederhergestellt ist.',
|
||||
'reason_missing_delegated_permissions' => ':count delegierte Berechtigung(en) benötigen noch Aufmerksamkeit.',
|
||||
'impact_missing_delegated_permissions' => 'Der Tenant bleibt nur teilweise bereit, bis delegierte Berechtigungen geprüft und bei Bedarf erteilt wurden.',
|
||||
'impact_missing_delegated_permissions' => 'Die Umgebung bleibt nur teilweise bereit, bis delegierte Berechtigungen geprüft und bei Bedarf erteilt wurden.',
|
||||
'reason_high_severity_findings' => ':count Findings mit hoher Kritikalität benötigen noch eine Operator-Prüfung.',
|
||||
'impact_high_severity_findings' => 'Schwere Drift bleibt ungelöst, bis diese Findings triagiert oder behoben sind.',
|
||||
'reason_overdue_findings' => ':count Finding(s) sind bereits überfällig.',
|
||||
'impact_overdue_findings' => 'Workflow-Verzögerungen können die aktuelle Risikolage des Tenants verschleiern, bis überfällige Punkte bereinigt sind.',
|
||||
'impact_overdue_findings' => 'Workflow-Verzögerungen können die aktuelle Risikolage der Umgebung verschleiern, bis überfällige Punkte bereinigt sind.',
|
||||
'reason_risk_exceptions' => ':count Risikoausnahme(n) oder Governance-Punkte mit akzeptiertem Risiko benötigen Nachverfolgung.',
|
||||
'impact_risk_exceptions' => 'Aussagen zu akzeptierten Risiken verlieren an Vertrauenswürdigkeit, wenn ihre Ausnahmehistorie nicht mehr aktuell ist.',
|
||||
'impact_recovery_posture' => 'Die Wiederherstellungsbereitschaft sollte geprüft werden, bevor kundensichere Aussagen auf Backup- oder Restore-Vertrauen beruhen.',
|
||||
'reason_terminal_operations' => ':count Vorgangslauf/Läufe endeten blockiert, teilweise oder fehlgeschlagen.',
|
||||
'impact_terminal_operations' => 'Terminale Laufergebnisse benötigen Nachverfolgung, bevor der Tenant als ruhig gelten kann.',
|
||||
'impact_terminal_operations' => 'Terminale Laufergebnisse benötigen Nachverfolgung, bevor die Umgebung als ruhig gelten kann.',
|
||||
'reason_operations_requiring_attention' => 'Ein oder mehrere Vorgänge endeten mit einem Ergebnis, das Follow-up benötigt.',
|
||||
'impact_operations_requiring_attention' => 'Der Tenant sollte nicht als vollständig gesund betrachtet werden, bis das Vorgangsergebnis geprüft wurde.',
|
||||
'impact_operations_requiring_attention' => 'Die Umgebung sollte nicht als vollständig gesund betrachtet werden, bis das Vorgangsergebnis geprüft wurde.',
|
||||
'reason_continue_review' => 'Kundensichere Ausgabe ist noch nicht vollständig bereit.',
|
||||
'impact_continue_review' => 'Die Review-Ausgabe bleibt teilweise, bis Review-, Nachweis- und Paketflächen sauber zusammenpassen.',
|
||||
'operations_attention_title' => 'Vorgänge mit Aufmerksamkeitsbedarf',
|
||||
@ -253,16 +253,16 @@
|
||||
'operations_attention_outcome_generic' => 'Der Vorgang endete mit einem Ergebnis, das Nachverfolgung benötigt.',
|
||||
'operations_attention_outcome_stale' => 'Der Vorgang ist noch aktiv, liegt aber außerhalb seines erwarteten Lebenszyklusfensters.',
|
||||
'operations_attention_outcome_provider_consent_required' => 'Die Prüfung ist abgeschlossen, aber die Provider-Zustimmung ist noch erforderlich.',
|
||||
'operations_attention_reason_fallback' => 'Das aufgezeichnete Ergebnis muss geprüft werden, bevor der Tenant als gesund gelten kann.',
|
||||
'operations_attention_reason_fallback' => 'Das aufgezeichnete Ergebnis muss geprüft werden, bevor die Umgebung als gesund gelten kann.',
|
||||
'operations_attention_reason_stale' => 'Der Lauf liegt außerhalb seines normalen Lebenszyklusfensters und schreitet möglicherweise nicht mehr fort.',
|
||||
'operations_attention_reason_provider_consent_required' => 'Eine Admin-Zustimmung ist erforderlich, bevor die Provider-Verbindung verwendet werden kann.',
|
||||
'operations_attention_impact_follow_up' => 'Die Tenant-Bereitschaft sollte nicht als vollständig gesund betrachtet werden, bis das Vorgangsergebnis geprüft wurde.',
|
||||
'operations_attention_impact_stale' => 'Die Tenant-Bereitschaft sollte nicht als aktuell betrachtet werden, bis der blockierte Lauf geprüft wurde.',
|
||||
'operations_attention_impact_provider_consent_required' => 'Die Tenant-Bereitschaft kann nicht als gesund betrachtet werden, bis dies geprüft wurde.',
|
||||
'operations_attention_impact_follow_up' => 'Die Umgebungsbereitschaft sollte nicht als vollständig gesund betrachtet werden, bis das Vorgangsergebnis geprüft wurde.',
|
||||
'operations_attention_impact_stale' => 'Die Umgebungsbereitschaft sollte nicht als aktuell betrachtet werden, bis der blockierte Lauf geprüft wurde.',
|
||||
'operations_attention_impact_provider_consent_required' => 'Die Umgebungsbereitschaft kann nicht als gesund betrachtet werden, bis dies geprüft wurde.',
|
||||
'operations_attention_timing_completed' => 'Abgeschlossen :time',
|
||||
'operations_attention_timing_started' => 'Gestartet :time',
|
||||
'governance_baseline_compare_label' => 'Baseline Compare',
|
||||
'governance_baseline_compare_description' => 'Aktueller Compare-Status für die Tenant-Baseline.',
|
||||
'governance_baseline_compare_description' => 'Aktueller Compare-Status für die Umgebungs-Baseline.',
|
||||
'governance_evidence_coverage_label' => 'Nachweisabdeckung',
|
||||
'governance_review_freshness_label' => 'Review-Aktualität',
|
||||
'governance_provider_permissions_label' => 'Provider-Berechtigungen',
|
||||
@ -270,7 +270,7 @@
|
||||
'governance_backup_posture_unavailable_description' => 'Wiederherstellungsbereitschaft ist noch nicht verfügbar.',
|
||||
'readiness_current_review_title' => 'Aktuelles Review',
|
||||
'readiness_current_review_empty_status' => 'Kein aktives Review',
|
||||
'readiness_current_review_empty_description' => 'Für diesen Tenant ist aktuell kein Review in Bearbeitung.',
|
||||
'readiness_current_review_empty_description' => 'Für diese Umgebung ist aktuell kein Review in Bearbeitung.',
|
||||
'readiness_current_review_updated_label' => 'Zuletzt aktualisiert',
|
||||
'readiness_current_review_findings_progress_label' => 'Findings mit Ergebnis',
|
||||
'readiness_current_review_completion_progress_label' => 'Review-Fortschritt',
|
||||
@ -285,16 +285,16 @@
|
||||
'readiness_risk_exceptions_pending_label' => 'Ausstehende Freigaben',
|
||||
'readiness_provider_health_title' => 'Provider Health',
|
||||
'readiness_provider_health_empty_status' => 'Provider-Status nicht verfügbar',
|
||||
'readiness_provider_health_empty_description' => 'Für diesen Tenant liegt aktuell kein Provider-Health-Snapshot vor.',
|
||||
'readiness_provider_health_empty_description' => 'Für diese Umgebung liegt aktuell kein Provider-Health-Snapshot vor.',
|
||||
'readiness_provider_health_last_check_label' => 'Letzter Check',
|
||||
'readiness_provider_health_permissions_label' => 'Fehlende Berechtigungen',
|
||||
'readiness_provider_health_snapshot_label' => 'Berechtigungs-Snapshot',
|
||||
'readiness_provider_health_degraded_description' => 'Der letzte Provider-Health-Check hat Warnungen für diesen Tenant gemeldet.',
|
||||
'readiness_provider_health_blocked_description' => 'Der Provider-Health-Check ist für diesen Tenant aktuell blockiert.',
|
||||
'readiness_provider_health_error_description' => 'Der Provider-Health-Check ist für diesen Tenant fehlgeschlagen.',
|
||||
'readiness_provider_health_pending_description' => 'Der letzte Provider-Health-Check läuft für diesen Tenant noch.',
|
||||
'readiness_provider_health_degraded_description' => 'Der letzte Provider-Health-Check hat Warnungen für diese Umgebung gemeldet.',
|
||||
'readiness_provider_health_blocked_description' => 'Der Provider-Health-Check ist für diese Umgebung aktuell blockiert.',
|
||||
'readiness_provider_health_error_description' => 'Der Provider-Health-Check ist für diese Umgebung fehlgeschlagen.',
|
||||
'readiness_provider_health_pending_description' => 'Der letzte Provider-Health-Check läuft für diese Umgebung noch.',
|
||||
'readiness_provider_health_unknown_description' => 'Für diesen Tenant wurde noch kein Provider-Health-Check erfasst.',
|
||||
'helper_findings_requires_permissions' => 'Sie sehen den Tenant-Status, aber zum Öffnen von Findings sind zusätzliche Berechtigungen erforderlich.',
|
||||
'helper_findings_requires_permissions' => 'Sie sehen den Umgebungsstatus, aber zum Öffnen von Findings sind zusätzliche Berechtigungen erforderlich.',
|
||||
'helper_risk_exceptions_requires_permissions' => 'Sie sehen die Zusammenfassung, aber zum Öffnen von Risikoausnahmen sind zusätzliche Berechtigungen erforderlich.',
|
||||
'helper_review_requires_permissions' => 'Sie sehen die Zusammenfassung, aber zum Öffnen der Review-Details sind zusätzliche Berechtigungen erforderlich.',
|
||||
'helper_continue_review_requires_manage' => 'Sie können den aktuellen Review-Status einsehen, aber nur Review-Manager können den Review-Workflow fortsetzen.',
|
||||
@ -306,7 +306,7 @@
|
||||
'helper_backup_posture_requires_permissions' => 'Sie sehen die Zusammenfassung, aber zum Öffnen der Backup-Statusdetails sind zusätzliche Berechtigungen erforderlich.',
|
||||
'evidence_unavailable_description' => 'Derzeit ist kein Nachweis-Snapshot für kundensichere Ausgabe verfügbar.',
|
||||
'evidence_generated_prefix' => 'Letzter Nachweis-Snapshot erstellt :time.',
|
||||
'review_unavailable_description' => 'Für diesen Tenant ist derzeit kein Tenant-Review verfügbar.',
|
||||
'review_unavailable_description' => 'Für diese Umgebung ist derzeit kein Review verfügbar.',
|
||||
'review_updated_prefix' => 'Letztes Review aktualisiert :time.',
|
||||
'provider_permissions_ready' => 'Bereit',
|
||||
'provider_permissions_blocked' => 'Blockiert',
|
||||
@ -321,7 +321,7 @@
|
||||
'risk_exceptions_pending_description' => 'Ausstehende, auslaufende oder abgelaufene Ausnahmen benötigen weiterhin Governance-Nachverfolgung.',
|
||||
'risk_exceptions_active_description' => 'Ausnahmen für akzeptierte Risiken bestehen, benötigen aktuell aber keine dringende Prüfung.',
|
||||
'risk_exceptions_calm_description' => 'Derzeit benötigen keine Risikoausnahmen Aufmerksamkeit.',
|
||||
'recent_operation_fallback_summary' => 'Aktueller Vorgangskontext für diesen Tenant.',
|
||||
'recent_operation_fallback_summary' => 'Aktueller Vorgangskontext für diese Umgebung.',
|
||||
],
|
||||
],
|
||||
'review' => [
|
||||
|
||||
@ -45,23 +45,23 @@
|
||||
'switch_environment' => 'Switch environment',
|
||||
'clear_environment_scope' => 'Clear environment scope',
|
||||
'back_to_environment_registry' => 'Back to environment registry',
|
||||
'tenant_scope' => 'Tenant scope',
|
||||
'select_tenant' => 'Select tenant',
|
||||
'selected_tenant' => 'Selected tenant',
|
||||
'no_tenant_selected' => 'No tenant selected',
|
||||
'switch_tenant' => 'Switch tenant',
|
||||
'clear_tenant_scope' => 'Clear tenant scope',
|
||||
'tenant_scope' => 'Environment scope',
|
||||
'select_tenant' => 'Select environment',
|
||||
'selected_tenant' => 'Selected environment',
|
||||
'no_tenant_selected' => 'No environment selected',
|
||||
'switch_tenant' => 'Switch environment',
|
||||
'clear_tenant_scope' => 'Clear environment scope',
|
||||
'context_unavailable' => 'Context unavailable',
|
||||
'context_unavailable_workspace' => 'The requested scope could not be restored. The shell is showing a valid workspace state instead.',
|
||||
'context_unavailable_no_workspace' => 'Choose a workspace to continue with a valid admin context.',
|
||||
'no_active_environments' => 'No active environments available',
|
||||
'no_active_environments_description' => 'There are no selectable active environments for the normal operating context in this workspace. Workspace-level pages still work with no environment selected, and you can inspect onboarding or archived records through managed environments.',
|
||||
'view_managed_environments' => 'View managed environments',
|
||||
'no_active_tenants' => 'No active tenants are available for the standard operating context in this workspace.',
|
||||
'view_managed_tenants' => 'View managed tenants',
|
||||
'workspace_wide_available' => 'No tenant selected. Workspace-wide pages remain available, and choosing a tenant only sets the normal active operating context.',
|
||||
'no_active_tenants' => 'No active environments are available for the standard operating context in this workspace.',
|
||||
'view_managed_tenants' => 'View managed environments',
|
||||
'workspace_wide_available' => 'No environment selected. Workspace-wide pages remain available, and choosing an environment only sets the normal active operating context.',
|
||||
'search_environments' => 'Search environments...',
|
||||
'search_tenants' => 'Search tenants...',
|
||||
'search_tenants' => 'Search environments...',
|
||||
'choose_workspace_first' => 'Choose a workspace first.',
|
||||
],
|
||||
'workspace' => [
|
||||
@ -81,7 +81,7 @@
|
||||
'auth' => [
|
||||
'microsoft_not_configured' => 'Microsoft sign-in is not configured.',
|
||||
'sign_in_microsoft' => 'Sign in with Microsoft',
|
||||
'tenant_admin_membership_required' => 'Tenant Admin access requires a tenant membership.',
|
||||
'tenant_admin_membership_required' => 'Admin access requires an environment membership.',
|
||||
],
|
||||
'navigation' => [
|
||||
'findings' => 'Findings',
|
||||
@ -96,7 +96,7 @@
|
||||
'dashboard' => 'Dashboard',
|
||||
],
|
||||
'dashboard' => [
|
||||
'tenant_title' => 'Tenant dashboard',
|
||||
'tenant_title' => 'Environment dashboard',
|
||||
'environment_title' => 'Environment dashboard',
|
||||
'system_title' => 'System dashboard',
|
||||
'more_actions' => 'More',
|
||||
@ -139,7 +139,7 @@
|
||||
'open_external_ticket' => 'Open external ticket',
|
||||
'open_support_diagnostics' => 'Open support diagnostics',
|
||||
'support_diagnostics' => 'Support diagnostics',
|
||||
'support_diagnostics_description' => 'Redacted tenant context from existing records.',
|
||||
'support_diagnostics_description' => 'Redacted environment context from existing records.',
|
||||
'close' => 'Close',
|
||||
'time_window' => 'Time window',
|
||||
'window' => 'Window',
|
||||
@ -150,7 +150,7 @@
|
||||
'overview' => [
|
||||
'page_subheading' => 'Environment governance overview',
|
||||
'context_workspace' => 'Current workspace',
|
||||
'context_no_tenant' => 'No tenant selected',
|
||||
'context_no_tenant' => 'No environment selected',
|
||||
'context_no_environment' => 'No environment selected',
|
||||
'context_workspace_chip' => 'Workspace: :workspace',
|
||||
'context_provider_chip' => ':provider environment',
|
||||
@ -162,15 +162,15 @@
|
||||
'status_not_ready' => 'Not ready',
|
||||
'status_evidence_available' => 'Evidence available',
|
||||
'status_needs_action' => 'Needs attention',
|
||||
'tenant_context_unavailable_headline' => 'Tenant context is not available.',
|
||||
'tenant_context_unavailable_summary' => 'Select a tenant to view the decision-first dashboard overview.',
|
||||
'tenant_context_unavailable_headline' => 'Environment context is not available.',
|
||||
'tenant_context_unavailable_summary' => 'Select an environment to view the decision-first dashboard overview.',
|
||||
'environment_context_unavailable_headline' => 'Environment context is not available.',
|
||||
'environment_context_unavailable_summary' => 'Select an environment to view the decision-first dashboard overview.',
|
||||
'posture_blocked_headline' => 'Provider permissions are blocking tenant workflows.',
|
||||
'posture_blocked_headline' => 'Provider permissions are blocking environment workflows.',
|
||||
'posture_blocked_summary' => 'Required application permissions are missing, so provider-backed operations cannot be treated as healthy readiness.',
|
||||
'posture_calm_headline' => 'No immediate tenant blocker is visible.',
|
||||
'posture_calm_headline' => 'No immediate environment blocker is visible.',
|
||||
'posture_calm_summary' => 'Current findings, permissions, recovery posture, and recent operations do not show an urgent follow-up path.',
|
||||
'posture_action_needed_fallback_summary' => 'The tenant still needs operator follow-up before the landing page can stay calm.',
|
||||
'posture_action_needed_fallback_summary' => 'The environment still needs operator follow-up before the landing page can stay calm.',
|
||||
'section_recommended_actions' => 'Recommended next actions',
|
||||
'section_governance_status' => 'Governance status',
|
||||
'section_readiness' => 'Review & evidence readiness',
|
||||
@ -180,9 +180,9 @@
|
||||
'label_reason' => 'Reason',
|
||||
'label_impact' => 'Impact',
|
||||
'empty_recommended_actions_headline' => 'No immediate action is waiting.',
|
||||
'empty_recommended_actions_summary' => 'The tenant currently looks calm. Use the status and readiness sections below to confirm what is healthy and what is simply unavailable.',
|
||||
'empty_recommended_actions_summary' => 'The environment currently looks calm. Use the status and readiness sections below to confirm what is healthy and what is simply unavailable.',
|
||||
'empty_recent_operations_headline' => 'No recent operations yet.',
|
||||
'empty_recent_operations_summary' => 'Once tenant operations run, the most recent execution context will appear here without taking over the first decision layer.',
|
||||
'empty_recent_operations_summary' => 'Once environment operations run, the most recent execution context will appear here without taking over the first decision layer.',
|
||||
'kpi_high_severity_label' => 'High severity findings',
|
||||
'kpi_high_severity_description' => 'High or critical findings still needing review.',
|
||||
'kpi_high_severity_tendency' => ':count active now',
|
||||
@ -193,13 +193,13 @@
|
||||
'kpi_overdue_tendency' => ':count overdue now',
|
||||
'kpi_overdue_tendency_none' => 'None overdue',
|
||||
'kpi_missing_permissions_label' => 'Missing permissions',
|
||||
'kpi_missing_permissions_description' => 'Provider-required permissions currently missing for this tenant.',
|
||||
'kpi_missing_permissions_description' => 'Provider-required permissions currently missing for this environment.',
|
||||
'kpi_missing_permissions_tendency_split' => ':app app · :delegated delegated missing',
|
||||
'kpi_missing_permissions_tendency_app_only' => ':count app missing',
|
||||
'kpi_missing_permissions_tendency_delegated_only' => ':count delegated missing',
|
||||
'kpi_missing_permissions_tendency_none' => 'Permission set complete',
|
||||
'kpi_active_operations_label' => 'Operations needing attention',
|
||||
'kpi_active_operations_description' => 'Operation runs that still need follow-up before the tenant can be treated as healthy.',
|
||||
'kpi_active_operations_description' => 'Operation runs that still need follow-up before the environment can be treated as healthy.',
|
||||
'kpi_active_operations_tendency' => ':count operations require attention',
|
||||
'kpi_active_operations_tendency_window' => ':count operations require attention',
|
||||
'kpi_active_operations_tendency_one' => '1 operation needs follow-up',
|
||||
@ -230,18 +230,18 @@
|
||||
'reason_missing_application_permissions' => ':count application permission(s) are still missing.',
|
||||
'impact_missing_application_permissions' => 'Provider-backed inventory, verification, and reporting flows stay blocked until consent is restored.',
|
||||
'reason_missing_delegated_permissions' => ':count delegated permission(s) still need attention.',
|
||||
'impact_missing_delegated_permissions' => 'The tenant stays partially ready until delegated permissions are reviewed and granted where needed.',
|
||||
'impact_missing_delegated_permissions' => 'The environment stays partially ready until delegated permissions are reviewed and granted where needed.',
|
||||
'reason_high_severity_findings' => ':count high severity finding(s) still need operator review.',
|
||||
'impact_high_severity_findings' => 'Severe drift stays unresolved until those findings are triaged or remediated.',
|
||||
'reason_overdue_findings' => ':count finding(s) are already overdue.',
|
||||
'impact_overdue_findings' => 'Workflow delay can hide the tenant\'s current risk posture until overdue items are cleared.',
|
||||
'impact_overdue_findings' => 'Workflow delay can hide the environment\'s current risk posture until overdue items are cleared.',
|
||||
'reason_risk_exceptions' => ':count risk exception(s) or accepted-risk governance item(s) need follow-up.',
|
||||
'impact_risk_exceptions' => 'Accepted-risk statements stop being trustworthy when their exception history is no longer current.',
|
||||
'impact_recovery_posture' => 'Recovery readiness should be checked before customer-safe claims rely on backup or restore confidence.',
|
||||
'reason_terminal_operations' => ':count operation run(s) finished blocked, partial, or failed.',
|
||||
'impact_terminal_operations' => 'Terminal run outcomes need follow-up before the tenant can be treated as calm.',
|
||||
'impact_terminal_operations' => 'Terminal run outcomes need follow-up before the environment can be treated as calm.',
|
||||
'reason_operations_requiring_attention' => 'One or more operations finished with an outcome that needs follow-up.',
|
||||
'impact_operations_requiring_attention' => 'The tenant should not be treated as fully healthy until the operation outcome has been reviewed.',
|
||||
'impact_operations_requiring_attention' => 'The environment should not be treated as fully healthy until the operation outcome has been reviewed.',
|
||||
'reason_continue_review' => 'Customer-safe output is not fully ready yet.',
|
||||
'impact_continue_review' => 'Review output stays partial until the review, evidence, and pack surfaces line up cleanly.',
|
||||
'operations_attention_title' => 'Operations requiring attention',
|
||||
@ -253,16 +253,16 @@
|
||||
'operations_attention_outcome_generic' => 'The operation finished with an outcome that needs follow-up.',
|
||||
'operations_attention_outcome_stale' => 'The operation is still active, but it is past its expected lifecycle window.',
|
||||
'operations_attention_outcome_provider_consent_required' => 'The check finished, but provider consent is still required.',
|
||||
'operations_attention_reason_fallback' => 'The recorded outcome still needs operator review before the tenant can be treated as healthy.',
|
||||
'operations_attention_reason_fallback' => 'The recorded outcome still needs operator review before the environment can be treated as healthy.',
|
||||
'operations_attention_reason_stale' => 'The run is past its normal lifecycle window and may no longer be progressing.',
|
||||
'operations_attention_reason_provider_consent_required' => 'Admin consent is required before the provider connection can be used.',
|
||||
'operations_attention_impact_follow_up' => 'Tenant readiness should not be treated as fully healthy until the operation outcome has been reviewed.',
|
||||
'operations_attention_impact_stale' => 'Tenant readiness should not be treated as current until the stalled run has been reviewed.',
|
||||
'operations_attention_impact_provider_consent_required' => 'Tenant readiness cannot be treated as healthy until this is reviewed.',
|
||||
'operations_attention_impact_follow_up' => 'Environment readiness should not be treated as fully healthy until the operation outcome has been reviewed.',
|
||||
'operations_attention_impact_stale' => 'Environment readiness should not be treated as current until the stalled run has been reviewed.',
|
||||
'operations_attention_impact_provider_consent_required' => 'Environment readiness cannot be treated as healthy until this is reviewed.',
|
||||
'operations_attention_timing_completed' => 'Completed :time',
|
||||
'operations_attention_timing_started' => 'Started :time',
|
||||
'governance_baseline_compare_label' => 'Baseline compare',
|
||||
'governance_baseline_compare_description' => 'Current compare posture for the tenant baseline.',
|
||||
'governance_baseline_compare_description' => 'Current compare posture for the environment baseline.',
|
||||
'governance_evidence_coverage_label' => 'Evidence coverage',
|
||||
'governance_review_freshness_label' => 'Review freshness',
|
||||
'governance_provider_permissions_label' => 'Provider permissions',
|
||||
@ -270,7 +270,7 @@
|
||||
'governance_backup_posture_unavailable_description' => 'Recovery readiness is not yet available.',
|
||||
'readiness_current_review_title' => 'Current review',
|
||||
'readiness_current_review_empty_status' => 'No active review',
|
||||
'readiness_current_review_empty_description' => 'There is currently no review in progress for this tenant.',
|
||||
'readiness_current_review_empty_description' => 'There is currently no review in progress for this environment.',
|
||||
'readiness_current_review_updated_label' => 'Last updated',
|
||||
'readiness_current_review_findings_progress_label' => 'Findings with outcome',
|
||||
'readiness_current_review_completion_progress_label' => 'Review completion',
|
||||
@ -285,16 +285,16 @@
|
||||
'readiness_risk_exceptions_pending_label' => 'Pending approval',
|
||||
'readiness_provider_health_title' => 'Provider Health',
|
||||
'readiness_provider_health_empty_status' => 'Provider status unavailable',
|
||||
'readiness_provider_health_empty_description' => 'No provider health snapshot is currently available for this tenant.',
|
||||
'readiness_provider_health_empty_description' => 'No provider health snapshot is currently available for this environment.',
|
||||
'readiness_provider_health_last_check_label' => 'Last check',
|
||||
'readiness_provider_health_permissions_label' => 'Missing permissions',
|
||||
'readiness_provider_health_snapshot_label' => 'Permissions snapshot',
|
||||
'readiness_provider_health_degraded_description' => 'The latest provider health check reported warnings for this tenant.',
|
||||
'readiness_provider_health_blocked_description' => 'The provider health check is currently blocked for this tenant.',
|
||||
'readiness_provider_health_error_description' => 'The provider health check failed for this tenant.',
|
||||
'readiness_provider_health_pending_description' => 'The latest provider health check is still pending.',
|
||||
'readiness_provider_health_degraded_description' => 'The latest provider health check reported warnings for this environment.',
|
||||
'readiness_provider_health_blocked_description' => 'The provider health check is currently blocked for this environment.',
|
||||
'readiness_provider_health_error_description' => 'The provider health check failed for this environment.',
|
||||
'readiness_provider_health_pending_description' => 'The latest provider health check is still pending for this environment.',
|
||||
'readiness_provider_health_unknown_description' => 'No provider health check has been recorded yet.',
|
||||
'helper_findings_requires_permissions' => 'You can see the tenant posture, but opening findings requires additional permissions.',
|
||||
'helper_findings_requires_permissions' => 'You can see the environment posture, but opening findings requires additional permissions.',
|
||||
'helper_risk_exceptions_requires_permissions' => 'You can see the summary, but opening risk exceptions requires additional permissions.',
|
||||
'helper_review_requires_permissions' => 'You can see the summary, but opening review detail requires additional permissions.',
|
||||
'helper_continue_review_requires_manage' => 'You can inspect the current review state, but only review managers can continue the review workflow.',
|
||||
@ -306,7 +306,7 @@
|
||||
'helper_backup_posture_requires_permissions' => 'You can see the summary, but opening backup posture detail requires additional permissions.',
|
||||
'evidence_unavailable_description' => 'No evidence snapshot is currently available for customer-safe output.',
|
||||
'evidence_generated_prefix' => 'Latest evidence snapshot generated :time.',
|
||||
'review_unavailable_description' => 'No tenant review is currently available for this tenant.',
|
||||
'review_unavailable_description' => 'No review is currently available for this environment.',
|
||||
'review_updated_prefix' => 'Latest review updated :time.',
|
||||
'provider_permissions_ready' => 'Ready',
|
||||
'provider_permissions_blocked' => 'Blocked',
|
||||
@ -321,7 +321,7 @@
|
||||
'risk_exceptions_pending_description' => 'Pending, expiring, or expired exceptions still need governance follow-up.',
|
||||
'risk_exceptions_active_description' => 'Accepted-risk exceptions exist but do not currently need urgent review.',
|
||||
'risk_exceptions_calm_description' => 'No risk exceptions currently need attention.',
|
||||
'recent_operation_fallback_summary' => 'Recent operation context for this tenant.',
|
||||
'recent_operation_fallback_summary' => 'Recent operation context for this environment.',
|
||||
],
|
||||
],
|
||||
'review' => [
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
|
||||
<x-filament::section heading="Reference overview">
|
||||
<x-slot name="description">
|
||||
Compare assigned tenants remains simulation only. This operator view changes presentation density, not compare truth, visible-set scope, or the existing drilldown path.
|
||||
Compare assigned environments remains simulation only. This operator view changes presentation density, not compare truth, visible-set scope, or the existing drilldown path.
|
||||
</x-slot>
|
||||
|
||||
<div class="space-y-4">
|
||||
@ -86,15 +86,15 @@
|
||||
</h2>
|
||||
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300">
|
||||
Assigned tenants: {{ (int) ($reference['assignedTenantCount'] ?? 0) }}.
|
||||
Visible tenants: {{ $visibleTenantCount }}.
|
||||
Assigned environments: {{ (int) ($reference['assignedTenantCount'] ?? 0) }}.
|
||||
Visible environments: {{ $visibleTenantCount }}.
|
||||
@if (filled($reference['referenceSnapshotCapturedAt'] ?? null))
|
||||
Reference captured {{ \Illuminate\Support\Carbon::parse($reference['referenceSnapshotCapturedAt'])->diffForHumans() }}.
|
||||
@endif
|
||||
</p>
|
||||
|
||||
<p class="text-sm text-gray-600 dark:text-gray-300">
|
||||
Auto mode resolves from the visible tenant set. Manual mode stays local to this route and never becomes stored preference truth.
|
||||
Auto mode resolves from the visible environment set. Manual mode stays local to this route and never becomes stored preference truth.
|
||||
</p>
|
||||
|
||||
@if (filled($reference['referenceReasonCode'] ?? null))
|
||||
@ -107,7 +107,7 @@
|
||||
|
||||
<dl class="grid gap-3 sm:grid-cols-2 xl:w-[28rem]">
|
||||
<div class="rounded-2xl border border-gray-200 bg-white px-4 py-3 shadow-sm dark:border-gray-800 dark:bg-gray-900/70">
|
||||
<dt class="text-[11px] font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Visible tenants</dt>
|
||||
<dt class="text-[11px] font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Visible environments</dt>
|
||||
<dd class="mt-1 text-3xl font-semibold text-gray-950 dark:text-white">
|
||||
{{ $visibleTenantCount }}
|
||||
</dd>
|
||||
@ -165,7 +165,7 @@
|
||||
</x-filament::button>
|
||||
@else
|
||||
<x-filament::badge color="gray" size="sm">
|
||||
Compact unlocks at one visible tenant
|
||||
Compact unlocks at one visible environment
|
||||
</x-filament::badge>
|
||||
@endif
|
||||
</div>
|
||||
@ -201,7 +201,7 @@
|
||||
|
||||
@if ($hiddenAssignedTenantCount > 0)
|
||||
<span class="text-xs text-gray-500 dark:text-gray-400">
|
||||
Visible-set only. Hidden tenants never contribute to summaries or drilldowns.
|
||||
Visible-set only. Hidden environments never contribute to summaries or drilldowns.
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@ -223,7 +223,7 @@
|
||||
<div class="text-sm font-semibold text-gray-950 dark:text-white">Applied matrix scope</div>
|
||||
<p class="text-sm leading-6 text-gray-600 dark:text-gray-300">
|
||||
@if ($activeFilterCount === 0)
|
||||
No narrowing filters are active. Showing every visible subject and tenant in the current baseline scope.
|
||||
No narrowing filters are active. Showing every visible subject and environment in the current baseline scope.
|
||||
@else
|
||||
{{ $activeFilterCount }} active {{ \Illuminate\Support\Str::plural('filter', $activeFilterCount) }} are already shaping the rendered matrix.
|
||||
@endif
|
||||
@ -250,7 +250,7 @@
|
||||
</x-filament::badge>
|
||||
|
||||
<x-filament::badge color="gray" size="sm">
|
||||
ManagedEnvironment sort: {{ $tenantSortOptions[$currentFilters['tenant_sort'] ?? 'tenant_name'] ?? 'ManagedEnvironment name' }}
|
||||
Environment sort: {{ $tenantSortOptions[$currentFilters['tenant_sort'] ?? 'tenant_name'] ?? 'Environment name' }}
|
||||
</x-filament::badge>
|
||||
|
||||
<x-filament::badge color="gray" size="sm">
|
||||
@ -337,8 +337,8 @@
|
||||
<div class="rounded-2xl border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-800 dark:bg-gray-900/70">
|
||||
<div class="text-sm font-semibold text-gray-950 dark:text-white">Current scope</div>
|
||||
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
|
||||
{{ $visibleTenantCount }} visible {{ \Illuminate\Support\Str::plural('tenant', $visibleTenantCount) }}.
|
||||
{{ $resolvedMode === 'dense' ? 'State-first dense scan stays active.' : 'Compact single-tenant review stays active.' }}
|
||||
{{ $visibleTenantCount }} visible {{ \Illuminate\Support\Str::plural('environment', $visibleTenantCount) }}.
|
||||
{{ $resolvedMode === 'dense' ? 'State-first dense scan stays active.' : 'Compact single-environment review stays active.' }}
|
||||
</p>
|
||||
|
||||
@if ($policyTypeOptions !== [])
|
||||
@ -454,7 +454,7 @@
|
||||
|
||||
<x-filament::section heading="Compact compare results">
|
||||
<x-slot name="description">
|
||||
One visible tenant remains in scope, so the matrix collapses into a shorter subject-result list instead of a pseudo-grid.
|
||||
One visible environment remains in scope, so the matrix collapses into a shorter subject-result list instead of a pseudo-grid.
|
||||
</x-slot>
|
||||
|
||||
@if ($compactTenant)
|
||||
@ -568,7 +568,7 @@
|
||||
<div class="flex flex-wrap gap-3 text-sm">
|
||||
@if ($primaryUrl)
|
||||
<x-filament::link :href="$primaryUrl" size="sm">
|
||||
{{ filled($result['findingId'] ?? null) ? 'Open finding' : 'Open tenant compare' }}
|
||||
{{ filled($result['findingId'] ?? null) ? 'Open finding' : 'Open environment compare' }}
|
||||
</x-filament::link>
|
||||
@endif
|
||||
|
||||
@ -591,7 +591,7 @@
|
||||
</div>
|
||||
</x-filament::section>
|
||||
@else
|
||||
<x-filament::section heading="Dense multi-tenant scan">
|
||||
<x-filament::section heading="Dense multi-environment scan">
|
||||
<x-slot name="description">
|
||||
The matrix body is state-first. Row click stays forbidden, the subject column stays pinned, and repeated follow-up actions move behind compact secondary reveals.
|
||||
</x-slot>
|
||||
@ -649,7 +649,7 @@
|
||||
<div class="flex flex-wrap gap-3 text-sm">
|
||||
@if ($tenantCompareUrl)
|
||||
<x-filament::link :href="$tenantCompareUrl" size="sm">
|
||||
Open tenant compare
|
||||
Open environment compare
|
||||
</x-filament::link>
|
||||
@endif
|
||||
|
||||
@ -830,7 +830,7 @@
|
||||
@if ($primaryUrl)
|
||||
<div class="text-sm">
|
||||
<x-filament::link :href="$primaryUrl" size="sm">
|
||||
{{ filled($cell['findingId'] ?? null) ? 'Open finding' : 'Open tenant compare' }}
|
||||
{{ filled($cell['findingId'] ?? null) ? 'Open finding' : 'Open environment compare' }}
|
||||
</x-filament::link>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
{{ $summary['visible_unassigned'] }}
|
||||
</div>
|
||||
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">
|
||||
Visible unassigned intake rows after the current tenant scope.
|
||||
Visible unassigned intake rows after the current environment scope.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -57,10 +57,10 @@ class="inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-sm fo
|
||||
|
||||
@if ($this->hasTenantPrefilter())
|
||||
<div class="flex flex-wrap items-center gap-3 text-sm text-gray-600 dark:text-gray-300">
|
||||
<span>The register is currently filtered to one tenant.</span>
|
||||
<span>The register is currently filtered to one environment.</span>
|
||||
|
||||
<a href="{{ $this->pageUrl(['tenant' => null]) }}" class="font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400 dark:hover:text-primary-300">
|
||||
Clear tenant filter
|
||||
Clear environment filter
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
@ -68,4 +68,4 @@ class="inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-sm fo
|
||||
</x-filament::section>
|
||||
|
||||
{{ $this->table }}
|
||||
</x-filament-panels::page>
|
||||
</x-filament-panels::page>
|
||||
|
||||
@ -66,10 +66,10 @@ class="inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-sm fo
|
||||
|
||||
@if ($this->hasTenantPrefilter())
|
||||
<div class="flex flex-wrap items-center gap-3 text-sm text-gray-600 dark:text-gray-300">
|
||||
<span>The inbox is currently filtered to one tenant.</span>
|
||||
<span>The inbox is currently filtered to one environment.</span>
|
||||
|
||||
<a href="{{ $this->pageUrl(['tenant' => null]) }}" class="font-medium text-primary-600 hover:text-primary-500 dark:text-primary-400 dark:hover:text-primary-300">
|
||||
Clear tenant filter
|
||||
Clear environment filter
|
||||
</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
|
||||
<div class="text-sm text-gray-600 dark:text-gray-300">
|
||||
Review pending requests, expiring governance, and lapsed exception coverage across entitled tenants without leaving the Monitoring area.
|
||||
Review pending requests, expiring governance, and lapsed exception coverage across entitled environments without leaving the Monitoring area.
|
||||
</div>
|
||||
|
||||
<div class="text-sm text-gray-600 dark:text-gray-300">
|
||||
@ -48,7 +48,7 @@
|
||||
Related drilldown
|
||||
</div>
|
||||
<div class="mt-2 text-sm text-gray-600 dark:text-gray-300">
|
||||
Open tenant detail and Open finding stay available for context, but they no longer share the same semantic lane as the review decision.
|
||||
Open environment detail and Open finding stay available for context, but they no longer share the same semantic lane as the review decision.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -57,7 +57,7 @@
|
||||
@else
|
||||
<x-filament::section heading="Quiet monitoring mode">
|
||||
<x-slot name="description">
|
||||
Inspect an exception to enter the focused review lane. Scope, filters, and tenant drilldowns stay secondary until one request is actively under review.
|
||||
Inspect an exception to enter the focused review lane. Scope, filters, and environment drilldowns stay secondary until one request is actively under review.
|
||||
</x-slot>
|
||||
|
||||
<div class="text-sm text-gray-600 dark:text-gray-300">
|
||||
|
||||
@ -103,7 +103,7 @@
|
||||
<div class="flex flex-wrap items-start justify-between gap-4">
|
||||
<div class="space-y-1">
|
||||
<div class="text-sm text-gray-600 dark:text-gray-300">
|
||||
Review what’s missing for this tenant and copy the missing permissions for admin consent.
|
||||
Review what’s missing for this environment and copy the missing permissions for admin consent.
|
||||
</div>
|
||||
<div class="text-xs text-gray-500 dark:text-gray-400">
|
||||
Stored-data view only. Last refreshed: {{ $lastRefreshedLabel }}{{ $isStale ? ' (stale)' : '' }}.
|
||||
@ -140,7 +140,7 @@
|
||||
<div class="rounded-xl border border-warning-200 bg-warning-50 p-4 text-sm text-warning-800 dark:border-warning-800 dark:bg-warning-950/30 dark:text-warning-200">
|
||||
<div class="font-semibold">No data available</div>
|
||||
<div class="mt-1">
|
||||
No stored verification data is available for this tenant.
|
||||
No stored verification data is available for this environment.
|
||||
<a href="{{ $reRunUrl }}" class="font-medium underline">Start verification</a>.
|
||||
</div>
|
||||
</div>
|
||||
@ -512,7 +512,7 @@ class="group rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800
|
||||
<div class="mt-4">
|
||||
@if (! $tenant)
|
||||
<div class="text-sm text-gray-600 dark:text-gray-300">
|
||||
No tenant selected.
|
||||
No environment selected.
|
||||
</div>
|
||||
@else
|
||||
<div class="space-y-6">
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
$page
|
||||
->assertNoJavaScriptErrors()
|
||||
->waitForText('Requested: Auto mode. Resolved: Dense mode.')
|
||||
->assertSee('Dense multi-tenant scan')
|
||||
->assertSee('Dense multi-environment scan')
|
||||
->assertSee('Applied filters and the focused subject are carried by the URL so the current matrix scan can be reopened or shared.')
|
||||
->assertSee('Grouped legend')
|
||||
->assertSee('Open finding')
|
||||
@ -146,7 +146,7 @@
|
||||
->assertSee('Passive auto-refresh every 5 seconds')
|
||||
->assertSee('Applied filters and the focused subject are carried by the URL so the current matrix scan can be reopened or shared.')
|
||||
->click('Reset filters')
|
||||
->waitForText('Dense multi-tenant scan')
|
||||
->waitForText('Dense multi-environment scan')
|
||||
->assertSee('Requested: Dense mode. Resolved: Dense mode.')
|
||||
->assertNoJavaScriptErrors();
|
||||
});
|
||||
|
||||
@ -10,11 +10,11 @@
|
||||
use App\Models\OperationRun;
|
||||
use App\Support\Baselines\BaselineCompareStats;
|
||||
|
||||
it('returns no_tenant state when tenant is null', function (): void {
|
||||
it('returns no_tenant state when environment is null', function (): void {
|
||||
$stats = BaselineCompareStats::forTenant(null);
|
||||
|
||||
expect($stats->state)->toBe('no_tenant')
|
||||
->and($stats->message)->toContain('No tenant');
|
||||
->and($stats->message)->toContain('No environment');
|
||||
});
|
||||
|
||||
it('returns no_assignment state when tenant has no baseline assignment', function (): void {
|
||||
|
||||
@ -56,8 +56,8 @@
|
||||
->assertDontSee('Passive auto-refresh every 5 seconds')
|
||||
->assertSee('Grouped legend')
|
||||
->assertSee('Apply filters')
|
||||
->assertSee('Compact unlocks at one visible tenant')
|
||||
->assertSee('Dense multi-tenant scan')
|
||||
->assertSee('Compact unlocks at one visible environment')
|
||||
->assertSee('Dense multi-environment scan')
|
||||
->assertSee('Open finding')
|
||||
->assertSee('More follow-up')
|
||||
->assertSee('data-testid="baseline-compare-matrix-dense-shell"', false)
|
||||
@ -248,10 +248,10 @@
|
||||
->test(BaselineCompareMatrix::class, ['record' => $fixture['profile']->getKey()])
|
||||
->assertActionVisible('compareAssignedTenants')
|
||||
->assertActionDisabled('compareAssignedTenants')
|
||||
->assertActionExists('compareAssignedTenants', fn (Action $action): bool => $action->getTooltip() === 'The selected governed subjects span multiple compare strategy families and must be narrowed before comparing assigned tenants.');
|
||||
->assertActionExists('compareAssignedTenants', fn (Action $action): bool => $action->getTooltip() === 'The selected governed subjects span multiple compare strategy families and must be narrowed before comparing assigned environments.');
|
||||
});
|
||||
|
||||
it('renders an empty state when the baseline profile has no assigned tenants', function (): void {
|
||||
it('renders an empty state when the baseline profile has no assigned environments', function (): void {
|
||||
$fixture = $this->makeBaselineCompareMatrixFixture();
|
||||
|
||||
$fixture['profile']->tenantAssignments()->delete();
|
||||
@ -261,7 +261,7 @@
|
||||
$this->withSession($session)
|
||||
->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
|
||||
->assertOk()
|
||||
->assertSee('No assigned tenants');
|
||||
->assertSee('No assigned environments');
|
||||
});
|
||||
|
||||
it('renders an empty state when the assigned set is not visible to the current actor', function (): void {
|
||||
@ -280,7 +280,7 @@
|
||||
$this->withSession($session)
|
||||
->get(BaselineProfileResource::compareMatrixUrl($fixture['profile']))
|
||||
->assertOk()
|
||||
->assertSee('No visible assigned tenants');
|
||||
->assertSee('No visible assigned environments');
|
||||
});
|
||||
|
||||
it('renders a passive auto-refresh cue instead of a perpetual blocking state while compare runs remain active', function (): void {
|
||||
|
||||
@ -181,7 +181,7 @@ function seedComparableBaselineProfileForTenant(ManagedEnvironment $tenant, Base
|
||||
|
||||
$component = Livewire::actingAs($user)
|
||||
->test(ViewBaselineProfile::class, ['record' => $profile->getKey()])
|
||||
->assertActionExists('compareAssignedTenants', fn (Action $action): bool => $action->getLabel() === 'Compare assigned tenants'
|
||||
->assertActionExists('compareAssignedTenants', fn (Action $action): bool => $action->getLabel() === 'Compare assigned environments'
|
||||
&& $action->isConfirmationRequired()
|
||||
&& str_contains((string) $action->getModalDescription(), 'Simulation only.'));
|
||||
|
||||
|
||||
@ -94,7 +94,7 @@
|
||||
Livewire::actingAs($user)
|
||||
->test(ListBaselineProfiles::class)
|
||||
->assertTableColumnExists('tenant_assignments_count', function (TextColumn $column): bool {
|
||||
return $column->getLabel() === 'Assigned tenants'
|
||||
return $column->getLabel() === 'Assigned environments'
|
||||
&& (int) $column->getState() === 2;
|
||||
}, $assignedProfile)
|
||||
->assertTableColumnExists('tenant_assignments_count', function (TextColumn $column): bool {
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
->assertSee('Snapshot #'.$latestAttempt->getKey().' (Incomplete)')
|
||||
->assertSee('Compare readiness')
|
||||
->assertSee('No eligible compare target')
|
||||
->assertSee('Assign this baseline to a tenant you can compare, or use an account with access to an assigned tenant.');
|
||||
->assertSee('Assign this baseline to an environment you can compare, or use an account with access to an assigned environment.');
|
||||
});
|
||||
|
||||
it('shows compare readiness as ready when a consumable snapshot and eligible target tenant exist', function (): void {
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
it('resolves first-wave governance labels from the active locale', function (): void {
|
||||
App::setLocale('de');
|
||||
|
||||
expect(__('localization.dashboard.tenant_title'))->toBe('Tenant-Dashboard')
|
||||
expect(__('localization.dashboard.tenant_title'))->toBe('Umgebungs-Dashboard')
|
||||
->and(FindingResource::getNavigationGroup())->toBe('Governance')
|
||||
->and(__('localization.findings.needs_action'))->toBe('Handlungsbedarf')
|
||||
->and(__('baseline-compare.stat_total_findings'))->toBe('Findings gesamt')
|
||||
|
||||
@ -45,8 +45,8 @@
|
||||
->assertSee('Open alerts')
|
||||
->assertSee('Review current and recent workspace-wide operations.')
|
||||
->assertSee('Activity only. Active execution does not imply governance health.')
|
||||
->assertSee('Visible tenants with non-healthy backup posture.')
|
||||
->assertSee('Visible tenants with weakened or unvalidated recovery evidence.')
|
||||
->assertSee('Visible environments with non-healthy backup posture.')
|
||||
->assertSee('Visible environments with weakened or unvalidated recovery evidence.')
|
||||
->assertSee('Governance risk counts affected tenants')
|
||||
->assertSee('Backup health stays separate from recovery evidence')
|
||||
->assertSee('Calm wording stays bounded to visible tenants and checked domains')
|
||||
|
||||
@ -381,7 +381,7 @@ function recordFindingsHygieneAudit(Finding $finding, string $action, CarbonImmu
|
||||
$component = findingsHygienePage($user)
|
||||
->assertSet('tableFilters.managed_environment_id.value', (string) $tenantB->getKey())
|
||||
->assertCanNotSeeTableRecords([$tenantAIssue])
|
||||
->assertSee('No hygiene issues match this tenant scope')
|
||||
->assertSee('No hygiene issues match this environment scope')
|
||||
->assertActionVisible('clear_tenant_filter');
|
||||
|
||||
$component->callAction('clear_tenant_filter')
|
||||
|
||||
@ -336,7 +336,7 @@ function makeIntakeFinding(ManagedEnvironment $tenant, array $attributes = []):
|
||||
findingsIntakePage($user, [
|
||||
'tenant' => (string) $tenantA->external_id,
|
||||
])
|
||||
->assertSee('No intake findings match this tenant scope')
|
||||
->assertSee('No intake findings match this environment scope')
|
||||
->assertTableEmptyStateActionsExistInOrder(['clear_tenant_filter_empty']);
|
||||
|
||||
Finding::query()->delete();
|
||||
|
||||
@ -122,7 +122,7 @@ function makeAssignedFindingForInbox(ManagedEnvironment $tenant, User $assignee,
|
||||
],
|
||||
[
|
||||
'key' => 'tenant',
|
||||
'label' => 'ManagedEnvironment',
|
||||
'label' => 'Managed environment',
|
||||
'fixed' => false,
|
||||
'options' => [
|
||||
['value' => (string) $tenantA->getKey(), 'label' => 'Alpha ManagedEnvironment'],
|
||||
@ -150,7 +150,7 @@ function makeAssignedFindingForInbox(ManagedEnvironment $tenant, User $assignee,
|
||||
]);
|
||||
});
|
||||
|
||||
it('defaults to the active tenant prefilter and lets the operator clear it without dropping personal scope', function (): void {
|
||||
it('defaults to the active environment prefilter and lets the operator clear it without dropping personal scope', function (): void {
|
||||
[$user, $tenantA] = myWorkInboxActingUser();
|
||||
|
||||
$tenantB = ManagedEnvironment::factory()->create([
|
||||
@ -268,7 +268,7 @@ function makeAssignedFindingForInbox(ManagedEnvironment $tenant, User $assignee,
|
||||
->assertCanNotSeeTableRecords([$ordinary]);
|
||||
});
|
||||
|
||||
it('renders the tenant-prefilter empty-state branch and offers only a clear-filter recovery action', function (): void {
|
||||
it('renders the environment-prefilter empty-state branch and offers only a clear-filter recovery action', function (): void {
|
||||
[$user, $tenantA] = myWorkInboxActingUser();
|
||||
|
||||
$tenantB = ManagedEnvironment::factory()->create([
|
||||
@ -286,7 +286,7 @@ function makeAssignedFindingForInbox(ManagedEnvironment $tenant, User $assignee,
|
||||
'tenant' => (string) $tenantA->external_id,
|
||||
])
|
||||
->assertCanNotSeeTableRecords([])
|
||||
->assertSee('No assigned findings match this tenant scope')
|
||||
->assertSee('No assigned findings match this environment scope')
|
||||
->assertTableEmptyStateActionsExistInOrder(['clear_tenant_filter_empty']);
|
||||
|
||||
expect($component->instance()->summaryCounts())->toBe([
|
||||
@ -295,7 +295,7 @@ function makeAssignedFindingForInbox(ManagedEnvironment $tenant, User $assignee,
|
||||
]);
|
||||
});
|
||||
|
||||
it('renders the calm zero-work branch and points back to tenant selection when no active tenant context exists', function (): void {
|
||||
it('renders the calm zero-work branch and points back to environment selection when no active environment context exists', function (): void {
|
||||
[$user, $tenant] = myWorkInboxActingUser();
|
||||
|
||||
session()->forget(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY);
|
||||
@ -306,7 +306,7 @@ function makeAssignedFindingForInbox(ManagedEnvironment $tenant, User $assignee,
|
||||
->assertTableEmptyStateActionsExistInOrder(['choose_tenant_empty']);
|
||||
});
|
||||
|
||||
it('uses the active visible tenant for the calm empty-state drillback when tenant context exists', function (): void {
|
||||
it('uses the active visible environment for the calm empty-state drillback when environment context exists', function (): void {
|
||||
[$user, $tenant] = myWorkInboxActingUser();
|
||||
|
||||
session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [
|
||||
@ -319,13 +319,13 @@ function makeAssignedFindingForInbox(ManagedEnvironment $tenant, User $assignee,
|
||||
|
||||
expect($component->instance()->emptyState())->toMatchArray([
|
||||
'action_name' => 'open_tenant_findings_empty',
|
||||
'action_label' => 'Open tenant findings',
|
||||
'action_label' => 'Open environment findings',
|
||||
'action_kind' => 'url',
|
||||
'action_url' => FindingResource::getUrl('index', panel: 'admin', tenant: $tenant),
|
||||
]);
|
||||
});
|
||||
|
||||
it('builds tenant detail drilldowns with inbox continuity', function (): void {
|
||||
it('builds environment detail drilldowns with inbox continuity', function (): void {
|
||||
[$user, $tenant] = myWorkInboxActingUser();
|
||||
|
||||
$finding = makeAssignedFindingForInbox($tenant, $user, [
|
||||
|
||||
@ -120,8 +120,8 @@
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $alphaTenant->workspace_id])
|
||||
->get(DecisionRegister::getUrl(panel: 'admin').'?managed_environment_id='.(string) $alphaTenant->getKey())
|
||||
->assertOk()
|
||||
->assertSee('This tenant filter is hiding other visible decision follow-through')
|
||||
->assertSee('Clear tenant filter');
|
||||
->assertSee('This environment filter is hiding other visible decision follow-through')
|
||||
->assertSee('Clear environment filter');
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $alphaTenant->workspace_id])
|
||||
@ -175,4 +175,4 @@ function decisionRegisterPageException(
|
||||
$exception->forceFill(['current_decision_id' => (int) $decision->getKey()])->save();
|
||||
|
||||
return $exception->fresh(['currentDecision']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,15 +155,15 @@
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $alphaTenant->workspace_id])
|
||||
->get(GovernanceInbox::getUrl(panel: 'admin').'?managed_environment_id='.(string) $alphaTenant->getKey())
|
||||
->assertOk()
|
||||
->assertSee('This tenant filter is hiding other visible attention')
|
||||
->assertSee('Clear tenant filter');
|
||||
->assertSee('This environment filter is hiding other visible attention')
|
||||
->assertSee('Clear environment filter');
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $alphaTenant->workspace_id])
|
||||
->get(GovernanceInbox::getUrl(panel: 'admin').'?managed_environment_id='.(string) $alphaTenant->getKey().'&family=alert_delivery_failures')
|
||||
->assertOk()
|
||||
->assertSee('Alert delivery failures')
|
||||
->assertSee('No failed alert deliveries match this tenant filter right now.')
|
||||
->assertSee('No failed alert deliveries match this environment filter right now.')
|
||||
->assertDontSee('Open my findings');
|
||||
});
|
||||
|
||||
|
||||
@ -46,20 +46,83 @@
|
||||
'all entitled tenants',
|
||||
'tenant-specific context',
|
||||
],
|
||||
'apps/platform/app/Filament/Pages/Monitoring/FindingExceptionsQueue.php' => [
|
||||
'View tenant register',
|
||||
'Open tenant detail',
|
||||
],
|
||||
'apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php' => [
|
||||
'Clear tenant filter',
|
||||
'No assigned findings match this tenant scope',
|
||||
'Open tenant findings',
|
||||
'Choose a tenant',
|
||||
],
|
||||
'apps/platform/app/Filament/Resources/BackupScheduleResource.php' => [
|
||||
'No tenant selected',
|
||||
],
|
||||
'apps/platform/app/Filament/Resources/BaselineProfileResource/RelationManagers/BaselineTenantAssignmentsRelationManager.php' => [
|
||||
'Remove tenant assignment',
|
||||
'No tenants assigned',
|
||||
],
|
||||
'apps/platform/resources/views/filament/pages/baseline-compare-landing.blade.php' => [
|
||||
'tenant landing',
|
||||
],
|
||||
'apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php' => [
|
||||
'Open tenant compare',
|
||||
'Visible tenants',
|
||||
'Assigned tenants',
|
||||
'Compact unlocks at one visible tenant',
|
||||
'Dense multi-tenant scan',
|
||||
'No assigned tenants',
|
||||
'No visible assigned tenants',
|
||||
],
|
||||
'apps/platform/app/Filament/Pages/BaselineCompareMatrix.php' => [
|
||||
'Compare assigned tenants',
|
||||
'tenant-owned baseline compare',
|
||||
'comparing assigned tenants',
|
||||
'No visible assigned tenants',
|
||||
'visible tenant before compare',
|
||||
],
|
||||
'apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/ViewBaselineProfile.php' => [
|
||||
'Compare assigned tenants',
|
||||
'tenant-owned baseline compare',
|
||||
'comparing assigned tenants',
|
||||
'No visible assigned tenants',
|
||||
],
|
||||
'apps/platform/app/Support/ReasonTranslation/ReasonTranslator.php' => [
|
||||
'assigned tenant with compare',
|
||||
'access to an assigned tenant',
|
||||
],
|
||||
'apps/platform/resources/views/filament/pages/monitoring/finding-exceptions-queue.blade.php' => [
|
||||
'Open tenant detail',
|
||||
'tenant drilldowns',
|
||||
],
|
||||
'apps/platform/resources/views/filament/pages/tenant-required-permissions.blade.php' => [
|
||||
'No tenant selected',
|
||||
],
|
||||
'apps/platform/lang/en/localization.php' => [
|
||||
'build this tenant\'s policy inventory',
|
||||
'Tenant scope',
|
||||
'Select tenant',
|
||||
'No tenant selected',
|
||||
'No active tenants',
|
||||
'Tenant dashboard',
|
||||
'tenant blocker',
|
||||
],
|
||||
'apps/platform/app/Support/Baselines/BaselineCompareSummaryAssessor.php' => [
|
||||
'This tenant does not have an assigned baseline yet.',
|
||||
],
|
||||
'apps/platform/app/Support/Baselines/BaselineCompareStats.php' => [
|
||||
'This tenant has no baseline assignment. A workspace manager can assign a baseline profile to this tenant.',
|
||||
'No tenant selected.',
|
||||
],
|
||||
'apps/platform/app/Services/Tenants/TenantActionPolicySurface.php' => [
|
||||
'Add tenant',
|
||||
'Restore tenant',
|
||||
'Archive tenant',
|
||||
],
|
||||
'apps/platform/app/Support/Ui/GovernanceActions/GovernanceActionCatalog.php' => [
|
||||
'Restore tenant',
|
||||
'Archive tenant',
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@
|
||||
expect($hits)->toBeEmpty("Retired management path or tenant-panel route emission detected on a Spec 288 seam:\n".implode("\n", $hits));
|
||||
});
|
||||
|
||||
it('keeps spec 288 proof seams free of retired tenant-panel helper bootstrapping', function (): void {
|
||||
it('keeps spec 288 proof seams free of reintroduced retired tenant-panel helpers', function (): void {
|
||||
$root = base_path();
|
||||
|
||||
$forbiddenPatternsByFile = [
|
||||
@ -136,5 +136,5 @@
|
||||
}
|
||||
}
|
||||
|
||||
expect($hits)->toBeEmpty("Retired tenant-panel helper or bootstrapping detected on a Spec 288 proof seam:\n".implode("\n", $hits));
|
||||
});
|
||||
expect($hits)->toBeEmpty("Forbidden retired tenant-panel helper or bootstrapping detected on a Spec 288 proof seam; setTenantPanelContext() must not be reintroduced as a current helper:\n".implode("\n", $hits));
|
||||
});
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
->get('/admin/login')
|
||||
->assertSuccessful()
|
||||
->assertSee('Mit Microsoft anmelden')
|
||||
->assertSee('ManagedEnvironment-Admin-Zugriff erfordert eine ManagedEnvironment-Mitgliedschaft');
|
||||
->assertSee('Admin-Zugriff erfordert eine Umgebungsmitgliedschaft');
|
||||
});
|
||||
|
||||
it('keeps system plane resolution independent from user and workspace preferences', function (): void {
|
||||
|
||||
@ -224,7 +224,7 @@
|
||||
expect($payload['sections'])->toHaveCount(1)
|
||||
->and($payload['sections'][0]['key'])->toBe('alert_delivery_failures')
|
||||
->and($payload['sections'][0]['count'])->toBe(0)
|
||||
->and($payload['sections'][0]['empty_state'])->toContain('tenant filter');
|
||||
->and($payload['sections'][0]['empty_state'])->toContain('environment filter');
|
||||
});
|
||||
|
||||
it('omits finding exceptions when the exception family is hidden or tenant scope is inaccessible', function (): void {
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
# Requirements Checklist: Managed Environment Terminology & Copy Cleanup
|
||||
|
||||
**Purpose**: Validate that Spec 298 preparation is bounded, implementation-ready, and constitution-aligned.
|
||||
**Created**: 2026-05-13
|
||||
**Feature**: [spec.md](/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/298-managed-environment-terminology-copy-cleanup/spec.md)
|
||||
|
||||
## Applicability And Low-Impact Gate
|
||||
|
||||
- [x] CHK001 The change explicitly affects operator-facing copy, localization values, tests, guards, and possible browser smoke anchors.
|
||||
- [x] CHK002 The spec, plan, and tasks carry the same native/custom classification, shared-family relevance, state-layer ownership, and exception policy.
|
||||
|
||||
## Native, Shared-Family, And State Ownership
|
||||
|
||||
- [x] CHK003 The scope keeps existing Laravel/Filament/Blade surfaces and does not introduce a new custom UI system.
|
||||
- [x] CHK004 No shared-detail or shared-family surface is replaced; labels and selectors are updated in place.
|
||||
- [x] CHK005 Copy/value, page/action label, view text, test helper wording, guard regex descriptions, and browser selectors are named as separate state layers.
|
||||
- [x] CHK006 Existing action hierarchy and inspect/open models remain unchanged unless an affected label needs a noun update.
|
||||
|
||||
## Shared Pattern Reuse
|
||||
|
||||
- [x] CHK007 The cross-cutting interaction classes are explicitly marked: localization, shell/context copy, action labels, guard tests, and browser anchors.
|
||||
- [x] CHK008 The existing shared paths are named: localization arrays, `ManagedEnvironmentLinks`, `setAdminEnvironmentContext()`, and current guard/browser patterns.
|
||||
- [x] CHK009 No parallel operator-facing vocabulary framework is introduced.
|
||||
|
||||
## OperationRun Start UX Contract
|
||||
|
||||
- [x] CHK010 The spec states that no new OperationRun start/completion/link behavior is introduced.
|
||||
- [x] CHK011 Existing OperationRun UX/link contracts remain the owner if copy around operations is touched.
|
||||
- [x] CHK012 No queued DB notification or terminal notification behavior changes are planned.
|
||||
|
||||
## Provider Boundary And Vocabulary
|
||||
|
||||
- [x] CHK013 Provider-owned terms such as Microsoft tenant ID and Entra tenant ID are allowed only when the external provider is the subject.
|
||||
- [x] CHK014 Generic platform/operator vocabulary is required to use workspace, managed environment, environment, provider connection, operation, finding, review, evidence, and governance terms.
|
||||
|
||||
## Signals, Exceptions, And Test Depth
|
||||
|
||||
- [x] CHK015 Repository signals are classified as review-mandatory: final scans, guard literals, browser selector changes, localization value decisions, and destructive action label changes.
|
||||
- [x] CHK016 Remaining tenant references must be documented in `terminology-audit.md` with explicit categories.
|
||||
- [x] CHK017 Required surface test profiles are explicit: `standard-native-filament`, `global-context-shell`, and targeted `browser-smoke` only when touched.
|
||||
- [x] CHK018 The chosen test lanes are focused and do not require a full-suite repair loop.
|
||||
|
||||
## Audience-Aware Disclosure And Decision Hierarchy
|
||||
|
||||
- [x] CHK019 Default-visible context copy must be environment-first while provider/raw/support details remain in existing disclosure tiers.
|
||||
- [x] CHK020 Customer/read-only paths do not gain raw JSON, copied context payloads, fingerprints, or internal reason ownership.
|
||||
- [x] CHK021 The spec does not add new primary actions; it only relabels existing actions where needed.
|
||||
- [x] CHK022 Duplicate or contradictory tenant/environment wording is treated as drift to fix or document.
|
||||
|
||||
## Filament v5 Contract
|
||||
|
||||
- [x] CHK023 Filament v5 / Livewire v4.0+ compliance is explicit.
|
||||
- [x] CHK024 Laravel 12 panel provider registration remains in `apps/platform/bootstrap/providers.php`.
|
||||
- [x] CHK025 Globally searchable resource handling is called out for any touched resource.
|
||||
- [x] CHK026 Destructive actions that are relabeled must retain `->action(...)`, `->requiresConfirmation()`, and authorization.
|
||||
- [x] CHK027 Asset strategy is unchanged unless implementation unexpectedly registers assets, in which case `filament:assets` is required in deployment notes.
|
||||
- [x] CHK028 Testing plan names affected pages/actions/guards/browser anchors.
|
||||
|
||||
## Review Outcome
|
||||
|
||||
- [x] CHK029 Review outcome class: `acceptable-special-case`.
|
||||
- [x] CHK030 Workflow outcome: `keep`.
|
||||
- [x] CHK031 Final note location: active feature PR close-out entry `Guardrail / Terminology Cleanup / Smoke Coverage`.
|
||||
|
||||
## Notes
|
||||
|
||||
- This is a cleanup spec, not a broad rename or localization foundation.
|
||||
- Remaining provider/internal/historical tenant references are allowed only when categorized in the audit.
|
||||
329
specs/298-managed-environment-terminology-copy-cleanup/plan.md
Normal file
329
specs/298-managed-environment-terminology-copy-cleanup/plan.md
Normal file
@ -0,0 +1,329 @@
|
||||
# Implementation Plan: Managed Environment Terminology & Copy Cleanup
|
||||
|
||||
**Branch**: `298-managed-environment-terminology-copy-cleanup` | **Date**: 2026-05-13 | **Spec**: [spec.md](/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/298-managed-environment-terminology-copy-cleanup/spec.md)
|
||||
**Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/298-managed-environment-terminology-copy-cleanup/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Spec 298 is a bounded post-cutover terminology cleanup. The implementation will audit remaining tenant-first copy, update active visible UI/localization/test vocabulary to Workspace and Managed Environment / Environment terminology, clarify forbidden legacy guard literals, update affected browser-smoke selectors, and document allowed provider/internal/historical references. It must not rename the database/model layer or reintroduce legacy tenant routes, panels, helper aliases, or compatibility surfaces.
|
||||
|
||||
This plan is preparation only. It does not implement application code.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: PHP 8.4.15
|
||||
**Primary Dependencies**: Laravel 12.52.0, Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, Laravel Sail 1.52.0
|
||||
**Storage**: PostgreSQL through Laravel/Sail for tests; no schema or persistence change planned
|
||||
**Testing**: Pest via `./vendor/bin/sail artisan test --compact`; targeted Browser tests only if visible smoke anchors are touched
|
||||
**Validation Lanes**: Feature/Guards, Feature/Localization, Feature/Workspaces, Feature/ProviderConnections, Feature/RequiredPermissions, Feature/Filament, affected Feature areas, targeted Browser smoke
|
||||
**Target Platform**: Laravel Sail local runtime and Gitea-compatible CI runners
|
||||
**Project Type**: Laravel web application under `apps/platform`
|
||||
**Performance Goals**: Keep scans and tests focused; no full-suite repair and no browser timeout inflation
|
||||
**Constraints**: no `/admin/t...` restoration, no `/admin/tenants...` restoration, no `TenantPanelProvider`, no `setTenantPanelContext()` alias, no DB/model rename, no new localization architecture
|
||||
**Scale/Scope**: Copy, localization values, test wording, guard descriptions, browser selectors, and spec-local audit only
|
||||
|
||||
## Initial Repo Baseline
|
||||
|
||||
Preparation scans on 2026-05-13 found:
|
||||
|
||||
- Current branch before Spec Kit execution was `platform-dev`; Spec Kit switched to `298-managed-environment-terminology-copy-cleanup`.
|
||||
- Working tree was clean before creating the package.
|
||||
- No existing `specs/298-*` package or matching branch was present.
|
||||
- Related specs:
|
||||
- `specs/297-managed-environment-canonical-route-cutover/` is dependency/context and carries completed-task signals; do not rewrite it.
|
||||
- `specs/286-ui-copy-ia-localization-neutralization/` is adjacent context and carries completed/review signals; do not rewrite it.
|
||||
- `specs/288-quality-gates-no-legacy-enforcement/` is adjacent guard context and includes explicit legacy guard concepts; do not weaken it.
|
||||
- Read-only source scan over `apps/platform/app`, `apps/platform/resources`, and `apps/platform/routes` returned no hits for active old route/generator patterns:
|
||||
|
||||
```bash
|
||||
rg "filament\.admin\.resources\.tenants|/admin/tenants|/admin/t/|TenantResource::getUrl|TenantDashboard::getUrl|TenantRequiredPermissions::getUrl|setTenantPanelContext|panel:\s*'tenant'|panel:\s*\"tenant\"" apps/platform/app apps/platform/resources apps/platform/routes --glob '!vendor' --glob '!node_modules'
|
||||
```
|
||||
|
||||
- Read-only copy/test scan found representative hits in:
|
||||
- `apps/platform/lang/en/localization.php`
|
||||
- `apps/platform/lang/de/localization.php`
|
||||
- `apps/platform/resources/views/filament/pages/monitoring/finding-exceptions-queue.blade.php`
|
||||
- `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php`
|
||||
- `apps/platform/resources/views/filament/pages/tenant-required-permissions.blade.php`
|
||||
- `apps/platform/app/Services/Tenants/TenantActionPolicySurface.php`
|
||||
- `apps/platform/app/Support/Baselines/BaselineCompareStats.php`
|
||||
- `apps/platform/app/Support/Ui/GovernanceActions/GovernanceActionCatalog.php`
|
||||
- `apps/platform/app/Filament/Pages/Monitoring/FindingExceptionsQueue.php`
|
||||
- `apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php`
|
||||
- `apps/platform/app/Filament/Resources/BackupScheduleResource.php`
|
||||
- `apps/platform/app/Filament/Resources/BaselineProfileResource/RelationManagers/BaselineTenantAssignmentsRelationManager.php`
|
||||
- guard/localization/findings tests
|
||||
- `apps/platform/tests/Pest.php` already contains `setAdminEnvironmentContext()`.
|
||||
- `apps/platform/tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php` still contains `setTenantPanelContext` regex literals as forbidden-pattern checks; implementation must make the guard wording unambiguously legacy-forbidden.
|
||||
|
||||
The implementation must refresh `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/298-managed-environment-terminology-copy-cleanup/terminology-audit.md` with full required scans before application edits.
|
||||
|
||||
## UI / Surface Guardrail Plan
|
||||
|
||||
- **Guardrail scope**: changed visible copy and validation wording on existing surfaces; no new product workflow.
|
||||
- **Native vs custom classification summary**: Existing native Filament/Laravel/Blade surfaces; no custom UI redesign.
|
||||
- **Shared-family relevance**: shell/context labels, dashboard copy, action labels, modal headings, empty states, guard tests, browser anchors, localization values.
|
||||
- **State layers in scope**: copy/value, page/action label, view text, test helper wording, guard regex descriptions, browser selectors.
|
||||
- **Audience modes in scope**: operator-MSP and support-platform. Customer-facing localization may be touched only where targeted strings are already active and in scope.
|
||||
- **Decision/diagnostic/raw hierarchy plan**: Preserve existing hierarchy. Replace wrong tenant-first terms; do not move diagnostic/raw content.
|
||||
- **Raw/support gating plan**: unchanged.
|
||||
- **One-primary-action / duplicate-truth control**: Do not add new actions. If labels change, keep the existing action hierarchy and only update the object noun.
|
||||
- **Handling modes by drift class or surface**: fix active UI/test terminology; document provider/internal/historical/regression-guard exceptions; defer DB/model rename and broad historical cleanup.
|
||||
- **Repository-signal treatment**: review-mandatory for final scans, guard literals, browser selector changes, localization key/value decisions, and destructive action label changes.
|
||||
- **Special surface test profiles**: `standard-native-filament`, `global-context-shell`, `browser-smoke` if browser files change.
|
||||
- **Required tests or manual smoke**: focused Feature tests for touched areas; targeted Browser smokes when browser anchors change.
|
||||
- **Exception path and spread control**: Every final tenant-related hit must be in `terminology-audit.md` with category and reason.
|
||||
- **Active feature PR close-out entry**: Guardrail / Terminology Cleanup / Smoke Coverage.
|
||||
|
||||
## Shared Pattern & System Fit
|
||||
|
||||
- **Cross-cutting feature marker**: yes.
|
||||
- **Systems touched**: localization arrays, Filament page/resource labels, support copy emitters, Blade views, tests, browser smokes, and guard tests.
|
||||
- **Shared abstractions reused**: existing localization keys where safe, `ManagedEnvironmentLinks`, `setAdminEnvironmentContext()`, existing data-testid/browser patterns, existing guard-test pattern.
|
||||
- **New abstraction introduced? why?**: none.
|
||||
- **Why the existing abstraction was sufficient or insufficient**: Canonical route/helper truth already exists. The remaining issue is copy/test terminology, which can be fixed in place.
|
||||
- **Bounded deviation / spread control**: Technical class/model/table names and provider-specific Microsoft/Entra tenant wording remain only with audit documentation.
|
||||
|
||||
## OperationRun UX Impact
|
||||
|
||||
- **Touches OperationRun start/completion/link UX?**: no new start/completion/link behavior; possible label/copy updates only.
|
||||
- **Central contract reused**: existing OperationRun UX/link contracts if touched.
|
||||
- **Delegated UX behaviors**: unchanged.
|
||||
- **Surface-owned behavior kept local**: copy only.
|
||||
- **Queued DB-notification policy**: N/A.
|
||||
- **Terminal notification path**: unchanged.
|
||||
- **Exception path**: none.
|
||||
|
||||
## Provider Boundary & Portability Fit
|
||||
|
||||
- **Shared provider/platform boundary touched?**: yes, vocabulary only.
|
||||
- **Provider-owned seams**: Microsoft tenant ID, Entra tenant ID, Microsoft Graph, Intune, provider permission names, provider payload metadata.
|
||||
- **Platform-core seams**: Workspace, Managed Environment, Environment scope, Provider Connection, Operation, Finding, Review, Evidence, Governance.
|
||||
- **Neutral platform terms / contracts preserved**: current UI and tests should prefer workspace/environment terms in generic product surfaces.
|
||||
- **Retained provider-specific semantics and why**: Microsoft/Entra tenant terms remain when external identity or provider data is the subject.
|
||||
- **Bounded extraction or follow-up path**: no provider framework. Follow-up only for structural DB/model rename or broad localization productization.
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before runtime implementation and re-check before close-out.*
|
||||
|
||||
- Inventory-first: no inventory/snapshot truth change.
|
||||
- Read/write separation: no new write workflow. Touched destructive labels such as restore/remove must keep existing confirmation, authorization, and audit behavior.
|
||||
- Single Graph contract path: no Graph calls added.
|
||||
- Deterministic capabilities: no capability resolver change.
|
||||
- Proportionality / no premature abstraction: no new abstraction; copy updates are in place.
|
||||
- No new persisted truth: no migrations, tables, columns, compatibility shims, or dual-read paths.
|
||||
- Workspace isolation: copy/helper/test changes must not weaken workspace membership checks.
|
||||
- Tenant/managed-environment isolation: existing environment entitlement checks remain intact.
|
||||
- RBAC-UX: non-member/out-of-scope remains 404; established member missing capability remains 403.
|
||||
- Provider boundary: generic platform copy moves away from tenant-first wording; provider tenant terms remain provider-owned.
|
||||
- Test governance: targeted guard/feature/browser lanes only; no hidden broad suite repair.
|
||||
- Filament-native UI: Filament remains v5 on Livewire v4; no v3/v4 APIs; no custom UI styling changes.
|
||||
- Deployment/ops: no asset registration is planned. If assets are unexpectedly registered, deploy notes must include `cd apps/platform && php artisan filament:assets`.
|
||||
|
||||
## Filament v5 Output Contract
|
||||
|
||||
- **Livewire compliance**: Filament v5 targets Livewire v4.0+; current app has Livewire 4.1.4.
|
||||
- **Provider registration location**: Laravel 12 provider registration remains in `apps/platform/bootstrap/providers.php`; this spec must not add or restore a panel provider.
|
||||
- **Globally searchable resources**: No new searchable resource is planned. Any touched globally searchable resource must retain Edit/View pages or have global search disabled.
|
||||
- **Destructive actions**: This spec may relabel existing destructive actions such as restore/remove. They must still execute via `->action(...)`, require `->requiresConfirmation()`, and enforce server-side authorization.
|
||||
- **Asset strategy**: No new Filament assets are planned. If implementation unexpectedly registers assets, deployment must include `cd apps/platform && php artisan filament:assets`.
|
||||
- **Testing plan**: Touched Filament pages/resources/actions are covered with Pest/Filament tests; guard tests cover forbidden legacy helper/route wording; browser smokes cover affected anchors.
|
||||
|
||||
## Test Governance Check
|
||||
|
||||
- **Test purpose / classification by changed surface**: Feature guard tests for terminology and route/runtime regression; Feature/Localization and Feature/Filament tests for labels/copy; Browser only for affected smoke anchors.
|
||||
- **Affected validation lanes**: Feature/Guards, Feature/Localization, Feature/Workspaces, Feature/ProviderConnections, Feature/RequiredPermissions, Feature/Filament, affected Feature directories, Browser smoke anchors.
|
||||
- **Why this lane mix is the narrowest sufficient proof**: The change is copy/test terminology cleanup with route-regression protection, not a new workflow.
|
||||
- **Narrowest proving command(s)**:
|
||||
|
||||
```bash
|
||||
cd apps/platform
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Guards
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Localization
|
||||
```
|
||||
|
||||
- **Fixture / helper / factory / seed / context cost risks**: Avoid widening `setAdminEnvironmentContext()` or adding provider/browser setup defaults.
|
||||
- **Expensive defaults or shared helper growth introduced?**: none planned.
|
||||
- **Heavy-family additions, promotions, or visibility changes**: none planned; targeted browser smokes only when affected.
|
||||
- **Surface-class relief / special coverage rule**: Standard-native Filament relief unless a browser-visible context-shell anchor changes.
|
||||
- **Closing validation and reviewer handoff**: run final scans, focused guards, affected feature lanes, browser anchors if touched, Pint dirty, and `git diff --check`.
|
||||
- **Budget / baseline / trend follow-up**: none expected.
|
||||
- **Review-stop questions**: Did old tenant-first wording remain in active UI? Did a guard literal become ambiguous? Did a browser smoke still click old copy? Did route scans remain clean? Did destructive action relabeling preserve confirmation/authorization?
|
||||
- **Escalation path**: document-in-feature for allowed exceptions; follow-up-spec for structural rename/localization beyond scope.
|
||||
- **Active feature PR close-out entry**: Guardrail / Terminology Cleanup / Smoke Coverage.
|
||||
- **Why no dedicated follow-up spec is needed**: The current work is a bounded cleanup. Structural rename and broad localization remain explicit follow-ups.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/298-managed-environment-terminology-copy-cleanup/
|
||||
├── spec.md
|
||||
├── plan.md
|
||||
├── tasks.md
|
||||
├── terminology-audit.md
|
||||
└── checklists/
|
||||
└── requirements.md
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
Expected touched surfaces during implementation:
|
||||
|
||||
```text
|
||||
apps/platform/lang/
|
||||
├── en/localization.php
|
||||
└── de/localization.php
|
||||
|
||||
apps/platform/resources/views/
|
||||
├── filament/partials/context-bar.blade.php
|
||||
├── filament/pages/**
|
||||
└── livewire/**
|
||||
|
||||
apps/platform/app/
|
||||
├── Filament/**
|
||||
├── Support/**
|
||||
└── Services/**
|
||||
|
||||
apps/platform/tests/
|
||||
├── Pest.php
|
||||
├── Feature/**
|
||||
└── Browser/**
|
||||
```
|
||||
|
||||
**Structure Decision**: Use existing Laravel/Filament app structure and existing localization/test conventions. Do not create a new base application folder or dependency.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|---|---|---|
|
||||
| Spec-local terminology audit | Remaining `Tenant` references need classification so the implementation does not remove provider/internal/historical truth blindly | Ad hoc final summary would not give reviewers a durable exception map |
|
||||
| Cross-cutting copy/test updates | The old vocabulary appears across multiple existing layers | One local label change would leave contradictory product truth |
|
||||
| Guard wording update | Legacy helper regex literals remain useful but ambiguous | Removing the regex would weaken Spec 288 protection |
|
||||
|
||||
## Phase 0: Safety Gate
|
||||
|
||||
1. Run:
|
||||
|
||||
```bash
|
||||
git status --short --branch
|
||||
git diff --stat
|
||||
git log -1 --oneline
|
||||
```
|
||||
|
||||
2. Confirm the implementation branch is `298-managed-environment-terminology-copy-cleanup` or an isolated session branch derived from it.
|
||||
3. Stop if unrelated uncommitted changes exist.
|
||||
4. Read:
|
||||
|
||||
```text
|
||||
.specify/memory/constitution.md
|
||||
specs/297-managed-environment-canonical-route-cutover/
|
||||
specs/288-quality-gates-no-legacy-enforcement/
|
||||
specs/286-ui-copy-ia-localization-neutralization/
|
||||
```
|
||||
|
||||
## Phase 1: Baseline Scan And Audit
|
||||
|
||||
Refresh `terminology-audit.md` before application edits:
|
||||
|
||||
```bash
|
||||
git status --short --branch
|
||||
git diff --stat
|
||||
|
||||
cd apps/platform
|
||||
./vendor/bin/sail artisan route:list | rg "admin/tenants|admin/t/" && exit 1 || true
|
||||
|
||||
rg "filament\.admin\.resources\.tenants|/admin/tenants|/admin/t/|TenantResource::getUrl|TenantDashboard::getUrl|TenantRequiredPermissions::getUrl|setTenantPanelContext|panel:\s*'tenant'|panel:\s*\"tenant\"" app resources routes --glob '!vendor' --glob '!node_modules'
|
||||
|
||||
rg "setTenantPanelContext|panel:\s*'tenant'|panel:\s*\"tenant\"" tests --glob '!vendor' --glob '!node_modules'
|
||||
|
||||
rg "Tenant dashboard|Tenant detail|Open tenant|Select tenant|Tenant scope|No tenant selected|No active tenants|Remove tenant|Restore tenant|Tenant memberships|tenant blocker" app resources lang tests --glob '!vendor' --glob '!node_modules'
|
||||
```
|
||||
|
||||
Classify findings as `fixed`, `allowed-provider-term`, `allowed-internal-model`, `allowed-historical`, `allowed-regression-guard`, `out-of-scope-db-model-rename`, or `needs-follow-up`.
|
||||
|
||||
## Phase 2: Guard And Test Helper Cleanup
|
||||
|
||||
- Keep `setAdminEnvironmentContext()` as the active helper if repo-real.
|
||||
- Do not add `setTenantPanelContext()` alias.
|
||||
- Update guard test descriptions and failure messages so remaining `setTenantPanelContext` regex literals clearly forbid a retired helper.
|
||||
- Update active test names/comments that describe current runtime as tenant panel context.
|
||||
- Run:
|
||||
|
||||
```bash
|
||||
cd apps/platform
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Guards
|
||||
```
|
||||
|
||||
## Phase 3: Localization And Visible Copy Cleanup
|
||||
|
||||
- Update EN/DE localization values first; rename keys only when usage is fully bounded.
|
||||
- Replace targeted active UI phrases:
|
||||
- `Tenant dashboard` -> `Environment dashboard` or `Managed environment dashboard`
|
||||
- `Tenant detail` / `Open tenant detail` -> `Environment detail` / `Open environment detail`
|
||||
- `Select tenant` -> `Select environment`
|
||||
- `Tenant scope` -> `Environment scope`
|
||||
- `No tenant selected` -> `No environment selected`
|
||||
- `No active tenants` -> `No active environments`
|
||||
- `Tenant memberships` -> `Environment access scopes`
|
||||
- `Remove tenant` -> `Remove environment`
|
||||
- `Restore tenant` -> `Restore environment`
|
||||
- `tenant blocker` -> `environment blocker`
|
||||
- Keep Microsoft/Entra tenant ID wording where provider-specific.
|
||||
- Preserve existing Filament action hierarchy and destructive-action safeguards.
|
||||
- Run focused tests for touched areas.
|
||||
|
||||
## Phase 4: Blade, Filament, Support Copy, And Browser Smokes
|
||||
|
||||
- Update context-bar, dashboard, monitoring, baseline compare, required-permissions, backup schedule, support diagnostics, governance action, and policy surface copy as discovered by the audit.
|
||||
- Prefer stable `data-testid` selectors for browser smokes if old copy is not a stable product contract.
|
||||
- Do not increase timeouts without a documented timing cause.
|
||||
- Run affected browser smokes individually before broader browser anchors.
|
||||
|
||||
## Phase 5: Final Scans And Proof Pack
|
||||
|
||||
Run the final scans from Phase 1 again. Every remaining hit must be absent or documented in `terminology-audit.md`.
|
||||
|
||||
Run proof commands:
|
||||
|
||||
```bash
|
||||
cd apps/platform
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Guards
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Localization
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Workspaces
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Filament
|
||||
./vendor/bin/sail artisan test --compact tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php
|
||||
./vendor/bin/sail bin pint --dirty --format agent
|
||||
```
|
||||
|
||||
Then run from the repo root:
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
```
|
||||
|
||||
## Phase 6: Close-Out
|
||||
|
||||
- Update `terminology-audit.md` with final status and allowed references.
|
||||
- Record the Filament v5 output contract in the implementation summary.
|
||||
- Final decision must be one of:
|
||||
- `298 merge-ready; terminology cleanup complete`
|
||||
- `298 merge-ready with documented allowed technical tenant references`
|
||||
- `298 blocked by active legacy tenant copy`
|
||||
- `298 blocked by runtime legacy regression`
|
||||
|
||||
## Explicit Follow-Ups / Out of Scope
|
||||
|
||||
- Database/model rename from `Tenant` to `ManagedEnvironment`
|
||||
- Broad localization v1 or customer-facing localization adoption
|
||||
- Historical spec/doc rewrite
|
||||
- New customer review workspace
|
||||
- Decision inbox or new governance workflow
|
||||
- New RBAC or provider abstraction
|
||||
- UI redesign
|
||||
302
specs/298-managed-environment-terminology-copy-cleanup/spec.md
Normal file
302
specs/298-managed-environment-terminology-copy-cleanup/spec.md
Normal file
@ -0,0 +1,302 @@
|
||||
# Feature Specification: Managed Environment Terminology & Copy Cleanup
|
||||
|
||||
**Feature Branch**: `298-managed-environment-terminology-copy-cleanup`
|
||||
**Created**: 2026-05-13
|
||||
**Status**: Ready
|
||||
**Input**: User-provided Spec 298 draft: clean up remaining visible and test-side tenant terminology after Spec 297 retired the active legacy tenant route/runtime layer.
|
||||
|
||||
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
|
||||
|
||||
- **Problem**: The route/runtime cutover from legacy tenant surfaces is complete enough to make old tenant-first language misleading, but active copy, localization values, tests, guard descriptions, and browser-smoke selectors still expose the retired TenantPanel mental model.
|
||||
- **Today's failure**: Operators and contributors can still see or assert strings such as `Tenant dashboard`, `Tenant scope`, `Select tenant`, `No active tenants`, `Open tenant detail`, `Remove tenant`, `Restore tenant`, `Tenant memberships`, `tenant blocker`, or guard/helper language around `setTenantPanelContext()` even though the product is workspace-first and managed-environment-first.
|
||||
- **User-visible improvement**: Current UI surfaces, localization strings, tests, and smoke anchors read as Workspace -> Managed Environment / Environment context, while provider-specific phrases such as Microsoft tenant ID remain allowed only where they describe external Microsoft/Entra truth.
|
||||
- **Smallest enterprise-capable version**: Run and record a terminology audit, update active user-facing copy and localization values for the targeted phrases, clarify/rename ambiguous test helper and guard wording, update affected browser-smoke selectors or assertions, keep active legacy route scans clean, and document allowed technical/provider/historical exceptions.
|
||||
- **Explicit non-goals**: No database/table/model rename from `Tenant` to `ManagedEnvironment`, no migration rewrite, no new routing architecture, no new localization foundation, no UI redesign, no RBAC remodel, no old route or provider restoration, no broad historical spec rewrite, and no full-suite fix-all.
|
||||
- **Permanent complexity imported**: One spec-local terminology audit artifact plus targeted tests/guard updates. No new table, enum, status family, provider framework, route framework, or localization architecture is introduced.
|
||||
- **Why now**: Spec 297 retired active legacy tenant route surfaces and centralized canonical managed-environment links. Leaving visible/test copy on the old vocabulary makes future specs and tests regress toward tenant-first product truth.
|
||||
- **Why not local**: The drift crosses localization catalogs, Blade views, Filament labels/actions, support copy, tests, guard regex literals, and browser smokes. A single local copy fix would leave contradictory terminology in other active surfaces.
|
||||
- **Approval class**: Cleanup
|
||||
- **Red flags triggered**: Cross-cutting copy/test cleanup and terminology audit. Defense: the scope is explicitly bounded to existing strings, tests, and guard wording; it does not introduce a new vocabulary framework or rename persistence.
|
||||
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 2 | **Gesamt: 11/12**
|
||||
- **Decision**: approve
|
||||
|
||||
## Spec Scope Fields *(mandatory)*
|
||||
|
||||
- **Scope**: canonical-view
|
||||
- **Primary Routes**:
|
||||
- Canonical context: `/admin/workspaces/{workspace}/environments`
|
||||
- Canonical context: `/admin/workspaces/{workspace}/environments/{environment}`
|
||||
- Canonical environment support surfaces such as required permissions, diagnostics, access scopes, provider connections, operations, findings, reviews, evidence, and stored reports where repo-real
|
||||
- Retired and forbidden as product truth: `/admin/t...` and `/admin/tenants...`
|
||||
- **Data Ownership**:
|
||||
- No persisted data ownership changes.
|
||||
- Existing internal `Tenant` model/table/column names may remain technical implementation truth where DB/model rename is out of scope.
|
||||
- Provider-specific Microsoft/Entra tenant identifiers remain provider-owned external truth, not TenantPilot platform vocabulary.
|
||||
- **RBAC**:
|
||||
- Workspace membership remains the primary authorization boundary.
|
||||
- Managed-environment access scoping remains narrowing/access-scope behavior where repo-real.
|
||||
- Non-member or out-of-scope access remains deny-as-not-found (404).
|
||||
- Established member missing capability remains 403.
|
||||
- UI visibility is not authorization; Gates/Policies remain server-side truth.
|
||||
|
||||
For canonical-view specs:
|
||||
|
||||
- **Default filter behavior when tenant-context is active**: Current environment context may prefilter workspace-wide pages, but copy must name that state as environment or managed-environment context, not tenant-panel context.
|
||||
- **Explicit entitlement checks preventing cross-tenant leakage**: This spec must not weaken existing workspace/environment entitlement checks. Any changed links, labels, or smoke selectors must continue to use the canonical route/link helpers and existing authorization proof.
|
||||
|
||||
## Cross-Cutting / Shared Pattern Reuse *(mandatory)*
|
||||
|
||||
- **Cross-cutting feature?**: yes
|
||||
- **Interaction class(es)**: localization values, Filament page/resource labels, action labels, modal headings, empty states, helper text, notification/modal copy, context-bar copy, Blade view copy, test names, test helper wording, guard regex descriptions, browser-smoke selectors.
|
||||
- **Systems touched**:
|
||||
- `apps/platform/lang/en/localization.php`
|
||||
- `apps/platform/lang/de/localization.php`
|
||||
- `apps/platform/resources/views/**`
|
||||
- `apps/platform/app/Filament/**`
|
||||
- `apps/platform/app/Support/**`
|
||||
- `apps/platform/app/Services/**` where visible copy is emitted
|
||||
- `apps/platform/tests/Pest.php`
|
||||
- `apps/platform/tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php`
|
||||
- affected `apps/platform/tests/Feature/**` and `apps/platform/tests/Browser/**`
|
||||
- `specs/298-managed-environment-terminology-copy-cleanup/terminology-audit.md`
|
||||
- **Existing pattern(s) to extend**: Spec 297 canonical managed-environment route/link contract, existing `ManagedEnvironmentLinks`, existing `setAdminEnvironmentContext()` helper, current localization arrays, existing Spec 288 guard-test style, existing browser-smoke anchors.
|
||||
- **Shared contract / presenter / builder / renderer to reuse**: Use existing localization keys where key rename is risky; update visible values first. Use `ManagedEnvironmentLinks` and existing `data-testid` patterns for browser-safe anchors when selectors are needed.
|
||||
- **Why the existing shared path is sufficient or insufficient**: The canonical route/link path already exists. What remains insufficient is visible and test vocabulary that still uses tenant-first product language for current environment surfaces.
|
||||
- **Allowed deviation and why**: Internal model/class names such as `TenantResource`, `TenantDashboard`, `TenantRequiredPermissions`, `tenant_id`, and Microsoft/Entra tenant ID copy may remain where they are internal, provider-specific, historical, or out of scope for DB/model rename. They must be documented in the audit if surfaced by final scans.
|
||||
- **Consistency impact**: Current UI, tests, localization values, smoke anchors, and guard descriptions must converge on Workspace, Managed Environment, Environment, Provider Connection, Operation, Finding, Review, Evidence, and Governance vocabulary.
|
||||
- **Review focus**: Reviewers must verify that no active product UI uses retired TenantPanel or tenant-first language, route/runtime legacy scans remain clean, and guard literals only remain when they explicitly forbid retired behavior.
|
||||
|
||||
## OperationRun UX Impact *(mandatory)*
|
||||
|
||||
- **Touches OperationRun start/completion/link UX?**: no new OperationRun behavior; possible copy-only updates on operation-related strings.
|
||||
- **Shared OperationRun UX contract/layer reused**: Existing `OperationRunLinks`, `OperationUxPresenter`, and canonical operations routes remain unchanged if touched.
|
||||
- **Delegated start/completion UX behaviors**: Existing queued/running/terminal UX behavior remains owned by the shared OperationRun path.
|
||||
- **Local surface-owned behavior that remains**: Copy and labels only.
|
||||
- **Queued DB-notification policy**: `N/A`.
|
||||
- **Terminal notification path**: unchanged.
|
||||
- **Exception required?**: none.
|
||||
|
||||
## Provider Boundary / Platform Core Check *(mandatory)*
|
||||
|
||||
- **Shared provider/platform boundary touched?**: yes, through operator vocabulary and allowed provider-specific terminology.
|
||||
- **Boundary classification**: mixed
|
||||
- **Seams affected**: localization values, visible provider readiness copy, required-permissions copy, support diagnostics copy, dashboard copy, Microsoft/Entra tenant ID labels, and tests that distinguish platform vocabulary from provider vocabulary.
|
||||
- **Neutral platform terms preserved or introduced**: workspace, managed environment, environment, provider connection, environment scope, required permissions, diagnostics, operation, finding, review, evidence, governance.
|
||||
- **Provider-specific semantics retained and why**: Microsoft tenant ID, Entra tenant ID, Microsoft Graph, Intune, and tenant ID payload metadata remain valid when the external Microsoft provider is the subject.
|
||||
- **Why this does not deepen provider coupling accidentally**: The spec removes generic platform tenant-first vocabulary and narrows provider-specific `tenant` wording to Microsoft/Entra contexts only.
|
||||
- **Follow-up path**: document-in-feature for remaining technical/internal names; follow-up-spec only for structural DB/model rename or broader customer-facing localization adoption.
|
||||
|
||||
## UI / Surface Guardrail Impact *(mandatory)*
|
||||
|
||||
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Localization values | yes | Existing Laravel translation arrays | shell, dashboard, customer workspace, support copy | copy/value only | no | key rename optional only when low risk |
|
||||
| Filament labels/actions/empty states | yes | Native Filament surfaces | action labels, modal headings, page titles, empty states | page/action/copy | no | no layout redesign |
|
||||
| Blade/context-bar copy | yes | Existing Blade/Filament partials | shell/context, dashboard, matrix, queue copy | view copy only | no | no new custom styling |
|
||||
| Tests/guards/browser smokes | no direct operator UI | N/A | validation and smoke anchors | test wording/selectors | no | selectors should be stable and not timeout-based |
|
||||
|
||||
## Decision-First Surface Role *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
| Surface | Decision Role | Human-in-the-loop Moment | Immediately Visible for First Decision | On-Demand Detail / Evidence | Why This Is Primary or Why Not | Workflow Alignment | Attention-load Reduction |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| Environment dashboard/detail copy | Primary Decision Surface | Operator reviews current environment state | environment context, readiness, current blockers, next action | diagnostics and raw provider detail remain secondary | Primary because environment detail is the canonical environment entry point | Workspace -> Managed Environment -> domain pages | removes tenant-first ambiguity |
|
||||
| Context bar / workspace shell copy | Secondary Context Surface | Operator confirms current workspace/environment context | workspace and environment labels | none unless existing shell exposes detail | Secondary because it orients current scope | workspace-first context switching | clarifies workspace-wide pages can exist with no environment selected |
|
||||
| Required permissions/provider readiness copy | Secondary Context Surface | Operator checks provider readiness | environment/provider permission state | provider-specific Graph/Microsoft detail | Secondary because it supports readiness decisions | provider detail under environment context | keeps Microsoft tenant terms provider-specific |
|
||||
| Browser/test anchors | N/A | maintainer validation | stable selectors or current copy assertions | test output only | not an operator surface | validation lane only | prevents brittle old-copy assertions |
|
||||
|
||||
## Audience-Aware Disclosure *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
| Surface | Audience Modes In Scope | Decision-First Default-Visible Content | Operator Diagnostics | Support / Raw Evidence | One Dominant Next Action | Hidden / Gated By Default | Duplicate-Truth Prevention |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| Environment dashboard/detail copy | operator-MSP, support-platform | environment status, readiness, next action | provider detail, support diagnostics | raw payloads only where already permitted | page-owned primary action | raw/support detail | one environment noun across labels |
|
||||
| Context bar / shell copy | operator-MSP, support-platform | workspace and environment scope | unavailable context reason | none | choose/switch environment when applicable | none added | no tenant-panel wording |
|
||||
| Required permissions/provider copy | operator-MSP, support-platform | required permission state and provider context | Microsoft/Graph/Entra details | raw provider IDs if already shown | review/grant required permissions | raw payloads | provider-specific tenant wording only where externally true |
|
||||
|
||||
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
| Surface | Action Surface Class | Surface Type | Likely Next Operator Action | Primary Inspect/Open Model | Row Click | Secondary Actions Placement | Destructive Actions Placement | Canonical Collection Route | Canonical Detail Route | Scope Signals | Canonical Noun | Critical Truth Visible by Default | Exception Type / Justification |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| Managed environments context | Shell / Detail | Workspace-scoped environment context | Choose or inspect environment | existing canonical route/link | existing behavior | existing placement | unchanged; verify confirmation if label touched | `/admin/workspaces/{workspace}/environments` | `/admin/workspaces/{workspace}/environments/{environment}` | workspace + environment | Managed environment / Environment | selected or missing environment state | no route redesign |
|
||||
| Required permissions/provider readiness | Detail / Readiness | Environment-scoped provider readiness | Review permissions | existing page route | N/A | existing placement | none added | inherited environment route | `/admin/workspaces/{workspace}/environments/{environment}/required-permissions` | workspace + environment + provider | Required permissions | missing permission state | provider tenant terms allowed only for Microsoft/Entra |
|
||||
| Tests and guards | Validation | Guard/browser smoke | Prove retired copy/routes stay retired | N/A | N/A | N/A | N/A | N/A | N/A | test context | Admin environment context | forbidden legacy patterns | allowed regression-guard literals only |
|
||||
|
||||
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
| Surface | Primary Persona | Decision / Operator Action Supported | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| Environment dashboard/detail copy | Workspace operator | Decide what needs attention in the selected environment | detail/dashboard | What needs action in this environment? | environment identity, readiness, blockers, next action | provider IDs, support diagnostics | readiness, governance result, lifecycle/outcome where existing | unchanged | existing page actions with environment wording | unchanged |
|
||||
| Context bar / shell copy | Workspace operator | Confirm or switch current context | shell/context | Which workspace/environment am I operating in? | workspace, environment or no-environment state | none added | context availability | TenantPilot only | choose/switch/clear environment | none |
|
||||
| Required permissions/provider readiness | Workspace operator | Decide whether provider permission state blocks environment workflows | readiness detail | Which provider permissions are missing? | required permission state and remediation path | Graph/Microsoft detail | provider readiness | Microsoft tenant only when existing action says so | review required permissions | unchanged |
|
||||
|
||||
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
||||
|
||||
- **New source of truth?**: no
|
||||
- **New persisted entity/table/artifact?**: no application persistence; one spec-local `terminology-audit.md` artifact records scan results and allowed exceptions.
|
||||
- **New abstraction?**: no.
|
||||
- **New enum/state/reason family?**: no.
|
||||
- **New cross-domain UI framework/taxonomy?**: no.
|
||||
- **Current operator problem**: old tenant-first wording in active UI/tests makes the managed-environment cutover look incomplete and encourages future contributors to reintroduce retired route/runtime concepts.
|
||||
- **Existing structure is insufficient because**: copy drift is scattered across localization, Filament labels, Blade, support services, and tests; implementation needs an audit artifact and focused guard proof, not a new framework.
|
||||
- **Narrowest correct implementation**: update visible values and tests in place, prefer existing localization keys where key rename is risky, document allowed technical/provider references, and add or adjust only focused guards.
|
||||
- **Ownership cost**: low; one audit artifact and targeted copy/test updates.
|
||||
- **Alternative intentionally rejected**: repo-wide removal of every `Tenant` string or DB/model rename. Those would be larger structural changes and out of scope.
|
||||
- **Release truth**: current-release cleanup after route/runtime cutover in a pre-production environment.
|
||||
|
||||
### Compatibility posture
|
||||
|
||||
This feature assumes the repo's pre-production lean doctrine.
|
||||
|
||||
Backward compatibility aliases, legacy route fallbacks, old helper aliases, and tenant-first compatibility copy are out of scope. Current visible copy should be replaced rather than preserved with aliases unless the phrase is provider-specific, internal, historical, or explicitly documented as a regression guard.
|
||||
|
||||
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
|
||||
|
||||
- **Test purpose / classification**: Feature guard tests for route/copy/helper contracts; Feature/Filament tests for affected labels/actions/pages; Browser tests only for affected smoke anchors; no Unit lane unless pure helper logic is touched.
|
||||
- **Validation lane(s)**: Feature/Guards, Feature/Localization, Feature/Filament, Feature/Workspaces, Feature/ProviderConnections, Feature/RequiredPermissions, affected Feature areas, and targeted Browser smoke anchors.
|
||||
- **Why this classification and these lanes are sufficient**: The risk is terminology, labels, selectors, and guard drift, not a new product workflow. Focused scans and existing affected suites prove the cleanup without pulling in unrelated full-suite repair.
|
||||
- **New or expanded test families**: possible focused guard assertions for terminology; no new permanent lane.
|
||||
- **Fixture / helper cost impact**: no new expensive setup. Existing `setAdminEnvironmentContext()` remains the current helper; do not introduce provider setup or browser defaults into cheap Feature tests.
|
||||
- **Heavy-family visibility / justification**: Browser lane is explicit and limited to smoke tests whose selectors/copy are touched.
|
||||
- **Special surface test profile**: `standard-native-filament`, `global-context-shell`, and `browser-smoke` for touched browser anchors.
|
||||
- **Standard-native relief or required special coverage**: ordinary Pest/Filament coverage is sufficient for copy-only native Filament updates unless browser-visible anchors change.
|
||||
- **Reviewer handoff**: Reviewers must confirm Filament v5 on Livewire v4.0+, panel providers remain registered through `apps/platform/bootstrap/providers.php`, globally searchable resources have Edit/View pages or disabled global search, touched destructive actions still use `->action(...)`, `->requiresConfirmation()`, and authorization, asset strategy is unchanged, and tests cover changed pages/actions/widgets through Livewire/Filament where applicable.
|
||||
- **Budget / baseline / trend impact**: no planned material runtime shift. Browser tests remain targeted; no blind timeout increases.
|
||||
- **Escalation needed**: document-in-feature for allowed technical/provider/historical tenant references; follow-up-spec only for structural DB/model rename or broader customer localization adoption.
|
||||
- **Active feature PR close-out entry**: Guardrail / Terminology Cleanup / Smoke Coverage.
|
||||
- **Planned validation commands**:
|
||||
|
||||
```bash
|
||||
cd apps/platform
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Guards
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Localization
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Workspaces
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions
|
||||
./vendor/bin/sail artisan test --compact tests/Feature/Filament
|
||||
./vendor/bin/sail artisan test --compact tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php
|
||||
./vendor/bin/sail bin pint --dirty --format agent
|
||||
git diff --check
|
||||
```
|
||||
|
||||
## Repo Baseline From Preparation
|
||||
|
||||
Read-only preparation scans on 2026-05-13 found:
|
||||
|
||||
- The active route/link source scan for retired route generators under `apps/platform/app`, `apps/platform/resources`, and `apps/platform/routes` returned no hits for `filament.admin.resources.tenants`, `/admin/tenants`, `/admin/t/`, direct legacy `TenantResource::getUrl(...)`, `TenantDashboard::getUrl(...)`, `TenantRequiredPermissions::getUrl(...)`, or tenant panel IDs.
|
||||
- `ManagedEnvironmentLinks` and `setAdminEnvironmentContext()` are repo-real and should remain the canonical route/helper vocabulary.
|
||||
- Remaining target copy hits exist in localization values, Blade copy, Filament/support copy, and tests. Representative hits include `Tenant scope`, `Select tenant`, `No tenant selected`, `No active tenants`, `Tenant dashboard`, `Open tenant detail`, `Restore tenant`, `Remove tenant assignment`, and `tenant blocker`.
|
||||
- `Spec288NoLegacyRouteAndHelperGuardTest.php` still contains `setTenantPanelContext` regex literals as forbidden-pattern checks. These are allowed only if the test description clearly says they forbid reintroducing the retired helper.
|
||||
|
||||
The implementation must refresh `terminology-audit.md` with full required scans before editing runtime code.
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Operators See Environment Vocabulary (Priority: P1)
|
||||
|
||||
As a workspace operator, I need active admin surfaces to describe current context as workspace, managed environment, or environment, not as a tenant panel.
|
||||
|
||||
**Why this priority**: This is the visible product truth after Spec 297.
|
||||
|
||||
**Independent Test**: Render affected shell/dashboard/detail/readiness surfaces and scan active UI/localization values for targeted tenant-first phrases.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a workspace-wide page with no environment selected, **When** the context copy renders, **Then** it says no environment is selected and does not say no tenant is selected.
|
||||
2. **Given** an environment dashboard/detail surface, **When** the heading, empty states, and helper text render, **Then** they use Environment or Managed environment wording.
|
||||
3. **Given** provider-specific Microsoft detail, **When** it refers to external Microsoft identity, **Then** Microsoft tenant ID or Entra tenant ID may remain.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Tests And Guards Describe Current Runtime Truth (Priority: P1)
|
||||
|
||||
As a maintainer, I need test names, helpers, and guard messages to use admin environment context vocabulary unless they are explicitly forbidding retired TenantPanel behavior.
|
||||
|
||||
**Why this priority**: Test vocabulary is a durable product contract for future agents and contributors.
|
||||
|
||||
**Independent Test**: Run the guard scans and focused guard tests; verify remaining `setTenantPanelContext` text appears only as forbidden legacy regex literals with clear descriptions.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** `tests/Pest.php`, **When** helper names are scanned, **Then** the active helper is `setAdminEnvironmentContext()` or equivalent current vocabulary with no `setTenantPanelContext()` alias.
|
||||
2. **Given** Spec 288 guard tests, **When** they retain `setTenantPanelContext` regex literals, **Then** the test description and failure message state that the retired helper must not be reintroduced.
|
||||
3. **Given** feature/browser tests for current admin environment flows, **When** their names and assertions are reviewed, **Then** they do not describe the current runtime as tenant panel context.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Browser Smokes Remain Stable After Copy Cleanup (Priority: P2)
|
||||
|
||||
As a maintainer, I need browser smokes to follow stable current selectors or intentionally stable current copy without increasing timeouts.
|
||||
|
||||
**Why this priority**: Copy cleanup should not make the browser lane brittle.
|
||||
|
||||
**Independent Test**: Run affected browser smokes individually after selector/copy updates.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a smoke test that previously clicked old tenant copy, **When** the target UI has a stable `data-testid`, **Then** the smoke uses that selector.
|
||||
2. **Given** a smoke test that asserts current UI copy, **When** the copy is a product contract, **Then** the assertion uses the new environment wording.
|
||||
3. **Given** an affected browser smoke, **When** it is updated, **Then** no timeout is raised without a documented timing cause.
|
||||
|
||||
## Functional Requirements
|
||||
|
||||
- **FR-001 Initial scan before changes**: Before implementation edits, run the status, route, source, test, and copy scans listed in `plan.md` and record results in `terminology-audit.md`.
|
||||
- **FR-002 Guard literals updated**: `Spec288NoLegacyRouteAndHelperGuardTest.php` must not present `setTenantPanelContext` as a current helper. It may retain the regex only as an explicit forbidden legacy pattern.
|
||||
- **FR-003 Test helper terminology finalized**: Current tests must use admin/managed-environment context wording and active helper names such as `setAdminEnvironmentContext()`.
|
||||
- **FR-004 User-facing tenant copy neutralized**: Active UI copy for the targeted phrases must move to Environment or Managed Environment vocabulary, except provider-specific Microsoft/Entra terms.
|
||||
- **FR-005 Filament labels and actions cleaned**: Page titles, navigation labels, breadcrumbs, action labels, empty states, helper texts, badge labels, modal headings, and notifications in active surfaces must not use old tenant-first product language.
|
||||
- **FR-006 Blade/context-bar copy cleaned**: Active Blade and Filament partials must use environment context wording and avoid class-name-like visible copy.
|
||||
- **FR-007 Localization values cleaned**: Existing EN/DE localization values must output current vocabulary. Key renames are optional and only allowed when all usages are safely updated.
|
||||
- **FR-008 Browser smokes updated**: Affected smokes must use stable selectors or current copy, with no blind timeout increases.
|
||||
- **FR-009 Allowed exceptions documented**: Remaining tenant-related hits must be categorized in `terminology-audit.md`.
|
||||
- **FR-010 No active legacy route reintroduced**: Final route/source scans must remain clean for `/admin/t...`, `/admin/tenants...`, old URL generators, tenant panel IDs, and `setTenantPanelContext()` in runtime surfaces.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- **AC-001**: Source scan is clean for active old TenantPanel route/generator patterns in `app`, `resources`, and `routes`.
|
||||
- **AC-002**: Test helper scan is clean or contains only explicit forbidden legacy guard literals with clear descriptions.
|
||||
- **AC-003**: Targeted tenant-first copy is absent from active UI surfaces or documented as provider-specific, internal, historical, or regression-guard-only.
|
||||
- **AC-004**: `terminology-audit.md` documents every remaining allowed tenant reference found by final scans.
|
||||
- **AC-005**: Route scan does not show active `/admin/t...` or `/admin/tenants...` product routes.
|
||||
- **AC-006**: Spec 297 route/runtime proof remains intact.
|
||||
- **AC-007**: Canonical browser anchors pass when affected.
|
||||
- **AC-008**: Pint dirty and `git diff --check` pass.
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
- DB table rename
|
||||
- `Tenant` model rename
|
||||
- `tenant_id` column rename
|
||||
- migration rewrite
|
||||
- historical spec rewrite
|
||||
- broad docs cleanup
|
||||
- new localization architecture
|
||||
- new customer workspace feature
|
||||
- new decision inbox feature
|
||||
- new routing model
|
||||
- new RBAC model
|
||||
- new provider abstraction
|
||||
- UI redesign
|
||||
- reactivation of `/admin/t...`, `/admin/tenants...`, `TenantPanelProvider`, or `setTenantPanelContext()`
|
||||
|
||||
## Risks
|
||||
|
||||
- Some localization keys still contain `tenant_*`; changing keys broadly could create avoidable risk. Values should be updated first unless key rename is proven bounded.
|
||||
- Some visible `tenant` terms may be valid provider-specific Microsoft/Entra terminology. The audit must distinguish provider truth from product vocabulary.
|
||||
- Browser smokes may rely on old visible text. Prefer stable selectors where the copy is not the contract.
|
||||
- Guard regex literals can look like drift if test names/messages are ambiguous. Clarify the guard contract rather than weakening it.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- Spec 297 has retired active route/runtime legacy surfaces and `ManagedEnvironmentLinks` is the canonical URL owner.
|
||||
- The repo remains pre-production, so old compatibility aliases are not required.
|
||||
- The active product mental model is Workspace first, then Managed Environment / Environment context.
|
||||
- Internal technical names may remain until a separate DB/model rename spec exists.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- None blocking preparation. Implementation must update the audit if scans reveal an active visible tenant-first phrase outside the targeted list that is clearly current product UX.
|
||||
|
||||
## Follow-Up Spec Candidates
|
||||
|
||||
- Structural DB/model rename from `Tenant` to `ManagedEnvironment`, if product and persistence maturity require it later.
|
||||
- Broader customer-facing localization adoption beyond the targeted cleanup, aligned with the existing localization roadmap.
|
||||
- Historical docs/spec cleanup, if the repository later decides historical artifacts should be normalized separately.
|
||||
153
specs/298-managed-environment-terminology-copy-cleanup/tasks.md
Normal file
153
specs/298-managed-environment-terminology-copy-cleanup/tasks.md
Normal file
@ -0,0 +1,153 @@
|
||||
---
|
||||
description: "Task list for Managed Environment Terminology & Copy Cleanup"
|
||||
---
|
||||
|
||||
# Tasks: Managed Environment Terminology & Copy Cleanup
|
||||
|
||||
**Input**: Design documents from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/298-managed-environment-terminology-copy-cleanup/`
|
||||
**Prerequisites**: `spec.md`, `plan.md`, `terminology-audit.md`, `checklists/requirements.md`
|
||||
|
||||
**Tests**: Required (Pest) for guard/test/localization/copy changes. Browser smoke is required only if visible browser anchors/selectors are touched.
|
||||
**Operations**: No new `OperationRun` behavior. Existing operation links and copy must keep the shared OperationRun UX contract if touched.
|
||||
**RBAC**: No authorization model change. Existing 404/403 semantics, capability checks, and destructive action authorization must remain intact.
|
||||
**Filament / Panel Guardrails**: Filament remains v5 on Livewire v4. Provider registration remains in `apps/platform/bootstrap/providers.php`. No new panel. No asset-strategy change unless explicitly documented.
|
||||
**Review Outcome**: preparation-ready
|
||||
**Workflow Outcome**: keep
|
||||
**Test-governance Outcome**: keep
|
||||
|
||||
## Test Governance Checklist
|
||||
|
||||
- [x] Lane assignment is named and is the narrowest sufficient proof for each changed behavior.
|
||||
- [x] New or changed tests stay in the smallest honest family; browser/heavy-governance additions are explicit.
|
||||
- [x] Shared helpers, factories, seeds, fixtures, provider setup, workspace context, session state, and capability defaults stay cheap by default.
|
||||
- [x] Planned validation commands cover terminology, route guard, helper, and browser-anchor changes without pulling in unrelated lane cost.
|
||||
- [x] The declared surface test profile or `standard-native-filament` relief is explicit.
|
||||
- [x] Any material runtime, budget, baseline, trend, or escalation note is recorded in the active spec close-out.
|
||||
|
||||
## Phase 1: Safety Gate And Baseline Audit
|
||||
|
||||
**Purpose**: Start from a clean branch and record repo truth before runtime edits.
|
||||
|
||||
- [x] T001 Run `git status --short --branch`, `git diff --stat`, and `git log -1 --oneline` in `/Users/ahmeddarrazi/Documents/projects/wt-plattform`; stop if unrelated uncommitted changes are present.
|
||||
- [x] T002 Confirm the implementation branch is `298-managed-environment-terminology-copy-cleanup` or an isolated session branch derived from it.
|
||||
- [x] T003 Review `/Users/ahmeddarrazi/Documents/projects/wt-plattform/.specify/memory/constitution.md`, this spec package, and related Specs 286, 288, and 297 as context only.
|
||||
- [x] T004 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan route:list | rg "admin/tenants|admin/t/" && exit 1 || true`.
|
||||
- [x] T005 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && rg "filament\\.admin\\.resources\\.tenants|/admin/tenants|/admin/t/|TenantResource::getUrl|TenantDashboard::getUrl|TenantRequiredPermissions::getUrl|setTenantPanelContext|panel:\\s*'tenant'|panel:\\s*\\\"tenant\\\"" app resources routes --glob '!vendor' --glob '!node_modules'`.
|
||||
- [x] T006 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && rg "setTenantPanelContext|panel:\\s*'tenant'|panel:\\s*\\\"tenant\\\"" tests --glob '!vendor' --glob '!node_modules'`.
|
||||
- [x] T007 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && rg "Tenant dashboard|Tenant detail|Open tenant|Select tenant|Tenant scope|No tenant selected|No active tenants|Remove tenant|Restore tenant|Tenant memberships|tenant blocker" app resources lang tests --glob '!vendor' --glob '!node_modules'`.
|
||||
- [x] T008 Update `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/298-managed-environment-terminology-copy-cleanup/terminology-audit.md` with every initial finding before editing application code.
|
||||
- [x] T009 Confirm the scope boundary remains explicit: no DB/model rename, no migration rewrite, no old route restoration, no helper alias, no broad localization architecture, and no UI redesign.
|
||||
|
||||
## Phase 2: Guard And Test Helper Terminology
|
||||
|
||||
**Goal**: Make current test vocabulary match admin environment context while retaining explicit retired-helper guards.
|
||||
|
||||
- [x] T010 [P] Inspect `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Pest.php` and confirm `setAdminEnvironmentContext()` is the active helper and `setTenantPanelContext()` is absent.
|
||||
- [x] T011 [P] Inspect `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php` for `setTenantPanelContext` forbidden-pattern literals.
|
||||
- [x] T012 Update Spec 288 guard test names, comments, and failure messages so any remaining `setTenantPanelContext` regex literal clearly forbids reintroducing the retired tenant panel context helper.
|
||||
- [x] T013 Update active test names/comments that describe current runtime setup as `tenant panel`, `tenant panel context`, `panel tenant`, or equivalent legacy wording.
|
||||
- [x] T014 Ensure no compatibility alias named `setTenantPanelContext()` is introduced.
|
||||
- [x] T015 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php`.
|
||||
- [x] T016 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards`.
|
||||
|
||||
## Phase 3: Localization Values
|
||||
|
||||
**Goal**: Make EN/DE values output environment-first product language.
|
||||
|
||||
- [x] T017 [P] Audit `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/lang/en/localization.php` for targeted tenant-first values.
|
||||
- [x] T018 [P] Audit `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/lang/de/localization.php` for targeted tenant-first values.
|
||||
- [x] T019 Update EN shell/dashboard/support/customer-visible values so active generic UI says environment or managed environment instead of tenant-first wording.
|
||||
- [x] T020 Update DE shell/dashboard/support/customer-visible values with equivalent environment wording.
|
||||
- [x] T021 Keep existing localization keys if renaming them would broaden scope; update visible values first.
|
||||
- [x] T022 If any key is renamed, update all usages and tests in the same phase.
|
||||
- [x] T023 Update localization tests under `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Localization` and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards` that assert old copy.
|
||||
- [x] T024 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Localization`.
|
||||
|
||||
## Phase 4: Active UI Copy In App And Views
|
||||
|
||||
**Goal**: Replace targeted tenant-first visible copy in active Filament, Blade, support, and service surfaces.
|
||||
|
||||
- [x] T025 [P] Audit `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/resources/views/filament/partials/context-bar.blade.php` and other active context-bar/shell views for visible `Tenant scope`, `No tenant selected`, and `Open tenant` wording.
|
||||
- [x] T026 [P] Audit `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/resources/views/filament/pages/monitoring/finding-exceptions-queue.blade.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/resources/views/filament/pages/tenant-required-permissions.blade.php`.
|
||||
- [x] T027 [P] Audit `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Pages/Monitoring/FindingExceptionsQueue.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php`, and relevant `app/Filament/**` surfaces for targeted labels/actions/headings.
|
||||
- [x] T028 [P] Audit `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/**` and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Services/**` for emitted visible copy such as `Restore tenant`, `No tenant selected`, and `tenant blocker`.
|
||||
- [x] T029 Replace active visible `Open tenant detail`, `Open tenant compare`, and similar labels with `Open environment ...` wording unless the target is provider-specific Microsoft tenant detail.
|
||||
- [x] T030 Replace active visible `Tenant scope`, `Select tenant`, `No tenant selected`, and `No active tenants` with environment wording.
|
||||
- [x] T031 Replace active visible `Remove tenant`, `Restore tenant`, and `Tenant memberships` with environment/access-scope wording while preserving destructive action confirmation and authorization.
|
||||
- [x] T032 Replace active visible `tenant blocker` or similar dashboard/readiness phrasing with environment wording.
|
||||
- [x] T033 Preserve provider-specific phrases such as Microsoft tenant ID and Entra tenant ID when the external provider is the subject.
|
||||
- [x] T034 Update affected Feature/Filament tests to assert current copy or stable semantics.
|
||||
|
||||
## Phase 5: Browser Smoke Selectors
|
||||
|
||||
**Goal**: Keep browser smoke tests stable after copy changes.
|
||||
|
||||
- [x] T035 [P] Audit `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php`.
|
||||
- [x] T036 [P] Audit `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php`.
|
||||
- [x] T037 [P] Audit `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Browser/Spec192RecordPageHeaderDisciplineSmokeTest.php` and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Browser/Dashboard/TenantDashboardProductizationSmokeTest.php` if copy changes affect them.
|
||||
- [x] T038 Prefer stable `data-testid` selectors for changed click targets when copy is not the product contract.
|
||||
- [x] T039 If adding a new `data-testid`, keep it narrowly scoped to the existing element and avoid layout/style changes.
|
||||
- [x] T040 Do not increase browser timeouts unless a real timing cause is identified and documented.
|
||||
- [x] T041 Run each affected browser test individually before the final browser anchor command.
|
||||
|
||||
## Phase 6: Audit Exceptions And Final Scans
|
||||
|
||||
**Goal**: Ensure every remaining tenant reference is intentional and documented.
|
||||
|
||||
- [x] T042 Run the final route scan: `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan route:list | rg "admin/tenants|admin/t/" && exit 1 || true`.
|
||||
- [x] T043 Run the final source scan from T005 and ensure it is clean or documented with explicit allowed technical exceptions.
|
||||
- [x] T044 Run the final test-helper scan from T006 and ensure only explicit forbidden-legacy guard literals remain.
|
||||
- [x] T045 Run the final copy scan from T007 and ensure every remaining hit is absent or documented.
|
||||
- [x] T046 Update `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/298-managed-environment-terminology-copy-cleanup/terminology-audit.md` with categories for every remaining hit: `fixed`, `allowed-provider-term`, `allowed-internal-model`, `allowed-historical`, `allowed-regression-guard`, `out-of-scope-db-model-rename`, or `needs-follow-up`.
|
||||
- [x] T047 Confirm no active runtime route, provider, compatibility alias, or global-search route regression from Spec 297 was reintroduced.
|
||||
|
||||
## Phase 7: Proof Pack And Formatting
|
||||
|
||||
**Goal**: Prove focused lanes remain green.
|
||||
|
||||
**Close-out note**: The full Filament feature lane was rerun after formatting and the terminology fixes. It completed with one order-sensitive failure in `tests/Feature/Filament/GovernanceArtifacts/GovernanceArtifactEnvironmentContextTest.php` where `ReviewPackResource::executeGeneration()` did not create a `ReviewPack` during the full suite; the same test file passed immediately when run alone. No changed implementation file participates in that governance artifact generation path, so this is recorded as residual non-terminology test-order risk rather than an in-scope Spec 298 finding.
|
||||
|
||||
- [x] T048 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards`.
|
||||
- [x] T049 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Localization`.
|
||||
- [x] T050 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces`.
|
||||
- [x] T051 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections`.
|
||||
- [x] T052 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions`.
|
||||
- [x] T053 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament`.
|
||||
- [x] T054 If browser files or visible browser anchors changed, run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php` plus any touched browser file.
|
||||
- [x] T055 Run `cd /Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`.
|
||||
- [x] T056 Run `git diff --check` from `/Users/ahmeddarrazi/Documents/projects/wt-plattform`.
|
||||
|
||||
## Phase 8: Close-Out Summary
|
||||
|
||||
**Goal**: Finish with a reviewer-ready proof summary and decision.
|
||||
|
||||
- [x] T057 Confirm the Filament v5 output contract in the final implementation summary: Livewire v4.0+ compliance, provider registration in `bootstrap/providers.php`, global-search handling, destructive action confirmation/authorization, asset strategy, and testing plan.
|
||||
- [x] T058 Record commands run and results in the final implementation summary.
|
||||
- [x] T059 Record fixed terminology groups with before/after examples.
|
||||
- [x] T060 Record remaining allowed references and reasons from `terminology-audit.md`.
|
||||
- [x] T061 Choose one final decision string: `298 merge-ready; terminology cleanup complete`, `298 merge-ready with documented allowed technical tenant references`, `298 blocked by active legacy tenant copy`, or `298 blocked by runtime legacy regression`.
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
- Phase 1 blocks all runtime edits.
|
||||
- Phase 2 can run in parallel with Phase 3 after Phase 1 completes.
|
||||
- Phase 4 depends on the audit from Phase 1 and may proceed alongside localization updates if file ownership stays clear.
|
||||
- Phase 5 depends on knowing whether copy changes touched browser-visible anchors.
|
||||
- Phase 6 must run after all copy/test updates.
|
||||
- Phase 7 and Phase 8 close the proof loop.
|
||||
|
||||
## Parallel Execution Examples
|
||||
|
||||
- T010 and T017 can run in parallel because test-helper inspection and localization inspection touch different files.
|
||||
- T025, T026, T027, and T028 can run in parallel because they audit different UI/code surfaces.
|
||||
- T035 and T036 can run in parallel because the browser smoke files are independent.
|
||||
|
||||
## Explicit Follow-Ups / Out of Scope
|
||||
|
||||
- Database/model rename from `Tenant` to `ManagedEnvironment`
|
||||
- Broad localization v1 or customer-facing localization adoption
|
||||
- Historical spec/doc rewrite
|
||||
- New customer review workspace or decision inbox
|
||||
- New RBAC or provider abstraction
|
||||
- UI redesign
|
||||
- Reactivation of `/admin/t...`, `/admin/tenants...`, `TenantPanelProvider`, or `setTenantPanelContext()`
|
||||
@ -0,0 +1,82 @@
|
||||
# Terminology Audit: Managed Environment Terminology & Copy Cleanup
|
||||
|
||||
**Feature**: `298-managed-environment-terminology-copy-cleanup`
|
||||
**Created**: 2026-05-13
|
||||
**Status**: Implemented close-out. Final scans refreshed on 2026-05-13.
|
||||
|
||||
## Categories
|
||||
|
||||
| Category | Meaning |
|
||||
|---|---|
|
||||
| `fixed` | The implementation replaced or removed the old tenant-first wording. |
|
||||
| `allowed-provider-term` | The term describes external Microsoft/Entra provider truth, such as Microsoft tenant ID. |
|
||||
| `allowed-internal-model` | The term is an internal model/class/table/column name and DB/model rename is out of scope. |
|
||||
| `allowed-historical` | The term appears in historical specs/docs/audit history that this spec does not rewrite. |
|
||||
| `allowed-regression-guard` | The term is kept only as a forbidden legacy pattern in a guard test. |
|
||||
| `out-of-scope-db-model-rename` | The term requires a structural DB/model rename outside Spec 298. |
|
||||
| `needs-follow-up` | The term is real drift but cannot be safely fixed inside Spec 298. |
|
||||
|
||||
## Implementation Baseline Scan
|
||||
|
||||
Read-only implementation scans were refreshed on 2026-05-13 before application edits.
|
||||
|
||||
| Command | Result | Decision |
|
||||
|---|---|---|
|
||||
| `git status --short --branch && git diff --stat && git log -1 --oneline` | Active branch is `298-managed-environment-terminology-copy-cleanup`; only the active spec package was untracked before audit edit; base commit `3ec582a1 feat: retire legacy tenant route surfaces (#352)`. | Safe to continue because the untracked files are the active prepared spec artifacts. |
|
||||
| `cd apps/platform && ./vendor/bin/sail artisan route:list \| rg "admin/tenants\|admin/t/" && exit 1 \|\| true` | No output; no active route-list matches for retired route families. | Route baseline clean. |
|
||||
| `cd apps/platform && rg "filament\\.admin\\.resources\\.tenants\|/admin/tenants\|/admin/t/\|TenantResource::getUrl\|TenantDashboard::getUrl\|TenantRequiredPermissions::getUrl\|setTenantPanelContext\|panel:\\s*'tenant'\|panel:\\s*\\\"tenant\\\"" app resources routes --glob '!vendor' --glob '!node_modules'` | No output; no active runtime source matches in `app`, `resources`, or `routes`. | Source baseline clean. |
|
||||
| `cd apps/platform && rg "setTenantPanelContext\|panel:\\s*'tenant'\|panel:\\s*\\\"tenant\\\"" tests --glob '!vendor' --glob '!node_modules'` | Five `setTenantPanelContext` regex literals remain in `tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php`. | Allowed only as regression-guard literals after wording clarification. |
|
||||
| `cd apps/platform && rg "Tenant dashboard\|Tenant detail\|Open tenant\|Select tenant\|Tenant scope\|No tenant selected\|No active tenants\|Remove tenant\|Restore tenant\|Tenant memberships\|tenant blocker" app resources lang tests --glob '!vendor' --glob '!node_modules'` | Targeted active copy/test hits listed below. | In-scope cleanup targets except provider/internal/historical references. |
|
||||
|
||||
### Baseline Findings To Fix
|
||||
|
||||
| Pattern | File | Category | Decision | Reason |
|
||||
|---|---|---|---|---|
|
||||
| `Tenant scope`, `Select tenant`, `No tenant selected`, `No active tenants`, `Tenant dashboard`, `tenant blocker` | `apps/platform/lang/en/localization.php` | fixed | planned | Active localization values should output environment-first wording. Existing keys may remain if key rename is risky. |
|
||||
| German tenant-first equivalents for context/dashboard copy | `apps/platform/lang/de/localization.php` | fixed | planned | Active DE localization values should output environment-first wording. |
|
||||
| `Open tenant detail` | `apps/platform/resources/views/filament/pages/monitoring/finding-exceptions-queue.blade.php` | fixed | planned | Active view copy should say `Open environment detail` unless provider-specific. |
|
||||
| `Open tenant compare` | `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php` | fixed | planned | Baseline compare is an environment-context action after cutover. |
|
||||
| `No tenant selected.` | `apps/platform/resources/views/filament/pages/tenant-required-permissions.blade.php` | fixed | planned | Required permissions page should describe missing environment context. |
|
||||
| `Restore tenant` | `apps/platform/app/Services/Tenants/TenantActionPolicySurface.php` | fixed | planned | Visible operator copy should say restore environment while preserving confirmation/authorization. |
|
||||
| `Restore tenant` | `apps/platform/app/Support/Ui/GovernanceActions/GovernanceActionCatalog.php` | fixed | planned | Governance action copy should say restore environment while preserving confirmation/authorization. |
|
||||
| `Open tenant detail` | `apps/platform/app/Filament/Pages/Monitoring/FindingExceptionsQueue.php` | fixed | planned | Active action label should use environment wording. |
|
||||
| `Open tenant findings` | `apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php`, `apps/platform/tests/Feature/Findings/MyWorkInboxTest.php` | fixed | planned | Active action label should use environment wording if it targets environment-scoped findings. |
|
||||
| `No tenant selected` | `apps/platform/app/Filament/Resources/BackupScheduleResource.php` | fixed | planned | Backup schedule context copy should use environment wording. |
|
||||
| `Remove tenant assignment` | `apps/platform/app/Filament/Resources/BaselineProfileResource/RelationManagers/BaselineTenantAssignmentsRelationManager.php` | fixed | planned | Visible destructive label should use environment assignment wording while preserving confirmation/authorization. |
|
||||
| `No tenant selected.` | `apps/platform/app/Support/Baselines/BaselineCompareStats.php` | fixed | planned | Empty compare state should use environment context wording. |
|
||||
| Old-copy assertions | `apps/platform/tests/Feature/Localization/EnvironmentContextTerminologyTest.php`, `apps/platform/tests/Feature/Guards/EnvironmentCopyNeutralizationGuardTest.php` | fixed | planned | Tests should assert current environment vocabulary and forbid retired product copy. |
|
||||
| `setTenantPanelContext` regex literals | `apps/platform/tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php` | allowed-regression-guard | clarify | May remain only as explicit forbidden legacy pattern. Test names/messages must not suggest a current helper. |
|
||||
|
||||
## Final Audit
|
||||
|
||||
| Pattern | File | Category | Decision | Reason |
|
||||
|---|---|---|---|---|
|
||||
| Retired route families `/admin/tenants` and `/admin/t/` | `apps/platform` route list | fixed | clean | Final route scan returned no matches. |
|
||||
| Retired tenant panel route/helper patterns from T005 | `apps/platform/app`, `apps/platform/resources`, `apps/platform/routes` | fixed | clean | Final source scan returned no matches for retired route names, helper names, tenant panel provider usage, or tenant-panel route generation. |
|
||||
| `setTenantPanelContext` | `apps/platform/tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php` | allowed-regression-guard | keep | Remaining hits are forbidden-pattern regex literals and a clarified failure message preventing reintroduction of the retired helper. |
|
||||
| `Tenant scope`, `Select tenant`, `No tenant selected`, `No active tenants`, `Tenant dashboard`, `tenant blocker` | `apps/platform/lang/en/localization.php`, `apps/platform/lang/de/localization.php`, context/support tests | fixed | complete | Active localization values now use environment/managed-environment wording. Existing key names remain where key renames would broaden scope. |
|
||||
| Finding queue and governance inbox tenant-first labels | `apps/platform/app/Filament/Pages/**`, `apps/platform/resources/views/filament/pages/**`, related tests | fixed | complete | Active visible labels now say environment detail, environment findings, environment filter, or environment scope as appropriate. |
|
||||
| Baseline compare tenant-first labels and empty states | `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php`, `apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/ViewBaselineProfile.php`, `apps/platform/app/Support/Baselines/**`, `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php`, related tests | fixed | complete | Visible compare labels now say assigned environments, visible assigned environments, and multi-environment scan. Internal action IDs and model names remain unchanged. |
|
||||
| Destructive governance/environment action copy | `apps/platform/app/Services/Tenants/TenantActionPolicySurface.php`, `apps/platform/app/Support/Ui/GovernanceActions/GovernanceActionCatalog.php`, `apps/platform/app/Filament/Resources/BaselineProfileResource/RelationManagers/BaselineTenantAssignmentsRelationManager.php` | fixed | complete | Visible copy now says restore/archive/remove environment assignment while existing `->action(...)`, `->requiresConfirmation()`, and authorization surfaces remain intact. |
|
||||
| Old product-copy strings in copy scan | `apps/platform/tests/Feature/Localization/EnvironmentContextTerminologyTest.php`, `apps/platform/tests/Feature/Guards/EnvironmentCopyNeutralizationGuardTest.php` | allowed-regression-guard | keep | Final copy scan hits are forbidden strings used only by regression guards/assertions to ensure active UI does not reintroduce them. |
|
||||
| Microsoft tenant / Entra tenant identifiers | Provider/auth/Graph-facing code and tests | allowed-provider-term | keep | These terms describe external Microsoft provider concepts and are not product context labels. |
|
||||
| `Tenant`, `tenant_id`, `tenantRouteKey`, `TenantResource`, tenant review model/resource names | Models, resources, relations, fixtures, historical test names | allowed-internal-model | keep | DB/model/resource rename is explicitly out of scope for Spec 298. Runtime routes were not restored. |
|
||||
| Historical specs, archived decision context, and prior spec names | `specs/**`, `.specify/**`, historical tests where applicable | allowed-historical | keep | This cleanup does not rewrite historical records or prior spec names. |
|
||||
|
||||
## Final Verification Evidence
|
||||
|
||||
| Command | Result |
|
||||
|---|---|
|
||||
| `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards` | Passed: 265 tests, 4705 assertions. |
|
||||
| `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Localization` | Passed: 16 tests, 95 assertions after updating stale German auth copy expectation. |
|
||||
| `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces` | Passed: 96 tests, 276 assertions. |
|
||||
| `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections` | Passed: 78 tests, 588 assertions. |
|
||||
| `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions` | Passed: 21 tests, 82 assertions. |
|
||||
| `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament` | Rerun after formatting completed with 764 passed, 5 skipped, 1 failed. The failure was an order-sensitive `ReviewPack` creation assertion in `GovernanceArtifactEnvironmentContextTest`, outside changed terminology code. |
|
||||
| `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/GovernanceArtifacts/GovernanceArtifactEnvironmentContextTest.php` | Passed: 5 tests, 12 assertions immediately after the full-suite failure. |
|
||||
| `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php tests/Browser/Dashboard/TenantDashboardProductizationSmokeTest.php` | Passed: 6 tests, 105 assertions. |
|
||||
| `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` | Passed. |
|
||||
|
||||
## Residual Risk
|
||||
|
||||
The only remaining validation issue is the order-sensitive full Filament lane failure documented above. It does not touch the Spec 298 terminology files and passes in isolation, so it is not treated as an in-scope terminology finding. It should be tracked separately if full-suite determinism is required before merge.
|
||||
Loading…
Reference in New Issue
Block a user