TenantAtlas/specs/239-canonical-operation-type-source-of-truth/spec.md
ahmido fb32e9bfa5
Some checks failed
Main Confidence / confidence (push) Failing after 49s
feat: canonical operation type source of truth (#276)
## Summary
- implement the canonical operation type source-of-truth slice across operation writers, monitoring surfaces, onboarding flows, and supporting services
- add focused contract and regression coverage for canonical operation type handling
- include the generated spec 239 artifacts for the feature slice

## Validation
- browser smoke PASS for `/admin` -> workspace overview -> operations -> operation detail -> tenant-scoped operations drilldown
- spec/plan/tasks/quickstart artifact analysis cleaned up to a no-findings state
- automated test suite not run in this session

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #276
2026-04-25 18:11:23 +00:00

49 KiB

Feature Specification: Canonical Operation Type Source of Truth

Feature Branch: 239-canonical-operation-type-source-of-truth
Created: 2026-04-25
Status: Implemented
Input: User description: "Canonical Operation Type Source of Truth"
Mode: Implementation close-out. This artifact now records the scoped contract, guardrails, acceptance criteria, and validation basis for the implemented slice.

Spec Candidate Check (mandatory — SPEC-GATE-001)

  • Problem: The repo still has two competing truths for the same platform-owned operation identity: canonical dotted operation_type codes in the catalog and multiple raw storage or enum values such as inventory_sync, baseline_capture, entra_group_sync, and backup_schedule_run in in-scope writers and persisted workflow state.
  • Today's failure: The same operation family can be started, persisted, filtered, audited, or reviewed under different identifiers, which teaches the wrong platform contract, makes rollout guards weaker, and lets monitoring, onboarding, provider dispatch, and read models drift apart.
  • User-visible improvement: Operators and reviewers see one consistent operation identity across monitoring, onboarding, reporting, filters, and audit-adjacent surfaces, while historical rows continue to resolve correctly during the bounded rollout seam.
  • Smallest enterprise-capable version: Promote the existing dotted catalog codes to the single normative operation_type contract, converge the current write owners around that contract, and allow only a narrowly bounded read-side compatibility seam for historical rows and draft state encountered during rollout.
  • Architecture center: The primary deliverable is one platform-owned operation_type contract. Surface consistency, filter convergence, and drift guards are acceptance evidence for that contract, not a justification for new framework layers.
  • Explicit non-goals: No new tables, no new operation family, no monitoring information-architecture redesign, no broad governed-subject vocabulary cleanup, no provider-neutral rewrite of every domain-specific operation name, and no long-lived dual-write or alias-preservation framework.
  • Permanent complexity imported: One explicit single-source contract for operation_type, one temporary read-side compatibility seam during rollout, and focused guard coverage that blocks new raw alias writers from reappearing.
  • Why now: This is the next unresolved anti-drift hotspot in the active governance hardening lane after Specs 237 and 238. The repo already classifies operation_type as a platform-core canonical noun, and later governed-subject vocabulary work depends on stabilizing this contract first.
  • Why not local: The inconsistency is not isolated to one label or page. It crosses enum-backed writes, provider operation definitions, onboarding bootstrap workflow state, operation run read models, filter catalogs, audit metadata, and supporting guard tests.
  • Approval class: Core Enterprise
  • Red flags triggered: Foundation-sounding scope, many affected surfaces, and contract hardening in a shared platform seam. Defense: the slice stays tightly bounded to one already-existing contract, introduces no new persistence or framework, and prefers replacement over compatibility scaffolding.
  • Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexität: 1 | Produktnähe: 1 | Wiederverwendung: 2 | Gesamt: 10/12
  • Decision: approve

Spec Scope Fields (mandatory)

  • Scope: workspace, tenant, canonical-view, platform
  • Primary Routes:
    • Existing workspace-admin Operations collection and drill-in surfaces anchored on /admin/operations
    • Existing workspace-admin onboarding flow at /admin/onboarding
    • Existing system Operations pages at /system/ops/runs, /system/ops/failures, /system/ops/stuck, and /system/ops/runs/{run}
    • Existing shared widgets, related-navigation links, and audit-adjacent summaries that present operation identity on those surfaces
  • Data Ownership:
    • operation_runs remain the canonical persisted operational record; this spec does not add a new persisted run artifact
    • managed_tenant_onboarding_sessions.state.bootstrap_operation_types remains existing workflow state and does not become a new source of truth
    • OperationCatalog, filter options, labels, audit/reference summaries, and run presenters remain derived platform-core read models over canonical operation identity
  • RBAC:
    • Existing workspace membership remains required for workspace-admin operations and onboarding surfaces
    • Existing tenant entitlement remains required for tenant-context onboarding behavior and any tenant-owned operation visibility
    • Existing platform-user authorization remains required for /system/ops/* surfaces
    • Existing operation-start capabilities remain authoritative; this spec introduces no new capability and does not change 404 versus 403 semantics

For canonical-view specs, the spec MUST define:

  • Default filter behavior when tenant-context is active: Covered admin operations and monitoring surfaces continue to prefilter to the active tenant when tenant-context is present, and their operation-type filters expose only canonical dotted choices rather than duplicate alias variants.
  • Explicit entitlement checks preventing cross-tenant leakage: Existing workspace and tenant entitlement checks remain authoritative before any operation label, filter result, or drill-in is revealed. Canonicalization must not create a new path that reveals inaccessible tenant-owned runs through filter options, counts, or read-model summaries.

Cross-Cutting / Shared Pattern Reuse (mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write N/A - no shared interaction family touched)

  • Cross-cutting feature?: yes
  • Interaction class(es): operation labels, filter options, launch-surface selections, audit metadata, related-navigation summaries, run detail headings, and monitoring summaries
  • Systems touched: OperationCatalog, OperationRunType, provider operation definitions and start-gate payloads, onboarding bootstrap selection and resume state, filter option catalogs, operations list/detail surfaces, system ops pages, operation references, audit summaries, and workspace/dashboard summaries
  • Existing pattern(s) to extend: the existing OperationCatalog canonical definitions and alias inventory, FilterOptionCatalog::operationTypes(), OperationUxPresenter, OperationRunService, and the current operation_type glossary entry in the platform vocabulary inventory
  • Shared contract / presenter / builder / renderer to reuse: OperationCatalog remains the sole shared contract for canonical operation identity, labels, alias retirement metadata, and filter-option convergence; existing presenters and surfaces continue to read through that path instead of inventing a second translation layer
  • Why the existing shared path is sufficient or insufficient: the existing shared path is sufficient as the canonical catalog and operator-label source, but it is insufficient as long as enum-backed writers, provider operation definitions, and onboarding state still emit raw aliases as peer truths
  • Allowed deviation and why: a narrowly bounded read-side compatibility seam is allowed only for historical operation_runs.type rows and persisted onboarding draft state encountered during rollout; no new write-side aliasing, dual-write, or long-lived preservation path is allowed
  • Consistency impact: monitoring filters, run labels, audit metadata, onboarding bootstrap state, provider operation definitions, reference summaries, and start-gate payloads must all agree on the same canonical dotted operation_type
  • Review focus: reviewers must block any new underscore-style or alternate raw identifier from becoming write-time or registry-time truth, and must verify that compatibility stays read-side only and explicitly temporary
  • Touches OperationRun start/completion/link UX?: yes
  • Shared OperationRun UX contract/layer reused: the existing shared start and label path owned by OperationRunService, OperationUxPresenter, and OperationCatalog
  • Delegated start/completion UX behaviors: queued toast, Open operation deep link, run-enqueued browser event, queued DB-notification decision, dedupe-or-blocked messaging, and tenant-safe run URL resolution remain delegated to the existing shared OperationRun UX path; this slice changes the operation identity it receives, not the UX ownership model
  • Local surface-owned behavior that remains: launch surfaces such as the onboarding bootstrap step keep only initiation inputs and selection state; they do not own parallel operation-type translation rules
  • Queued DB-notification policy: existing explicit opt-in only; unchanged
  • Terminal notification path: existing central lifecycle mechanism; unchanged
  • Exception required?: none

Provider Boundary / Platform Core Check (mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write N/A - no shared provider/platform boundary touched)

  • Shared provider/platform boundary touched?: yes
  • Boundary classification: mixed
  • Seams affected: platform-core operation_type vocabulary, provider operation registry definitions and bindings, operation start-gate payloads, monitoring and reporting read models, audit metadata, and onboarding bootstrap selections
  • Neutral platform terms preserved or introduced: operation, operation_type, canonical operation code, operation catalog, operation label
  • Provider-specific semantics retained and why: provider-owned operation families such as Microsoft-specific entra.* codes remain valid current-release canonical codes where the operation itself is still provider-owned; this slice stabilizes shared contract ownership rather than renaming every provider-specific family
  • Why this does not deepen provider coupling accidentally: the contract becomes stricter about one platform-owned identity path and removes peer truths; it does not generalize Microsoft semantics into platform core and does not require provider-specific codes to leak into generic vocabulary beyond their already-bounded domain ownership
  • Follow-up path: follow-up-spec for broader governed-subject vocabulary enforcement and any later provider/domain naming cleanup that remains after this contract lands

UI / Surface Guardrail Impact (mandatory when operator-facing surfaces are changed; otherwise write N/A)

Surface / Change Operator-facing surface change? Native vs Custom Shared-Family Relevance State Layers Touched Exception Needed? Low-Impact / N/A Note
Workspace-admin Operations list and drill-ins yes Native Filament resource plus shared monitoring shell shared operations family table, detail, filter, read-model summary no Canonical filter options and labels must collapse legacy aliases into one operation identity
System Ops pages (Runs, Failures, Stuck, ViewRun) yes Native Filament pages plus shared ops widgets shared operations family table, detail, widget summary no The same canonical operation identity must drive triage labels and filters across system views
Managed tenant onboarding bootstrap step yes Native Filament wizard plus shared start UX shared onboarding and operation-launch family wizard step, persisted workflow state no Bootstrap selections persist and resume as canonical codes only
Shared operation references and dashboard widgets yes Native widgets plus shared reference presenters shared operations family related link, widget card, summary text no Secondary context surfaces inherit the same canonical operation identity without local alias mapping

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
Workspace-admin Operations list and drill-ins Primary Decision Surface Decide what ran, whether it needs follow-up, and which run to inspect operation label, status, outcome, initiator, started time, tenant scope run context, artifact links, diagnostic detail, related navigation Primary because this is the main workspace-admin run register where operators triage execution truth Follows monitoring and troubleshooting workflow rather than storage internals Removes duplicate alias choices and prevents the same operation family from appearing as different identities
System Ops pages Primary Decision Surface Decide which failed or stuck run needs platform/support attention operation label, failure/stuck class, scope, recency, current status low-level diagnostics and raw context on dedicated drill-ins Primary because these are the platform triage surfaces for operational exceptions Follows platform-ops triage workflow directly Avoids re-learning alias variants across Runs, Failures, and Stuck views
Managed tenant onboarding bootstrap step Primary Decision Surface Decide which bootstrap operations to start for the tenant selected bootstrap actions, operability state, permission availability started run detail and post-start diagnostics Primary because the operator is choosing and launching bootstrap work here Follows onboarding progression rather than monitoring structure Prevents saved selections and resumed drafts from drifting back to legacy raw identifiers
Shared operation references and dashboard widgets Secondary Context Surface Decide whether to open a referenced operation from another workflow surface operation label, health summary, recency full run detail after drill-in Secondary because these surfaces support a larger owning workflow and route into operations detail Keeps navigation tied to the owning surface while reusing canonical operation identity Reduces mental translation between widgets, references, and the operations register

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
Workspace-admin Operations list and drill-ins List / Table / Bulk Read-only Registry / Monitoring Open one operation and inspect its result Existing admin operation detail drill-in from the operations register required Existing safe secondary actions stay in More or the detail header only Existing destructive-like resumable actions stay where already approved on detail surfaces /admin/operations existing admin operation detail drill-in workspace, tenant filter, problem class, recency Operations / Operation operation label, status, outcome, tenant, and started time none
System Ops pages List / Table / Bulk Monitoring / Triage Report Open a failed or stuck operation for deeper diagnosis Explicit system run drill-in allowed Existing secondary navigation stays in header or explicit row context only none added /system/ops/runs, /system/ops/failures, /system/ops/stuck /system/ops/runs/{run} platform scope, tenant/workspace context, problem class Operations / Operation failure/stuck state, operation label, scope, and recency none
Managed tenant onboarding bootstrap step Workflow / Wizard / Launch Wizard Step / Launch Surface Start the selected bootstrap operations The onboarding step itself before launch, then the existing run link after start forbidden Secondary guidance lives in step text and follow-up summaries, not competing actions none added /admin/onboarding existing operation detail drill-in after launch workspace, tenant, verification readiness, bootstrap selection Operations / Operation which bootstrap operations will start and whether they are allowed none
Shared operation references and dashboard widgets Embedded Related Navigation Related Link / Summary Card Open the referenced operation Explicit safe link only forbidden Footer or contextual link only none owning surface route existing admin or system operation detail route owning-surface context plus tenant/workspace scope Operations / Operation operation label, current health summary, recency none

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
Workspace-admin Operations list and drill-ins Workspace owner, manager, operator Decide whether a run needs follow-up and inspect the correct run record List and detail What ran, and what needs attention? operation label, status, outcome, initiator, tenant, started time raw context, artifact detail, related navigation, low-level explanation lifecycle, outcome, readiness/attention inspection only until an existing approved follow-up action is chosen Open operation, existing safe detail actions Existing detail-owned dangerous actions only where already approved
System Ops pages Platform operator or support reviewer Decide which failed or stuck platform-visible run needs triage List and detail Which operation needs platform attention right now? operation label, failure/stuck class, scope, recency extended diagnostics and raw execution context on drill-in lifecycle, failure/stuck state, recency inspection only Open operation, existing page-level navigation none added
Managed tenant onboarding bootstrap step Workspace owner or tenant manager Decide which bootstrap operations to start and resume safely Wizard step Which bootstrap operations should this tenant start now? selected bootstrap actions, permission state, existing bootstrap summary run detail after launch, deeper diagnostics through existing run links readiness, queued/running/completed bootstrap state starts existing tenant operations only Start bootstrap, continue onboarding none added
Shared operation references and dashboard widgets Workspace operator, reviewer, or platform operator Decide whether to drill into a referenced operation from the owning surface Embedded summary Do I need to open this operation from here? operation label, summary state, recency full run detail after navigation summary state, recency none Open operation none

Proportionality Review (mandatory when structural complexity is introduced)

  • New source of truth?: yes, in contract terms only; the existing dotted catalog becomes the single normative operation_type truth instead of one of two competing truths
  • New persisted entity/table/artifact?: no
  • New abstraction?: no
  • New enum/state/reason family?: no
  • New cross-domain UI framework/taxonomy?: no
  • Current operator problem: Operators and reviewers cannot reliably tell whether two differently named run identities refer to the same operation family, and maintainers can accidentally reintroduce raw aliases into onboarding, provider dispatch, or monitoring flows because the contract is still split.
  • Existing structure is insufficient because: OperationCatalog already defines canonical dotted meanings, but OperationRunType, provider operation definitions, and onboarding bootstrap state still treat raw aliases as first-class write truths, which means every consumer must keep translating and can drift independently.
  • Narrowest correct implementation: Reuse the existing catalog as the single contract, converge the current write owners and read models around it, and keep only a bounded read-side compatibility seam for historical rows or draft state encountered during rollout.
  • Ownership cost: Existing fixtures, enum-backed assumptions, onboarding tests, and provider operation guards must be updated to one canonical contract, and the temporary compatibility seam must be retired instead of silently becoming permanent.
  • Alternative intentionally rejected: Keeping long-lived dual semantics behind canonicalCode() translation or adding a broader new resolver framework was rejected because both preserve drift rather than removing it. A wider vocabulary cleanup was rejected because it would broaden scope beyond operation_type truth.
  • Release truth: current-release truth and anti-drift hardening, not future speculative generalization

Compatibility posture

This feature assumes a pre-production environment.

Canonical replacement is preferred over preservation.

The only allowed compatibility seam is a narrowly bounded read-side translator for historical operation_runs.type rows and persisted onboarding state encountered during rollout. No new dual-write, no new fallback writer, and no new long-lived legacy alias fixture policy are allowed.

Testing / Lane / Runtime Impact (mandatory for runtime behavior changes)

  • Test purpose / classification: Unit, Feature, Heavy-Governance
  • Validation lane(s): fast-feedback, confidence, heavy-governance
  • Why this classification and these lanes are sufficient: the contract change is proven by narrow resolution and guard behavior plus representative operator-facing surfaces. Unit coverage proves canonical-code ownership, alias resolution, and registry normalization. Focused feature coverage proves monitoring filters, onboarding resume/start behavior, DB-only operations rendering, tenant-safe detail navigation, and operation-facing labels or read models. Existing heavy-governance families prove platform vocabulary anti-drift plus workspace and tenant non-leakage on touched operations surfaces.
  • New or expanded test families: focused operation-type contract guards, monitoring/filter convergence coverage, onboarding bootstrap canonicalization coverage, provider operation registry canonical-code coverage, and existing heavy-governance non-leakage coverage on touched operations surfaces
  • Fixture / helper cost impact: low to moderate; implementation should reuse existing OperationRun, onboarding session, workspace, tenant, and provider fixtures while shrinking legacy alias fixtures over time rather than adding a new helper layer
  • Heavy-family visibility / justification: existing heavy-governance families in tests/Architecture and tests/Feature/OpsUx are touched because the feature changes platform-core vocabulary and tenant-safe operation visibility; no new heavy family is introduced
  • Special surface test profile: monitoring-state-page plus standard-native-filament onboarding coverage
  • Standard-native relief or required special coverage: ordinary feature coverage remains sufficient for the primary operator surfaces; browser proof is not required. Existing heavy-governance families remain necessary for anti-drift and non-leakage proof.
  • Reviewer handoff: reviewers must confirm that write-time callers stop emitting raw aliases, filter options collapse duplicate alias variants into one canonical choice, shared links and summary widgets preserve the same canonical operation identity, onboarding resume normalizes historical selections, operations tenant-scope and tenantless viewer behavior remain entitlement-safe, DB-only operations rendering stays DB-only, and compatibility remains read-side only and temporary
  • Budget / baseline / trend impact: small increase in focused fast-feedback and confidence coverage plus reuse of existing heavy-governance families; no new heavy family or browser lane
  • Escalation needed: none
  • Active feature PR close-out entry: Guardrail
  • Planned validation commands:
    • Current repo baseline before implementation: export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/OperationTypeResolutionTest.php tests/Unit/Providers/ProviderOperationStartGateTest.php tests/Unit/Onboarding/OnboardingDraftResolverTest.php
    • Post-implementation expanded unit proof after the planned canonical-contract tests land: export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/OperationTypeResolutionTest.php tests/Unit/Support/OperationRunTypeCanonicalContractTest.php tests/Unit/Providers/ProviderOperationRegistryCanonicalTypeTest.php tests/Unit/Providers/ProviderOperationStartGateTest.php tests/Unit/Onboarding/OnboardingDraftResolverTest.php
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/OperationRunListFiltersTest.php tests/Feature/Filament/RecentOperationsSummaryWidgetTest.php tests/Feature/Monitoring/AuditCoverageOperationsTest.php tests/Feature/Monitoring/OperationsTenantScopeTest.php tests/Feature/Monitoring/OperationsDbOnlyRenderTest.php tests/Feature/Operations/TenantlessOperationRunViewerTest.php tests/Feature/ManagedTenantOnboardingWizardTest.php tests/Feature/Workspaces/ManagedTenantOnboardingProviderStartTest.php tests/Feature/Rbac/OnboardingWizardUiEnforcementTest.php
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Architecture/PlatformVocabularyBoundaryGuardTest.php tests/Feature/Guards/OperationRunLinkContractGuardTest.php tests/Feature/OpsUx/UnknownOperationTypeLabelTest.php tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php

User Scenarios & Testing (mandatory)

User Story 1 - See One Operation Identity Everywhere (Priority: P1)

As a workspace or platform operator, I want one consistent operation identity behind monitoring labels, filters, and references so I can trust that the same operation family is not being split across multiple raw names.

Why this priority: This is the primary trust and workflow problem. If monitoring and related surfaces still treat inventory_sync and inventory.sync as different truths, the platform keeps teaching the wrong contract.

Independent Test: Can be fully tested by loading covered operations surfaces with historical and current run rows and confirming that one canonical operation identity and one label source are used for the same operation family.

Acceptance Scenarios:

  1. Given historical runs contain a raw alias such as inventory_sync and newer runs contain inventory.sync, When the operator opens a covered operations surface, Then both resolve under one canonical operation identity and one filter choice rather than appearing as separate operation families.
  2. Given a related-navigation link or dashboard widget references an operation run, When the operator views it, Then the operation label comes from the same canonical source used by the operations register.

User Story 2 - Resume Onboarding Without Rewriting Legacy Drift (Priority: P1)

As a workspace admin using onboarding bootstrap actions, I want saved selections and resumed drafts to normalize to canonical operation codes so the wizard does not keep writing legacy raw values back into the platform.

Why this priority: Onboarding is an active write surface today. If it keeps persisting legacy aliases, the platform contract cannot converge even if monitoring labels do.

Independent Test: Can be fully tested by opening the bootstrap step with historical draft state, resuming the wizard, saving again, and starting bootstrap actions to verify canonical codes are used for persistence and start payloads.

Acceptance Scenarios:

  1. Given an onboarding draft contains legacy bootstrap selections such as inventory_sync, When the wizard resumes and the operator saves or starts bootstrap, Then the persisted selection is canonicalized to the dotted code and no new legacy write is produced.
  2. Given the operator starts bootstrap actions from the onboarding step, When the run start is delegated, Then the shared OperationRun UX path receives canonical operation codes only.

User Story 3 - Extend Operation Families Without Creating Peer Truths (Priority: P2)

As a maintainer or reviewer, I want one platform-owned operation-type contract so future provider or monitoring work cannot silently reintroduce raw alias writers or alternate registry truth.

Why this priority: The feature is justified not only by current operator clarity but by preventing the same semantic hotspot from reopening as more governance and provider work lands.

Independent Test: Can be fully tested by exercising focused guard coverage that fails when a new in-scope writer or registry definition emits a raw alias as first-class operation identity.

Acceptance Scenarios:

  1. Given a new in-scope operation definition or launch path is added using a legacy raw alias, When focused guard coverage runs, Then the change fails because the platform contract is no longer allowed to accept that alias as write-time truth.
  2. Given historical rows still contain legacy aliases, When read models resolve them, Then the compatibility seam remains read-side only and does not turn those aliases back into approved write-time contract values.

Edge Cases

  • Historical operation_runs.type rows may still contain aliases such as baseline_capture, baseline_compare, inventory_sync, entra_group_sync, or backup_schedule_run, and covered read surfaces must still resolve them correctly during rollout.
  • Persisted onboarding draft state may already contain alias arrays such as inventory_sync, and resume behavior must normalize them without silently writing the old value back.
  • Some existing canonical dotted codes already contain underscore segments, such as backup_set.update or tenant.review_pack.generate; this slice must not accidentally widen into a cosmetic segment-rename campaign.
  • Unknown or unsupported operation types must remain explicitly unknown rather than falling through to a misleading nearby label.
  • A single canonical filter option may need to match multiple historical raw values, and covered surfaces must not expose duplicate filter choices or contradictory counts.
  • Authorization boundaries must remain intact even when canonicalization collapses multiple stored raw values into one visible operation identity.

Acceptance Criteria Summary

  • Covered write surfaces emit only canonical dotted operation_type codes after implementation.
  • Covered read surfaces collapse legacy aliases into one canonical operation identity without duplicate filter choices.
  • Historical rows and draft state remain readable during rollout through a bounded read-side seam only.
  • Guard coverage blocks the reintroduction of raw alias writers or alternate registry truth on in-scope paths.

Implementation Close-Out

  • Covered current-release writers now emit canonical dotted values directly through OperationRunType, provider registry/start paths, onboarding bootstrap starts, lifecycle config, and representative inventory, backup, evidence, review, baseline, and directory writers.
  • The remaining compatibility seam is documented as read-side only for historical operation_runs.type rows, queued-run reauthorization, filter matching, and persisted onboarding draft normalization; legacy aliases remain write_allowed: false.
  • Validation completed through focused US1, US2, US3, and affected writer/queue regression lanes before final quickstart validation.

Requirements (mandatory)

Constitution alignment (required): This feature changes the contract around existing long-running operations, not the existence of those operations. Any in-scope start, read-model, or audit change must preserve current OperationRun observability, tenant/workspace isolation, auditability, and service-owned lifecycle behavior while canonicalizing operation_type identity.

Constitution alignment (PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001): The feature promotes an existing platform-core operation catalog to the single normative contract and removes peer truths. It does not add new persistence, new states, new registries, or a second abstraction layer.

Constitution alignment (XCUT-001): This is cross-cutting across monitoring labels, filter options, launch surfaces, onboarding bootstrap state, audit metadata, reference summaries, and provider operation definitions. It must reuse the existing shared OperationCatalog path rather than create a parallel translator or presenter family.

Constitution alignment (PROV-001): operation_type remains platform-core. Provider operation bindings continue to describe provider-owned behavior, but they must consume canonical platform-owned operation codes rather than introduce alternate raw identifiers as shared truth.

Constitution alignment (TEST-GOV-001): Proof stays in focused unit, feature, and existing heavy-governance lanes. No browser lane and no new heavy-governance family are justified. New coverage must make alias drift, non-leakage, and DB-only render safety explicit without expanding default fixture cost or creating a new test-helper framework.

Constitution alignment (OPS-UX): This feature reuses existing OperationRun behavior. The default 3-surface feedback contract remains intact, OperationRun.status and OperationRun.outcome remain service-owned through OperationRunService, summary_counts semantics remain unchanged, and scheduled/system-run terminal notification behavior remains unchanged.

Constitution alignment (OPS-UX-START-001): The feature includes the OperationRun UX Impact section and keeps start-surface behavior delegated to the existing shared path. Local surfaces are limited to initiation inputs and canonical operation selection; they do not own queued toast, link, browser-event, or notification behavior.

Constitution alignment (RBAC-UX): Authorization planes remain unchanged. Non-members remain 404, members lacking capability remain 403, and covered operations/global references remain tenant-safe. No destructive confirmation rule changes are introduced.

Constitution alignment (OPS-EX-AUTH-001): Not applicable.

Constitution alignment (BADGE-001): Existing run status and outcome badges remain centralized and unchanged. This slice does not introduce a new badge family or local status mapping.

Constitution alignment (UI-FIL-001): UI-FIL-001 is satisfied. Covered admin and system surfaces stay on native Filament resources, pages, widgets, forms, and sections plus existing shared presenters. No local replacement markup or local status language is introduced.

Constitution alignment (UI-NAMING-001): The target object is the operation and its platform operation_type identity. Operator-facing labels continue to use existing operation display labels derived from the canonical catalog. Raw storage aliases remain implementation details and must not become primary operator-facing copy.

Constitution alignment (DECIDE-001): Operations registers and onboarding bootstrap remain primary decision surfaces. Shared references and widgets remain secondary context surfaces that route to the same canonical run truth.

Constitution alignment (UI-CONST-001 / UI-SURF-001 / ACTSURF-001 / UI-HARD-001 / UI-EX-001 / UI-REVIEW-001 / HDR-001): The affected surface classes, inspect models, routes, scope cues, default-visible truth, and action placements are captured in the surface tables above. No exemption is required.

Constitution alignment (ACTSURF-001 - action hierarchy): This slice does not add a new action family. Existing navigation, mutation, and dangerous-action placement remain unchanged while canonical operation identity is normalized underneath them.

Constitution alignment (OPSURF-001): Default-visible content remains operator-first on covered surfaces. Operators continue to see labels, status, outcome, and scope rather than raw alias strings. Diagnostic identity details remain secondary.

Constitution alignment (UI-SEM-001 / LAYER-001 / TEST-TRUTH-001): Direct mapping from the canonical operation catalog to UI labels and filters is sufficient. The slice exists to remove redundant truth, not add another interpretation layer.

Constitution alignment (Filament Action Surfaces): The Action Surface Contract is satisfied. Each affected surface keeps one primary inspect/open model, redundant View actions remain absent, empty action groups remain absent, and destructive action placement remains unchanged. The UI Action Matrix below records the affected surfaces.

Constitution alignment (UX-001 — Layout & Information Architecture): Covered Filament screens keep their existing native layouts, sections, tables, and empty-state behavior. No UX-001 exemption is required because this slice changes contract truth and shared labels/filters rather than introducing new layouts.

Functional Requirements

  • FR-239-001: Existing catalog-defined dotted operation_type codes MUST become the single normative platform contract for in-scope operation identity.
  • FR-239-002: All new or updated in-scope operation starts, provider operation definitions, audit metadata payloads, and onboarding bootstrap selections MUST emit or persist canonical dotted codes rather than raw legacy aliases.
  • FR-239-003: Existing canonical dotted codes that already contain underscore segments, such as backup_set.update or tenant.review_pack.generate, MUST remain valid canonical codes in this slice; this feature MUST NOT widen into a cosmetic renaming campaign.
  • FR-239-004: No in-scope write-time caller MAY require a second translation step such as canonicalCode() to discover the normative platform contract after implementation; the emitted or stored value itself must already be canonical.
  • FR-239-005: OperationCatalog MUST remain the sole shared resolver for canonical operation code, operator label, alias retirement metadata, and filter-option convergence.
  • FR-239-006: Historical raw values MAY be resolved only at read time for legacy operation_runs.type rows or persisted onboarding draft state encountered during rollout.
  • FR-239-007: The compatibility seam for historical aliases MUST be bounded, documented, and removable; no dual-write, fallback writer, or long-lived alias-preservation framework is allowed.
  • FR-239-008: Covered operations collection and detail surfaces MUST collapse alias variants into one canonical operation identity and one operator label source.
  • FR-239-009: Covered monitoring, reporting, reference, and audit surfaces that describe an operation type MUST derive from the canonical code or its catalog label rather than rendering raw legacy aliases as first-class truth.
  • FR-239-010: The onboarding bootstrap step MUST normalize legacy saved selections on resume and MUST persist only canonical dotted codes after any in-scope edit, save, or start action.
  • FR-239-011: Provider operation registries, bindings, and start-gate payloads MUST define operation_type using canonical dotted codes rather than raw aliases.
  • FR-239-012: Unknown or unsupported operation types MUST remain explicitly unknown and MUST NOT silently inherit a nearby canonical label or alias match.
  • FR-239-013: Existing OperationRun lifecycle, dedupe, notification, and authorization behavior MUST remain unchanged except for canonical operation-type identity.
  • FR-239-014: Existing 404 versus 403 semantics across workspace-admin, tenant-context, and system operations surfaces MUST remain unchanged.
  • FR-239-015: The first implementation slice MUST cover OperationRunType, OperationCatalog, provider operation definitions and start-gate consumers, onboarding bootstrap state, operations filter/read-model helpers, and focused guard coverage.
  • FR-239-016: The feature MUST NOT add new tables, new operation families, new provider abstraction frameworks, or a broader monitoring information-architecture redesign.
  • FR-239-017: Regression coverage MUST fail if a new underscore-style or otherwise non-canonical write-time identifier becomes accepted as platform-core truth on any covered writer or registry path.
  • FR-239-018: operation_type MUST remain classified as a platform-core canonical noun, while operation_runs.type remains only a temporary compatibility storage seam during rollout.
  • FR-239-019: Later vocabulary cleanup outside operation_type truth, including broader governed-subject key work and unrelated domain naming, MUST remain outside this slice.

Non-Goals

  • Renaming every existing canonical code segment to eliminate embedded underscores
  • Reworking operation navigation, dashboard information architecture, or monitoring page layout
  • Introducing a new registry, resolver, presenter, or taxonomy framework for operation identity
  • Adding new operation families or expanding provider-neutral runtime scope
  • Performing application-code implementation in this spec artifact

Assumptions

  • LEAN-001 applies: the product is still pre-production, so canonical replacement is preferred over preserving raw alias writers.
  • The existing OperationCatalog dotted definitions are the closest current platform truth and are sufficient as the single normative contract for this slice.
  • Historical operation_runs.type rows and persisted onboarding drafts may still contain legacy raw aliases when implementation starts.
  • Operator-facing copy continues to use current display labels derived from the canonical catalog rather than exposing dotted codes by default, except on surfaces that intentionally show identifiers.
  • Existing workspace, tenant, and platform authorization rules already cover the affected surfaces and do not need redesign for this slice.

Dependencies

  • specs/171-operations-naming-consolidation/spec.md for operator-visible naming alignment already completed separately from internal operation-type truth
  • specs/237-provider-boundary-hardening/spec.md for shared provider/platform seam discipline
  • specs/238-provider-identity-target-scope/spec.md as the adjacent anti-drift lane that keeps provider-neutral platform truth bounded correctly
  • Existing platform vocabulary classification that marks operation_type as a platform-core canonical noun and operation_runs.type as a rollout compatibility seam
  • Existing operations, onboarding, provider-dispatch, reference, and audit surfaces that already consume operation identity today

Risks

  • A bounded read-side compatibility seam could accidentally become permanent if in-scope write paths are not fully converged in the same implementation slice.
  • The slice can sprawl into broader vocabulary cleanup unless planning and review keep the scope locked to operation_type truth only.
  • Partial convergence across monitoring, onboarding, and provider dispatch would still leave contradictory platform truth even if one surface appears fixed.
  • Existing fixtures and historical assumptions may be numerous enough that reviewers are tempted to preserve alias writers instead of replacing them.

Resolved Planning Notes

  • Canonical dotted codes that legitimately retain underscore segments and must not trigger broader renaming include backup_set.update, directory.role_definitions.sync, tenant.review_pack.generate, tenant.evidence.snapshot.generate, entra.admin_roles.scan, and rbac.health_check.
  • The first implementation pass must explicitly cover non-UI exports and stored summaries that still surface raw operation_runs.type, including OperationRunService, OperationRunTriageService, FindingsLifecycleBackfillRunbookService, shared related-run links, and summary-widget read models.

Follow-up Candidates

  • Platform Vocabulary Boundary Enforcement for Governed Subject Keys
  • Retirement of the bounded read-side compatibility seam once historical rows and fixtures have been replaced
  • Any later provider/domain vocabulary cleanup that remains necessary after the canonical operation_type contract is fully converged
  • Customer Review Workspace v1 and broader review-surface work after this platform-core semantic drift is removed

UI Action Matrix (mandatory when Filament is changed)

Surface Location Header Actions Inspect Affordance (List/Table) Row Actions (max 2 visible) Bulk Actions (grouped) Empty-State CTA(s) View Header Actions Create/Edit Save+Cancel Audit log? Notes / Exemptions
Workspace-admin Operations surfaces existing admin operations resource and tenantless detail viewer no new header actions existing clickable-row or safe detail drill-in existing inspect action(s) only existing grouped bulk behavior remains unchanged existing empty-state behavior unchanged existing back, refresh, related links, and approved resumable actions remain n/a no new audit behavior Only the canonical operation-type contract behind labels and filters changes
System Ops pages existing system pages for runs, failures, stuck, and run detail no new header actions existing view-run drill-in existing inspect action only none added existing page behavior unchanged existing page-level navigation and refresh remain n/a no new audit behavior Canonical operation-type filters and labels must match workspace-admin operations truth
Managed tenant onboarding bootstrap step existing onboarding wizard bootstrap step none added the wizard step itself before launch; existing operation link after launch Start bootstrap remains existing launch action none existing onboarding CTA behavior remains n/a existing continue/cancel behavior remains existing onboarding audit behavior remains Saved selections and resumed drafts normalize to canonical codes only
Shared operation references and widgets existing dashboard widgets and reference presenters no new header actions explicit safe link only existing safe inspect link only none owning surface behavior unchanged n/a n/a no new audit behavior Secondary surfaces must not add local alias mapping or duplicate identity rules

Key Entities (include if feature involves data)

  • Canonical Operation Type: The single platform-owned dotted identifier that names an operation family consistently across starts, persistence, read models, filters, audit metadata, and operator-facing labels.
  • Historical Operation Type Alias: A legacy raw value such as inventory_sync or baseline_capture that may still appear in older persisted rows or workflow state and is allowed only through the temporary read-side compatibility seam.
  • Operation Run: The existing persisted operational record whose lifecycle, auditability, and visibility stay unchanged while its canonical operation identity is tightened.
  • Onboarding Bootstrap Selection: The existing workflow-state list of optional bootstrap operations chosen during onboarding and normalized to canonical operation codes before persistence or launch.
  • Provider Operation Definition: The existing provider-backed operation registry or binding entry that must consume canonical operation_type identity without becoming a second truth owner.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-239-001: In all covered write paths, 100% of newly emitted or persisted in-scope operation identifiers use canonical dotted operation_type codes rather than legacy raw aliases.
  • SC-239-002: On all covered monitoring and operations surfaces, 100% of alias variants for the same operation family collapse into one canonical operation identity and one filter choice.
  • SC-239-003: Historical rows and resumed onboarding drafts using legacy aliases remain readable throughout rollout without producing any new legacy write on a covered save or start path.
  • SC-239-004: Focused regression coverage fails whenever a covered writer, registry entry, or launch surface attempts to reintroduce a raw alias as first-class platform truth.
  • SC-239-005: The feature lands without adding any new table, new operation family, new abstraction framework, or long-lived dual-write compatibility layer.

Definition of Done

Spec 239 is complete when the platform has one normative dotted operation_type contract for covered operations, historical alias rows remain readable only through a bounded read-side seam during rollout, onboarding and provider-dispatch surfaces stop writing legacy raw values, covered operations surfaces expose one canonical identity per operation family, and focused automated coverage blocks the semantic drift from returning.