TenantAtlas/apps/platform/app/Support/Operations/LifecycleReconciliationReason.php
ahmido ad16eee591 Spec 204: harden platform core vocabulary (#234)
## Summary
- add the Spec 204 platform vocabulary foundation, including canonical glossary terms, registry ownership descriptors, canonical operation type and alias resolution, and explicit reason ownership and platform reason-family metadata
- harden platform-facing compare, snapshot, evidence, monitoring, review, and reporting surfaces so they prefer governed-subject and canonical operation semantics while preserving intentional Intune-owned terminology
- extend Spec 204 unit, feature, Filament, and architecture coverage and add the full spec artifacts, checklist, and completed task ledger

## Verification
- ran the focused recent-change Sail verification pack for the new glossary and reason-semantics work
- ran the full Spec 204 quickstart verification pack under Sail
- ran `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- ran an integrated-browser smoke pass covering tenant dashboard, operations, operation detail, baseline compare, evidence, reviews, review packs, provider connections, inventory items, backup schedules, onboarding, and the system dashboard/operations/failures/run-detail surfaces

## Notes
- provider registration is unchanged and remains in `bootstrap/providers.php`
- no new destructive actions or asset-registration changes are introduced by this branch

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #234
2026-04-14 06:09:42 +00:00

92 lines
3.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Support\Operations;
use App\Support\ReasonTranslation\NextStepOption;
use App\Support\ReasonTranslation\PlatformReasonFamily;
use App\Support\ReasonTranslation\ReasonOwnershipDescriptor;
use App\Support\ReasonTranslation\ReasonResolutionEnvelope;
enum LifecycleReconciliationReason: string
{
case StaleQueued = 'run.stale_queued';
case StaleRunning = 'run.stale_running';
case InfrastructureTimeoutOrAbandonment = 'run.infrastructure_timeout_or_abandonment';
case QueueFailureBridge = 'run.queue_failure_bridge';
case AdapterOutOfSync = 'run.adapter_out_of_sync';
public function operatorLabel(): string
{
return match ($this) {
self::StaleQueued => 'Run never started',
self::StaleRunning => 'Run stopped reporting progress',
self::InfrastructureTimeoutOrAbandonment => 'Infrastructure ended the run',
self::QueueFailureBridge => 'Queue failure was reconciled',
self::AdapterOutOfSync => 'Lifecycle was reconciled from related records',
};
}
public function shortExplanation(): string
{
return match ($this) {
self::StaleQueued => 'The run stayed queued past its lifecycle window and was marked failed.',
self::StaleRunning => 'The run stayed active past its lifecycle window and was marked failed.',
self::InfrastructureTimeoutOrAbandonment => 'Queue infrastructure ended the job before normal completion could update the run.',
self::QueueFailureBridge => 'The platform bridged a queue failure back to the owning run and marked it failed.',
self::AdapterOutOfSync => 'A related restore record reached terminal truth before the operation run was updated.',
};
}
public function actionability(): string
{
return match ($this) {
self::AdapterOutOfSync => 'non_actionable',
default => 'retryable_transient',
};
}
/**
* @return array<int, NextStepOption>
*/
public function nextSteps(): array
{
return match ($this) {
self::AdapterOutOfSync => [
NextStepOption::instruction('Review the related restore record before deciding whether to run the workflow again.'),
],
default => [
NextStepOption::instruction('Review worker health and logs before retrying this operation.'),
],
};
}
public function defaultMessage(): string
{
return $this->shortExplanation();
}
/**
* @param array<string, mixed> $context
*/
public function toReasonResolutionEnvelope(string $surface = 'detail', array $context = []): ReasonResolutionEnvelope
{
return new ReasonResolutionEnvelope(
internalCode: $this->value,
operatorLabel: $this->operatorLabel(),
shortExplanation: $this->shortExplanation(),
actionability: $this->actionability(),
nextSteps: $this->nextSteps(),
showNoActionNeeded: false,
diagnosticCodeLabel: $this->value,
reasonOwnership: new ReasonOwnershipDescriptor(
ownerLayer: 'platform_core',
ownerNamespace: 'operation_lifecycle',
reasonCode: $this->value,
platformReasonFamily: PlatformReasonFamily::Execution,
),
);
}
}