TenantAtlas/specs/271-counted-progress-rollout/plan.md
2026-05-05 02:26:31 +02:00

262 lines
17 KiB
Markdown

# Implementation Plan: Counted Progress Rollout v1
**Branch**: `271-counted-progress-rollout` | **Date**: 2026-05-05 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/271-counted-progress-rollout/spec.md`
## Summary
This plan prepares one bounded writer-rollout slice on top of the existing shared progress contract from Spec 270. The implementation path is to reuse `OperationRunProgressContract` and `OperationRunService`, add truthful `total` plus `processed` writes only where the repo already exposes deterministic work units, and leave baseline capture/compare on their current phased path. The slice must not invent totals, widen into phase/composite work, add new `summary_counts` keys, or redesign current Ops-UX surfaces.
## Inherited Baseline / Explicit Delta
### Inherited baseline
- `App\Support\OpsUx\OperationRunProgressContract` already centralizes `none`, `activity`, `counted`, `phased`, and `composite` progress modes.
- `App\Services\OperationRunService` already owns `updateRun()`, `incrementSummaryCounts()`, and `maybeCompleteBulkRun()` as the authoritative summary-count mutation path.
- The current tenant shell adopter already consumes the shared progress contract and can render determinate counted progress when trustworthy counts exist.
- Inventory sync, review-pack generation, evidence-snapshot generation, `AddPoliciesToBackupSetJob`, `BulkBackupSetRestoreJob`, and `BackupSetRestoreWorkerJob` are already repo-real workflows with current tests.
- Baseline capture and baseline compare already expose evidence-capture phase hints, which the current progress contract classifies as `phased` before `counted`.
### Explicit delta in this plan
- roll out truthful counted inputs for selected stable-unit run families only
- standardize parent and child count discipline across `AddPoliciesToBackupSetJob`, `BulkBackupSetRestoreJob`, and `BackupSetRestoreWorkerJob`
- keep current shell and Operations detail surfaces unchanged except for consuming newly truthful count data
- document the narrowed scope deviation from the original candidate wording: baseline capture/compare remain deferred because repo truth now places them on the phased/composite path
## Technical Context
**Language/Version**: PHP 8.4, Laravel 12, Filament v5, Livewire v4
**Primary Dependencies**: current Ops-UX support classes, native Filament/Livewire shell feedback, Pest v4
**Storage**: PostgreSQL via existing `operation_runs`, review-pack, evidence-snapshot, backup-set, and restore tables
**Testing**: Pest Unit + Feature
**Validation Lanes**: fast-feedback, confidence
**Target Platform**: existing Laravel monolith in `apps/platform`
**Project Type**: web application (Laravel monolith with Filament)
**Performance Goals**: no new query families, no new polling loops, and no slower-than-current active-operation feedback
**Constraints**: no new `summary_counts` keys, no new persistence, no contract-precedence change, and no broad writer sweep
**Scale/Scope**: one shared contract reused across 4 selected run families plus one standards update and focused regression coverage
## Likely Affected Repo Surfaces
- `apps/platform/app/Support/OpsUx/OperationRunProgressContract.php`
- `apps/platform/app/Support/OpsUx/SummaryCountsNormalizer.php`
- `apps/platform/app/Support/OpsUx/OperationSummaryKeys.php`
- `apps/platform/app/Services/OperationRunService.php`
- `apps/platform/app/Jobs/RunInventorySyncJob.php`
- `apps/platform/app/Services/Inventory/InventorySyncService.php`
- `apps/platform/app/Jobs/GenerateReviewPackJob.php`
- `apps/platform/app/Services/ReviewPackService.php`
- `apps/platform/app/Jobs/GenerateEvidenceSnapshotJob.php`
- `apps/platform/app/Services/Evidence/EvidenceSnapshotService.php`
- `apps/platform/app/Jobs/AddPoliciesToBackupSetJob.php`
- `apps/platform/app/Jobs/BulkBackupSetRestoreJob.php`
- `apps/platform/app/Jobs/Operations/BackupSetRestoreWorkerJob.php`
- `apps/platform/tests/Unit/Support/OpsUx/OperationRunProgressContractTest.php`
- `apps/platform/tests/Feature/Inventory/RunInventorySyncJobTest.php`
- `apps/platform/tests/Feature/ReviewPack/ReviewPackGenerationTest.php`
- `apps/platform/tests/Feature/Evidence/GenerateEvidenceSnapshotJobTest.php`
- `apps/platform/tests/Feature/BackupSets/AddPoliciesToBackupSetJobTest.php`
- `apps/platform/tests/Unit/BulkBackupSetRestoreJobTest.php`
- `apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php`
- `apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php`
- `docs/ui/tenantpilot-enterprise-ui-standards.md`
## UI / Filament & Livewire Fit
- The visible adopter remains the existing tenant-shell activity feedback surface. No new page, widget family, or dashboard card is introduced.
- The shell stays decision-first. This slice changes only whether selected runs can legitimately enter the already-existing counted mode.
- Operations collection/detail pages remain diagnostics-first drill-through targets. They inherit more truthful count data but no new layout or action model.
- No panel registration, asset registration, or global-search changes are planned.
## RBAC / Policy Fit
- Existing capability gates for the initiating surfaces remain unchanged.
- Existing `OperationRun` policies remain the only progress-visibility gate.
- No new mutation surface is introduced, so current server-side authorization and confirmation behavior remains on the existing launch and detail surfaces.
## Audit / Logging Fit
- Existing queued toasts and terminal notifications remain authoritative and unchanged.
- Existing run audit remains the only audit trail for the counted rollout. No new run-local audit channel is introduced.
- Parent/child bulk completion still flows through existing `OperationRunService` helpers instead of feature-local completion code.
## Data & Query Fit
- Progress truth remains fully derived from `operation_runs.summary_counts` plus existing contract logic.
- Determinate progress stays limited to work with deterministic units known before or during processing.
- Outcome counters remain summary truth and do not replace `processed`.
- No migration, no new JSON schema, no cache layer, and no new persisted preference or progress mode are planned.
## UI / Surface Guardrail Plan
- **Guardrail scope**: changed surfaces
- **Native vs custom classification summary**: native Filament + existing Livewire/Blade shell surface
- **Shared-family relevance**: Ops-UX activity feedback and run summaries
- **State layers in scope**: shell
- **Audience modes in scope**: operator-MSP
- **Decision/diagnostic/raw hierarchy plan**: decision-first on shell, diagnostics-second on Operations detail
- **Raw/support gating plan**: unchanged; raw/support detail remains on diagnostics surfaces only
- **One-primary-action / duplicate-truth control**: keep one dominant `View operation` action and one progress mode derived from the shared contract
- **Handling modes by drift class or surface**: review-mandatory
- **Repository-signal treatment**: review-mandatory
- **Special surface test profiles**: global-context-shell
- **Required tests or manual smoke**: functional-core, state-contract
- **Exception path and spread control**: none planned
- **Active feature PR close-out entry**: Guardrail / Smoke Coverage
## Shared Pattern & System Fit
- **Cross-cutting feature marker**: yes
- **Systems touched**: Ops-UX progress contract, summary-count service helpers, inventory/review/evidence/backup writers, shell adopter
- **Shared abstractions reused**: `OperationRunProgressContract`, `OperationRunService`, `SummaryCountsNormalizer`, `OperationSummaryKeys`
- **New abstraction introduced? why?**: none planned
- **Why the existing abstraction was sufficient or insufficient**: rendering semantics are already centralized; the missing piece is writer-side counted input for specific repo-real workflows
- **Bounded deviation / spread control**: keep all count mutation on `OperationRunService`; any run family without deterministic units stays out of scope rather than adding a local exception
## OperationRun UX Impact
- **Touches OperationRun start/completion/link UX?**: yes, for progress truth only
- **Central contract reused**: existing OperationRun Start UX Contract plus `OperationRunProgressContract`
- **Delegated UX behaviors**: queued toast, canonical run links, `run-enqueued` event, and terminal notification lifecycle remain delegated and unchanged
- **Surface-owned behavior kept local**: launch inputs and current domain-specific validation only
- **Queued DB-notification policy**: `N/A` - unchanged
- **Terminal notification path**: unchanged central lifecycle mechanism
- **Exception path**: none
## Provider Boundary & Portability Fit
- **Shared provider/platform boundary touched?**: no
- **Provider-owned seams**: `N/A`
- **Platform-core seams**: `OperationRun` truth, progress contract, shell feedback
- **Neutral platform terms / contracts preserved**: `Operation`, `progress`, `counted progress`, `activity`, `terminal outcome`
- **Retained provider-specific semantics and why**: none
- **Bounded extraction or follow-up path**: none
## Constitution Check
*GATE: Must pass before implementation begins and again before merge.*
- Inventory-first: PASS. The slice only enriches execution feedback over current `OperationRun` truth.
- Read/write separation: PASS. No new external write path is introduced; current domain jobs keep their existing behavior and only improve run-count truth.
- Graph contract path: PASS. No new Graph/provider seam is introduced.
- Deterministic capabilities: PASS. Authorization and progress eligibility stay deterministic and testable.
- RBAC-UX: PASS. Visibility remains on existing tenant/admin boundaries and `OperationRun` policies.
- Run observability: PASS. Long-running work still flows through current `OperationRun` ownership and current Ops-UX surfaces.
- Ops-UX lifecycle: PASS. `status` and `outcome` ownership remains on `OperationRunService`; only count truth is enriched.
- Ops-UX summary counts: PASS. The rollout stays on current whitelist semantics and numeric-only values.
- Test governance: PASS. Proof remains bounded to Unit plus Feature.
- Proportionality / no premature abstraction: PASS. No new abstraction or persistence is introduced.
- Persisted truth / behavioral state: PASS. No new table, cache, or status family is added.
- Shared pattern first / UI semantics / Filament-native UI: PASS. Existing Ops-UX path remains central and the visible adopter is unchanged.
- Provider boundary: PASS. No provider/platform seam change.
- Filament/Laravel panel safety: PASS. Filament v5 stays on Livewire v4, provider registration remains in `apps/platform/bootstrap/providers.php`, and no assets change.
**Gate evaluation**: PASS.
## Test Governance Check
- **Test purpose / classification by changed surface**: Unit for contract safeguards; Feature for selected writer rollouts and current shell adoption
- **Affected validation lanes**: fast-feedback, confidence
- **Why this lane mix is the narrowest sufficient proof**: domain feature suites already exist for the in-scope writer families, and the shared contract already has a focused unit suite. Browser proof remains owned by Spec 268 because this slice does not alter layout or clickability.
- **Narrowest proving command(s)**:
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/OpsUx/OperationRunProgressContractTest.php`
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Inventory/RunInventorySyncJobTest.php tests/Feature/ReviewPack/ReviewPackGenerationTest.php tests/Feature/Evidence/GenerateEvidenceSnapshotJobTest.php tests/Feature/BackupSets/AddPoliciesToBackupSetJobTest.php tests/Unit/BulkBackupSetRestoreJobTest.php tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php`
- **Fixture / helper / factory / seed / context cost risks**: low to moderate; reuse current tenant context helpers and current job-specific fixtures instead of introducing new provider-heavy harnesses
- **Expensive defaults or shared helper growth introduced?**: no
- **Heavy-family additions, promotions, or visibility changes**: none
- **Surface-class relief / special coverage rule**: `global-context-shell`
- **Closing validation and reviewer handoff**: rerun the two proving commands above and verify that selected families now emit truthful counts, excluded phased families remain excluded, and no writer bypasses `OperationRunService`
- **Budget / baseline / trend follow-up**: none expected beyond a small feature-local increase
- **Review-stop questions**: did any excluded run family sneak in, did any writer invent totals, did `processed` stay bounded by `total`, and did any new summary key or local progress helper appear?
- **Escalation path**: `reject-or-split` for any baseline phased/composite widening, dashboard redesign, or persisted progress model
- **Active feature PR close-out entry**: Guardrail / Smoke Coverage
- **Why no dedicated follow-up spec is needed**: this package is itself the bounded writer-rollout follow-through on Spec 270; any remaining excluded families are already named as future follow-ups.
## Project Structure
### Documentation (this feature)
```text
specs/271-counted-progress-rollout/
├── spec.md
├── plan.md
├── tasks.md
└── checklists/
└── requirements.md
```
### Source Code (expected implementation surfaces)
```text
apps/platform/app/Support/OpsUx/
apps/platform/app/Services/OperationRunService.php
apps/platform/app/Jobs/RunInventorySyncJob.php
apps/platform/app/Services/Inventory/InventorySyncService.php
apps/platform/app/Jobs/GenerateReviewPackJob.php
apps/platform/app/Services/ReviewPackService.php
apps/platform/app/Jobs/GenerateEvidenceSnapshotJob.php
apps/platform/app/Services/Evidence/EvidenceSnapshotService.php
apps/platform/app/Jobs/AddPoliciesToBackupSetJob.php
apps/platform/app/Jobs/BulkBackupSetRestoreJob.php
apps/platform/app/Jobs/Operations/BackupSetRestoreWorkerJob.php
apps/platform/tests/Unit/Support/OpsUx/
apps/platform/tests/Feature/Inventory/
apps/platform/tests/Feature/ReviewPack/
apps/platform/tests/Feature/Evidence/
apps/platform/tests/Feature/BackupSets/
apps/platform/tests/Feature/OpsUx/
docs/ui/tenantpilot-enterprise-ui-standards.md
```
**Structure Decision**: keep the rollout local to current jobs/services plus the existing Ops-UX support family. Do not introduce a new progress rollout framework or a second writer abstraction.
## Data / Migration Implications
- No migration or schema change is planned.
- No new persisted progress mode or preference is allowed.
- No backfill is planned. Historical runs remain historical truth; the rollout affects future execution only.
## Rollout Considerations
- Filament remains v5 on Livewire v4. Provider registration remains in `apps/platform/bootstrap/providers.php`.
- No global search or asset change is required because the slice changes only run-count truth.
- No destructive action or confirmation model changes are planned.
- No deployment step beyond ordinary code deploy and current test validation is expected.
## Risk Controls
- Reject any implementation that changes progress-contract precedence to force phased runs into counted mode.
- Reject any implementation that adds new `summary_counts` keys or uses outcome counters as hidden progress substitutes.
- Reject any implementation that sets totals from speculative estimates instead of deterministic current work sets.
- Reject any implementation that initializes parent totals multiple times or allows child retries to double-increment `processed`.
- Reject any implementation that broadens the rollout to unrelated run families not named in the spec and tasks.
## Implementation Phases
### Phase 0 - Confirm Selected Stable-Unit Writer Seams
- Verify current counted and terminal-only seams in inventory sync, review-pack generation, evidence-snapshot generation, `AddPoliciesToBackupSetJob`, `BulkBackupSetRestoreJob`, and `BackupSetRestoreWorkerJob`.
- Reconfirm that baseline capture/compare remain phased under the current contract and stay out of scope.
### Phase 1 - Roll Out Inventory And Artifact Writer Counts
- Add or standardize `total` plus `processed` writes for inventory sync, review-pack generation, and evidence-snapshot generation.
### Phase 2 - Standardize Enumerated Backup/Restore Fan-Out Counts
- Align `AddPoliciesToBackupSetJob`, `BulkBackupSetRestoreJob`, and `BackupSetRestoreWorkerJob` on one total/processed discipline and current `maybeCompleteBulkRun()` semantics.
### Phase 3 - Lock The Guardrail And Proof
- Update the UI standards and focused tests so later run families do not re-open fake or partial counted rollout.
## Proportionality Review
- **Current operator problem**: determinable long-running work still looks indeterminate because selected writers do not persist counts early enough or consistently enough.
- **Existing structure is insufficient because**: the shared contract already exists and cannot invent counted progress from terminal summaries alone.
- **Narrowest correct implementation**: update only repo-verified stable-unit writers and leave all other families on their current truthful modes.
- **Ownership cost created**: targeted job/service tests and one standards update.
- **Alternative intentionally rejected**: broad all-writers rollout or phased-precedence changes were rejected because they would widen into a second spec.
- **Release truth**: current-release truth. The repo already contains the contract, the visible adopter, and the selected writers needed for this rollout.