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

267 lines
29 KiB
Markdown

# Feature Specification: Counted Progress Rollout v1
**Feature Branch**: `271-counted-progress-rollout`
**Created**: 2026-05-05
**Status**: Ready for implementation
**Input**: Manual promotion from `docs/product/spec-candidates.md` after the 2026-05-05 repo-based next-best-prep review and explicit user preference to continue with candidate `271`.
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
- **Problem**: `specs/270-operationrun-progress-contract/` already made progress disclosure truthful, but many high-value `OperationRun` writers still emit terminal-only summaries or inconsistent partial counts. The shared contract cannot show determinate progress unless those writers persist trustworthy `total` and `processed` values while work is running.
- **Today's failure**: operators can start inventory sync, review-pack generation, evidence snapshot generation, and several bulk backup/restore operations, yet the shell often stays indeterminate until completion even when the code already knows stable work units. Some backup/restore fan-out jobs already increment counts, while adjacent launchers only seed totals or finish with terminal summaries, so progress trust varies by run family.
- **User-visible improvement**: selected long-running operations expose determinate progress only when stable work units exist, while unknown-total or phase-driven runs remain activity-only or phased under the existing contract.
- **Smallest enterprise-capable version**: reuse `App\Support\OpsUx\OperationRunProgressContract` and roll out trustworthy `summary_counts.total` plus `summary_counts.processed` writes only for current run families with repo-verified stable units: inventory sync, review-pack generation, evidence snapshot generation, `AddPoliciesToBackupSetJob`, `BulkBackupSetRestoreJob`, and `BackupSetRestoreWorkerJob`.
- **Explicit non-goals**: no broad rewrite of all `OperationRun` writers, no fake totals, no new `summary_counts` keys, no new status/outcome family, no dashboard redesign, no new notification policy, no new persistence, and no change to the `phased`/`composite` precedence already defined by Spec 270. Original candidate wording mentioned baseline capture/compare, but current repo truth classifies those runs through phased evidence-capture hints, so that portion is deferred rather than forced into this counted rollout.
- **Permanent complexity imported**: targeted writer-side count initialization/increment points in existing jobs and services, focused Pest coverage across current domain test families, and one standards update that records which run families may claim counted progress under the existing contract.
- **Why now**: Spec 270 is already prepared and its implementation surfaces now exist in the repo (`OperationRunProgressContract`, its unit suite, and the shell adopter). The next bounded value is to feed that contract with real counts instead of leaving it mostly theoretical for high-value operations.
- **Why not local**: fixing one job at a time would preserve inconsistent counted-progress semantics across inventory, evidence, review exports, and backup/restore fan-out. The operator trust problem is cross-family and needs one bounded rollout slice.
- **Approval class**: Core Enterprise
- **Red flags triggered**: multiple run families, shared execution-truth semantics, and writer-side summary-count changes. Defense: the slice adds no persistence, no new vocabulary, and no new rendering layer; it only reuses existing `OperationRunService` helpers and the already-shipped progress contract.
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 1 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 2 | **Gesamt: 10/12**
- **Decision**: approve
## Spec Scope Fields *(mandatory)*
- **Scope**: tenant + canonical-view
- **Primary Routes**:
- `/admin/t/{tenant}/...` tenant-scoped launch surfaces that already enqueue inventory sync, review-pack generation, evidence snapshot generation, and backup/restore bulk work
- `/admin/operations` and `/admin/operations/{run}` remain the canonical collection/detail routes that reflect the resulting counted progress through existing Ops-UX surfaces
- **Data Ownership**: existing tenant-owned `operation_runs.summary_counts` remains the only progress truth touched by this slice. No new table, cache, mirror entity, or persisted progress-mode flag is allowed. Existing tenant-owned review-pack, evidence-snapshot, backup-set, and restore-run records remain domain truth for their own workflows but do not gain a second progress projection.
- **RBAC**: existing capability checks for inventory sync, review pack generation, evidence snapshot generation, and backup/restore actions remain authoritative. Existing `OperationRun` policies remain the only visibility gate for progress feedback.
For canonical-view behavior:
- **Default filter behavior when tenant-context is active**: unchanged. `OperationRun` collection/detail surfaces continue to open in current tenant context, and the shell keeps tenant-scoped progress hints only for runs the actor can already view.
- **Explicit entitlement checks preventing cross-tenant leakage**: unchanged. Non-members remain `404`, member-but-missing-capability remains `403`, and no run family in scope may emit progress-derived copy for an inaccessible run.
## Cross-Cutting / Shared Pattern Reuse *(mandatory)*
- **Cross-cutting feature?**: yes
- **Interaction class(es)**: status messaging, activity feedback, execution-truth summaries
- **Systems touched**: `OperationRunService`, `OperationRunProgressContract`, `SummaryCountsNormalizer`, `OperationSummaryKeys`, current shell activity feedback, and selected current run-writer jobs/services
- **Existing pattern(s) to extend**: Spec 270 shared progress contract, current `summary_counts` sanitization/whitelist, current bulk-run completion helper, and current shell adopter
- **Shared contract / presenter / builder / renderer to reuse**: `App\Support\OpsUx\OperationRunProgressContract`, `App\Support\OpsUx\SummaryCountsNormalizer`, `App\Support\OpsUx\OperationSummaryKeys`, `App\Services\OperationRunService`, and current Ops-UX shell surfaces
- **Why the existing shared path is sufficient or insufficient**: the repo already has one truthful render contract. What is missing is not another presenter, but writer-side counted inputs for specific run families that already have stable work units.
- **Allowed deviation and why**: none planned. The rollout must converge on existing `OperationRunService` helpers rather than introduce domain-local count logic or host-local exceptions.
- **Consistency impact**: selected run families may claim counted progress only through `total` plus `processed`. `succeeded`, `failed`, `skipped`, `created`, and `updated` remain outcome counters or secondary summaries, never hidden percentage sources.
- **Review focus**: reviewers must block any rollout that invents totals, writes raw `summary_counts` without `OperationRunService`, changes progress-contract precedence, or quietly broadens the candidate back into phase/composite work.
## OperationRun UX Impact *(mandatory)*
- **Touches OperationRun start/completion/link UX?**: yes
- **Shared OperationRun UX contract/layer reused**: existing OperationRun Start UX Contract plus `App\Support\OpsUx\OperationRunProgressContract`
- **Delegated start/completion UX behaviors**: queued toast wording, canonical `View operation` links, `run-enqueued` browser events, existing terminal notifications, and tenant-safe URL resolution remain delegated to the current shared OperationRun UX path and are unchanged in this slice
- **Local surface-owned behavior that remains**: domain-specific initiation inputs and launch validation on current inventory, review-pack, evidence, and backup/restore start surfaces only
- **Queued DB-notification policy**: `N/A` - unchanged
- **Terminal notification path**: unchanged central lifecycle mechanism
- **Exception required?**: none
## Provider Boundary / Platform Core Check *(mandatory)*
- **Shared provider/platform boundary touched?**: no
- **Boundary classification**: `N/A`
- **Seams affected**: `N/A`
- **Neutral platform terms preserved or introduced**: `Operation`, `progress`, `counted progress`, `activity`, `terminal outcome`
- **Provider-specific semantics retained and why**: none
- **Why this does not deepen provider coupling accidentally**: the feature only rolls out counted inputs over existing platform-owned `OperationRun` truth and existing launchers
- **Follow-up path**: none
## 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 |
|---|---|---|---|---|---|---|
| Existing OperationRun progress feedback on the tenant shell | yes | Native Filament + existing Livewire/Blade surface | Ops-UX activity feedback and run summaries | shell | no | No new surface is introduced; the visible delta is that selected runs can now legitimately enter the existing counted-progress mode |
## Decision-First Surface Role *(mandatory)*
| 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 |
|---|---|---|---|---|---|---|---|
| Existing OperationRun progress feedback on the tenant shell | Primary Decision Surface | Decide whether active work is genuinely progressing or merely queued/activity-only | operation label, lifecycle state, truthful counted or indeterminate mode, and canonical `View operation` action | full run detail, logs, evidence, and diagnostics stay on Operations pages | Primary because the shell is the first feedback surface after a launch action | Follows current start-surface workflow rather than storage objects | Replaces inconsistent indeterminate-only feedback for selected run types without adding another widget family |
## Audience-Aware Disclosure *(mandatory)*
| 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 |
|---|---|---|---|---|---|---|---|
| Existing OperationRun progress feedback on the tenant shell | operator-MSP | operation label, lifecycle state, honest counted or indeterminate progress label, canonical open link | one concise guidance line only when the next action changes | raw payloads, failure internals, provider diagnostics | `View operation` | raw/support detail stays on Operations detail | the shell shows only one progress mode derived from the shared contract; domain jobs do not add parallel progress copy |
## UI/UX Surface Classification *(mandatory)*
| 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Existing OperationRun progress feedback on the tenant shell | Monitoring hint | Activity shell hint | Open the relevant operation only when follow-up is needed | explicit `View operation` link | forbidden | overflow navigation only | none | `/admin/operations?tenant_id={currentTenant}` | `/admin/operations/{run}` | current tenant context from the shell | Operation | lifecycle state plus one truthful progress mode | none |
## Operator Surface Contract *(mandatory)*
| 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 |
|---|---|---|---|---|---|---|---|---|---|---|
| Existing OperationRun progress feedback on the tenant shell | Tenant operator | Decide whether active work is genuinely advancing or only waiting | Start-surface hint | Is this operation actually making measurable progress right now? | operation label, lifecycle state, counted or indeterminate mode, canonical open link | detailed run diagnostics and evidence on Operations pages | lifecycle, progress capability | none | `View operation`, `Show all operations` | none |
## Proportionality Review *(mandatory when structural complexity is introduced)*
- **New source of truth?**: no
- **New persisted entity/table/artifact?**: no
- **New abstraction?**: no by default; the slice reuses `OperationRunProgressContract` and `OperationRunService`
- **New enum/state/reason family?**: no
- **New cross-domain UI framework/taxonomy?**: no
- **Current operator problem**: selected high-value runs already know stable units of work, but the product often cannot show determinate progress because those counts are never written while the run is active.
- **Existing structure is insufficient because**: Spec 270 centralized rendering semantics, but the shared contract cannot infer counted progress honestly without writer-side `total` and `processed` inputs.
- **Narrowest correct implementation**: update only repo-verified stable-unit run families to initialize/increment counts through existing helpers and keep all other runs on current activity/phased/composite semantics.
- **Ownership cost**: targeted writer tests, one small standards update, and review discipline around count initialization/increment points.
- **Alternative intentionally rejected**: inferring percentage from outcome counters or forcing baseline phased runs into counted mode was rejected because that would either be dishonest or widen the slice into Spec 272.
- **Release truth**: current-release truth. The repo already contains the writers, helpers, and shell adopter needed to make selected runs truthful now.
### Compatibility posture
This feature assumes a pre-production environment.
Backward compatibility, legacy aliases, migration shims, historical fixtures, and compatibility-specific tests are out of scope unless explicitly required by this spec.
Canonical replacement of terminal-only or inconsistent counted semantics is preferred over preserving duplicate progress logic.
## Testing / Lane / Runtime Impact *(mandatory)*
- **Test purpose / classification**: Unit, Feature
- **Validation lane(s)**: fast-feedback, confidence
- **Why this classification and these lanes are sufficient**: the rollout changes runtime count truth in existing jobs and services, while the visible shell adopter is already covered by Spec 268/270. Focused domain feature tests plus the existing progress-contract unit suite are the narrowest honest proof.
- **New or expanded test families**: extend `tests/Unit/Support/OpsUx/OperationRunProgressContractTest.php` only as needed, plus current domain feature suites for inventory, review packs, evidence snapshots, backup sets, and shell progress feedback
- **Fixture / helper cost impact**: low to moderate. Reuse existing operation-run factories, tenant helpers, and current domain job tests; do not add provider-heavy browser setup or new heavy-governance families.
- **Heavy-family visibility / justification**: none
- **Special surface test profile**: global-context-shell
- **Standard-native relief or required special coverage**: ordinary Unit plus Feature coverage only. No new browser requirement is justified because the layout contract remains owned by Spec 268.
- **Reviewer handoff**: reviewers must confirm that selected run families emit truthful `total` plus `processed` counts, that excluded phased runs remain phased, that no new `summary_counts` keys appear, and that `OperationRunService` remains the only writer path.
- **Budget / baseline / trend impact**: small feature-local increase only
- **Escalation needed**: `reject-or-split` if implementation widens into baseline phased/composite work, dashboard redesign, or a new persisted progress model
- **Active feature PR close-out entry**: Guardrail / Smoke Coverage
- **Planned validation commands**:
- `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`
## User Scenarios & Testing *(mandatory)*
### User Story 1 - See truthful counted progress for inventory sync (Priority: P1)
As a tenant operator, I need inventory sync to emit real running counts for the selected stable work units, so the shell can show determinate progress only when the sync is truly advancing.
**Why this priority**: inventory sync is a core operator workflow and already has a bounded unit set through attempted policy types, which makes it the cleanest counted rollout target.
**Independent Test**: start a sync run with multiple selected policy types, drive success/failure callback paths, and verify that `total` initializes once, `processed` increments per attempted type, and the shell can render counted progress while the run is active.
**Acceptance Scenarios**:
1. **Given** an inventory sync run starts with multiple attempted policy types, **When** the run enters `running`, **Then** `summary_counts.total` reflects the attempted type count before terminal completion.
2. **Given** an attempted type finishes successfully or fails, **When** the callback reports that result, **Then** `summary_counts.processed` increments once and the corresponding outcome counter updates without exceeding `total`.
3. **Given** the run completes, **When** terminal summary is written, **Then** `processed`, `total`, and outcome counters remain internally consistent and no fake counted mode is introduced for excluded or skipped work.
---
### User Story 2 - See truthful counted progress for evidence and review artifact generation (Priority: P1)
As a tenant operator, I need review-pack generation and evidence-snapshot generation to surface real running counts, so governance artifact work no longer looks indistinguishable from generic background activity.
**Why this priority**: these operations are visible, valuable, and already have deterministic work sets in current code (`fileMap` entries and payload items).
**Independent Test**: queue review-pack and evidence-snapshot runs, verify that each job initializes `total` from its deterministic work set, increments `processed` as entries are generated, and preserves truthful terminal summaries.
**Acceptance Scenarios**:
1. **Given** a review-pack job builds its ZIP file map, **When** generation begins, **Then** the run initializes `summary_counts.total` from the post-option-filtered file set and increments `processed` as files are added to the archive.
2. **Given** an evidence-snapshot job receives a payload with snapshot items, **When** the job persists those items, **Then** the run initializes `total` from the payload item count and increments `processed` as items are created.
3. **Given** either job fails before all units complete, **When** the run becomes terminal, **Then** counted progress stops, terminal outcome stays authoritative, and the shell does not keep a stale determinate percentage.
---
### User Story 3 - Standardize counted progress for existing backup and restore bulk fan-out paths (Priority: P2)
As a tenant operator, I need current backup and restore bulk fan-out operations to follow one total/processed discipline, so bulk backup/restore work does not oscillate between accurate counts and partial-count drift.
**Why this priority**: backup/restore fan-out already contains partial counted seams in repo-real jobs, so standardization is lower-risk than greenfield rollout and strengthens an operator-critical workflow family.
**Independent Test**: run existing backup-set add and bulk restore flows with mixed success, skip, and failure outcomes, then verify that launchers initialize totals once, workers increment `processed` exactly once per unit, and `maybeCompleteBulkRun()` closes the run only when all units are accounted for.
**Acceptance Scenarios**:
1. **Given** a bulk backup/restore launcher enqueues child work for a bounded ID set, **When** the bulk run starts, **Then** `summary_counts.total` is initialized once from the deduplicated ID list.
2. **Given** each child worker succeeds, skips, or fails, **When** it reports its outcome, **Then** `processed` increments exactly once per child and `maybeCompleteBulkRun()` closes the parent only after `processed >= total`.
3. **Given** `BackupSetDeleteWorkerJob` or `BackupSetForceDeleteWorkerJob` is reviewed during implementation, **When** the path is not one of the enumerated `271` seams, **Then** it remains follow-up work and does not receive counted rollout in this slice.
### Edge Cases
- Selected run families with zero measurable units must initialize truthfully and avoid impossible percentages or divide-by-zero behavior.
- Dedupe, archived, skipped, and not-found paths must still advance `processed` exactly once when they consume one planned work unit.
- `processed` must never exceed `total`, even when workers retry or a launcher accidentally replays a child.
- Runs that already expose `phased` or `composite` hints through `OperationRunProgressContract` must stay on those modes in this slice; the rollout must not silently reorder contract precedence.
- Terminal `succeeded`, `failed`, `skipped`, `created`, or `updated` counters must remain summary truth only and never become back-door progress substitutes.
## Requirements *(mandatory)*
**Constitution alignment summary**: This feature introduces no new Graph contract, no new persistence, no new lifecycle state, and no new `summary_counts` key. It only rolls out trustworthy counted inputs for selected existing `OperationRun` writers and keeps all progress disclosure on the current shared contract.
### Functional Requirements
- **FR-001**: The implementation MUST reuse `App\Support\OpsUx\OperationRunProgressContract`, `App\Services\OperationRunService`, `App\Support\OpsUx\SummaryCountsNormalizer`, and `App\Support\OpsUx\OperationSummaryKeys` as the only counted-progress contract and summary-count writing path.
- **FR-002**: The v1 counted-rollout target set is limited to repo-verified stable-unit run families: inventory sync, review-pack generation, evidence-snapshot generation, `AddPoliciesToBackupSetJob`, `BulkBackupSetRestoreJob`, and `BackupSetRestoreWorkerJob`.
- **FR-003**: For each selected run family, `summary_counts.total` MUST be initialized before or at the start of measurable work from a deterministic unit set already known to the current job/service.
- **FR-004**: For each selected run family, `summary_counts.processed` MUST increment as each planned unit reaches a terminal per-unit outcome (`succeeded`, `failed`, or `skipped`) and MUST remain `<= total`.
- **FR-005**: `summary_counts.succeeded`, `summary_counts.failed`, `summary_counts.skipped`, `summary_counts.created`, and `summary_counts.updated` remain outcome counters or secondary summaries. They MUST NOT replace `processed` as the counted-progress source.
- **FR-006**: Parent bulk runs that already use `OperationRunService::maybeCompleteBulkRun()` MUST keep using that helper rather than open-coding bulk completion rules.
- **FR-007**: Review-pack generation MUST derive its counted unit set from the actual post-option-filtered file map that is written into the ZIP archive, not from a speculative or pre-redaction estimate.
- **FR-008**: Evidence-snapshot generation MUST derive its counted unit set from the actual payload item set that will be persisted for the snapshot, not from later terminal summary fields.
- **FR-009**: Inventory sync MUST use stable currently attempted work units from the current selection/callback path and MUST NOT derive percentages from observed item counts alone when those item counts are only known at the end.
- **FR-010**: This slice MUST NOT force baseline capture or baseline compare onto counted progress while `OperationRunProgressContract` still classifies those runs through phased evidence-capture hints. That deviation from the original candidate wording is intentional repo-truth narrowing, not accidental omission.
- **FR-011**: The feature MUST update `docs/ui/tenantpilot-enterprise-ui-standards.md` to record which current run families may claim counted progress under Spec 270 and which families remain activity-only or phased/composite.
- **FR-012**: The feature MUST NOT add new `summary_counts` keys, new progress capabilities, new notification surfaces, new polling loops, or a second progress calculator in Blade/Livewire code.
### Authorization and Safety Requirements
- **AR-001**: Existing tenant/admin-plane authorization remains unchanged: non-members or out-of-scope actors stay `404`, and member-but-missing-capability stays `403`.
- **AR-002**: No in-scope surface may show counted progress for a run the current actor cannot already view through existing `OperationRun` policies.
- **AR-003**: No new destructive or state-changing UI action is introduced. Existing launch surfaces keep their current authorization and confirmation rules.
### Non-Functional Requirements
- **NFR-001**: Filament remains v5 on Livewire v4. No panel-provider registration change is allowed; `apps/platform/bootstrap/providers.php` remains authoritative.
- **NFR-002**: No new panel, globally searchable resource, or asset-registration strategy is allowed.
- **NFR-003**: No new parallel polling loop is allowed. Existing shell and monitoring pollers remain unchanged.
- **NFR-004**: Summary-count writes remain numeric-only and sanitize through existing whitelist semantics.
- **NFR-005**: The rollout must stay bounded enough that all changed run families can be proved with file-scoped Pest commands rather than a new heavy-governance or browser family.
## Deferred Follow-Ups / Explicit Non-Goals
- `272 - OperationRun Phase & Composite Progress v1`
- `273 - Tenant Dashboard Active Operations Summary Card`
- broad counted rollout across all remaining `OperationRun` writers
- baseline capture or baseline compare counted rollout while those runs still advertise phased evidence-capture hints through the current progress contract
- any new persisted progress model, telemetry registry, or dashboard/activity redesign
- any change to queued/terminal notification policy or current shell layout contract
## Key Entities
- **Counted Progress Rollout Unit**: the deterministic per-run-family work unit that can safely drive `total` plus `processed` without inventing progress.
- **Writer-side Count Initialization**: the point where a selected job or service seeds `summary_counts.total` from a bounded current work set.
- **Writer-side Count Advancement**: the point where a selected job or worker increments `processed` plus the relevant outcome counters exactly once per planned unit.
- **Excluded Phased Run Family**: a run family, such as baseline capture/compare under current repo truth, that remains on phased/composite hints instead of counted rollout.
## Success Criteria *(mandatory)*
- Selected run families emit truthful `total` plus `processed` counts during execution and no longer depend on terminal-only summary updates for visible progress.
- The tenant shell can show determinate counted progress for those selected run families through the existing `OperationRunProgressContract` without any view-local math changes.
- Excluded phased/composite families remain on their current truthful modes and are not silently forced into counted percentages.
- No new `summary_counts` keys, statuses, persistence layers, or notification policies are introduced.
- Focused Unit plus Feature suites prove the rollout for every selected run family and catch any attempt to exceed `processed > total` or to derive counted progress from outcome counters.
## Assumptions
- Spec 270 remains the authoritative progress contract and stays unchanged except for consuming new truthful writer-side counts.
- Review-pack file-map entries and evidence-snapshot payload items are stable enough in current repo truth to serve as counted work units.
- Existing bulk backup/restore workers already represent one child-per-planned-unit semantics where counted rollout is justified.
## Risks
- Review-pack generation can easily over-count if totals are derived before options remove files from the final archive.
- Inventory sync may regress into impossible percentages if retries or callback reuse increment `processed` more than once per attempted type.
- Backup/restore bulk launchers can drift if `total` is initialized repeatedly or if child workers increment `processed` on both retry and success paths.
- Pulling baseline capture/compare into this slice would conflict with the existing phased/composite precedence and reopen Spec 272 implicitly.
## Open Questions
- None blocking safe implementation. If any currently assumed stable unit set proves non-deterministic during implementation, that run family must move to a follow-up spec instead of widening this slice.