Some checks failed
Main Confidence / confidence (push) Failing after 54s
## Summary - harden baseline capture truth, compare readiness, and monitoring explanations around latest inventory eligibility, blocked prerequisites, and zero-subject outcomes - improve onboarding verification and bootstrap recovery handling, including admin-consent callback invalidation and queued execution legitimacy/report behavior - align workspace findings/workspace overview signals and refresh the related spec, roadmap, and spec-candidate artifacts ## Validation - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/BaselineDriftEngine/BaselineCaptureAuditEventsTest.php tests/Feature/BaselineDriftEngine/BaselineSnapshotNoTenantIdentifiersTest.php tests/Feature/BaselineDriftEngine/CaptureBaselineContentTest.php tests/Feature/BaselineDriftEngine/CaptureBaselineFullContentOnDemandTest.php tests/Feature/BaselineDriftEngine/CaptureBaselineMetaFallbackTest.php tests/Feature/Baselines/BaselineCaptureTest.php tests/Feature/Baselines/BaselineCompareFindingsTest.php tests/Feature/Baselines/BaselineSnapshotBackfillTest.php tests/Feature/Filament/BaselineCaptureResultExplanationSurfaceTest.php tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php tests/Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php tests/Feature/Filament/OperationRunBaselineTruthSurfaceTest.php tests/Feature/Monitoring/AuditCoverageGovernanceTest.php tests/Feature/Monitoring/GovernanceOperationRunSummariesTest.php tests/Feature/Notifications/OperationRunNotificationTest.php tests/Feature/Authorization/OperatorExplanationSurfaceAuthorizationTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/AdminConsentCallbackTest.php tests/Feature/Filament/WorkspaceOverviewDbOnlyTest.php tests/Feature/Guards/Spec194GovernanceActionSemanticsGuardTest.php tests/Feature/ManagedTenantOnboardingWizardTest.php tests/Feature/Onboarding/OnboardingVerificationTest.php tests/Feature/Operations/QueuedExecutionAuditTrailTest.php tests/Unit/Operations/QueuedExecutionLegitimacyGateTest.php` ## Notes - browser validation was not re-run in this pass Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #271
268 lines
27 KiB
Markdown
268 lines
27 KiB
Markdown
# Implementation Plan: Baseline Capture Truthful Outcomes and Upstream Guardrails
|
|
|
|
**Branch**: `235-baseline-capture-truth` | **Date**: 2026-04-23 | **Spec**: [spec.md](./spec.md)
|
|
**Input**: Feature specification from `/specs/235-baseline-capture-truth/spec.md`
|
|
|
|
**Note**: This plan keeps the slice intentionally narrow. It reuses the existing `BaselineSnapshot` lifecycle/usability model and the existing Ops UX explanation path, then hardens only baseline-capture eligibility, outcome mapping, no-data artifact handling, and current-baseline promotion.
|
|
|
|
## Summary
|
|
|
|
Harden baseline capture so it only succeeds when there is a credible inventory basis and at least one in-scope subject produces a consumable snapshot. The implementation will extend the existing capture reason-code family, make `BaselineCaptureService` evaluate the latest relevant inventory sync before enqueue, re-check the same prerequisite inside `CaptureBaselineSnapshotJob`, map zero-subject captures to `partially_succeeded` plus no-data artifact truth, keep `BaselineProfile.active_snapshot_id` anchored to the last consumable snapshot, and route operator messaging through the existing `ReasonTranslator`, `BaselineCompareStats`, and `GovernanceRunDiagnosticSummaryBuilder` paths instead of adding page-local copy branches.
|
|
|
|
## Technical Context
|
|
|
|
**Language/Version**: PHP 8.4.15, Laravel 12, Filament v5, Livewire v4
|
|
**Primary Dependencies**: `BaselineCaptureService`, `CaptureBaselineSnapshotJob`, `BaselineReasonCodes`, `BaselineCompareStats`, `ReasonTranslator`, `GovernanceRunDiagnosticSummaryBuilder`, `OperationRunService`, `BaselineProfile`, `BaselineSnapshot`, `OperationRunOutcome`, existing Filament capture/compare surfaces
|
|
**Storage**: Existing PostgreSQL tables only; no new table or schema migration is planned in the mainline slice
|
|
**Testing**: Pest v4 feature tests through Laravel Sail
|
|
**Validation Lanes**: `fast-feedback`, `confidence`
|
|
**Target Platform**: Laravel admin web application in Sail containers with workspace-admin routes under `/admin` and tenant routes under `/admin/t/{tenant}`
|
|
**Project Type**: Monorepo with one Laravel runtime in `apps/platform` and spec artifacts at repository root
|
|
**Performance Goals**: Preserve current capture request and queued-job behavior; add at most one focused latest-inventory eligibility lookup per capture attempt and no new high-cardinality UI rendering path
|
|
**Constraints**: No stale successful inventory fallback, no new persisted entity or lifecycle state, no new generic artifact-truth framework, no auth-plane expansion, and no drift of message semantics into page-local copy
|
|
**Scale/Scope**: One existing queued workflow (`baseline_capture`), one reason-code family extension, two existing start surfaces, one snapshot detail surface, one Monitoring run-detail explanation path, and focused baseline/Monitoring test families
|
|
|
|
## Filament v5 Implementation Contract
|
|
|
|
- **Livewire v4.0+ compliance**: Preserved. The plan changes existing Filament actions and shared presenters only; it introduces no legacy Livewire patterns.
|
|
- **Provider registration location**: Unchanged. Panel providers remain registered in `apps/platform/bootstrap/providers.php`.
|
|
- **Global search coverage**: `BaselineProfileResource` and `BaselineSnapshotResource` both keep global search disabled via `$isGloballySearchable = false`, so this slice adds no global-search exposure and no new view/edit requirement.
|
|
- **Destructive actions**: No destructive action is added or changed. The existing `Archive baseline profile` action already uses `->requiresConfirmation()` and remains on its current path.
|
|
- **Asset strategy**: No new assets are planned. Deployment expectations remain unchanged, including `cd apps/platform && php artisan filament:assets` only when future work introduces registered assets.
|
|
- **Testing plan**: Prove the slice with focused Pest feature coverage for baseline capture service/start surfaces, retained consumable happy-path success, compare landing readiness, snapshot-detail no-data truth, Monitoring run summaries, and the existing audit/terminal-notification contract for `baseline_capture`.
|
|
|
|
## UI / Surface Guardrail Plan
|
|
|
|
- **Guardrail scope**: changed surfaces
|
|
- **Native vs custom classification summary**: native
|
|
- **Shared-family relevance**: status messaging, header actions, run-detail explanations, audit-aligned summaries
|
|
- **State layers in scope**: page, detail
|
|
- **Handling modes by drift class or surface**: review-mandatory
|
|
- **Repository-signal treatment**: review-mandatory
|
|
- **Special surface test profiles**: `standard-native-filament`, `monitoring-state-page`
|
|
- **Required tests or manual smoke**: `functional-core`, `state-contract`
|
|
- **Exception path and spread control**: none planned; any unavoidable message deviation must stay bounded to the existing baseline shared presenter/translator path
|
|
- **Active feature PR close-out entry**: `Guardrail`
|
|
|
|
## Shared Pattern & System Fit
|
|
|
|
- **Cross-cutting feature marker**: yes
|
|
- **Systems touched**: baseline capture start surfaces, compare availability/readiness surfaces, baseline snapshot truth presentation, Monitoring run detail, audit prose, canonical reason translation
|
|
- **Shared abstractions reused**: `BaselineReasonCodes`, `BaselineCompareStats`, `ReasonTranslator`, `OperationRunService`, `OperationUxPresenter`, `GovernanceRunDiagnosticSummaryBuilder`, `OperatorExplanationBuilder`
|
|
- **New abstraction introduced? why?**: none planned. If inventory-eligibility logic needs reuse across start-time and runtime recheck, keep it as a narrow `BaselineCaptureService`-owned method or tiny baseline-local helper rather than a new registry/resolver layer.
|
|
- **Why the existing abstraction was sufficient or insufficient**: Existing abstractions are sufficient for translation, explanation, and compare-readiness messaging. The current gap is that capture eligibility and no-data truth do not yet feed those shared paths consistently.
|
|
- **Bounded deviation / spread control**: none
|
|
|
|
## Constitution Check
|
|
|
|
*GATE: Passed before Phase 0 research. Re-check after Phase 1 design: still passed with no new persistence, no new UI framework, and no auth-plane drift.*
|
|
|
|
| Gate | Status | Plan Notes |
|
|
|------|--------|------------|
|
|
| Inventory-first / read-write separation | PASS | The slice makes capture depend on the latest credible inventory truth and does not introduce any new Graph write or preview path. |
|
|
| RBAC, workspace isolation, tenant isolation | PASS | No new routes or capabilities are introduced; existing `/admin`, `/admin/t/{tenant}`, and canonical Monitoring entitlement rules remain authoritative. |
|
|
| Run observability / Ops-UX lifecycle | PASS | Existing `baseline_capture` `OperationRun` remains the queued-work truth. Known start-surface preconditions may still short-circuit with no run, while queued runtime rechecks will resolve through `OperationRunService` only. |
|
|
| Shared pattern first | PASS | The plan extends existing reason translation and run-summary builders instead of adding page-local message trees. |
|
|
| Proportionality / no premature abstraction | PASS | No new persistence or subsystem is planned. The only structural addition is a bounded extension of existing capture reason codes plus reuse of current services/presenters. |
|
|
| Persisted truth / behavioral state | PASS | No new table or snapshot lifecycle state is added. No-data capture uses existing snapshot lifecycle/usability semantics if an artifact row is kept. |
|
|
| Badge semantics / Filament-native discipline | PASS | Existing badge/outcome semantics remain centralized; touched surfaces stay on native Filament actions and shared presenters. |
|
|
| Filament v5 / Livewire v4 contract | PASS | Provider registration, global-search posture, and destructive-action discipline remain unchanged and compliant. |
|
|
| Test governance | PASS | Proof stays in focused baseline and Monitoring feature lanes without heavy-governance or browser expansion. |
|
|
|
|
## Test Governance Check
|
|
|
|
- **Test purpose / classification by changed surface**: `Feature` for service/start-surface, compare-readiness, retained consumable success, snapshot-detail truth, and Monitoring truth
|
|
- **Affected validation lanes**: `fast-feedback`, `confidence`
|
|
- **Why this lane mix is the narrowest sufficient proof**: The business truth lives in existing capture execution, existing Filament surfaces, and existing Monitoring detail. Focused feature tests prove the slice end-to-end without widening into browser or heavy-governance families.
|
|
- **Narrowest proving command(s)**:
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Baselines/BaselineCaptureTest.php`
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php tests/Feature/Filament/BaselineCaptureResultExplanationSurfaceTest.php`
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/OperationRunBaselineTruthSurfaceTest.php tests/Feature/Monitoring/GovernanceOperationRunSummariesTest.php tests/Feature/Authorization/OperatorExplanationSurfaceAuthorizationTest.php tests/Feature/Monitoring/AuditCoverageGovernanceTest.php tests/Feature/Notifications/OperationRunNotificationTest.php`
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Baselines/BaselineSnapshotBackfillTest.php` only if legacy empty-snapshot classification changes prove necessary during implementation
|
|
- **Fixture / helper / factory / seed / context cost risks**: Moderate. The slice needs explicit inventory-run outcome fixtures (`no inventory`, `blocked`, `failed`, `unusable coverage`, `after-enqueue drift to non-credible`, `credible but zero subjects`, `previous complete snapshot still current`) and must keep those scenarios opt-in rather than adding new default helpers.
|
|
- **Expensive defaults or shared helper growth introduced?**: No. New inventory eligibility scenarios should stay local to baseline capture tests.
|
|
- **Heavy-family additions, promotions, or visibility changes**: none
|
|
- **Surface-class relief / special coverage rule**: `standard-native relief` for profile/compare surfaces, `monitoring-state-page` for run-detail explanation assertions
|
|
- **Closing validation and reviewer handoff**: Reviewers should verify that no test still encodes empty capture as unconditional success, that unusable coverage and after-enqueue prerequisite drift are proved explicitly, that `active_snapshot_id` never advances on blocked/zero-subject capture paths, that compare landing still derives readiness from consumable baseline truth, that snapshot detail distinguishes no-data evidence from current baseline truth, and that Monitoring, audit prose, and terminal notification copy lead with the same dominant cause before diagnostics.
|
|
- **Budget / baseline / trend follow-up**: none expected beyond a small increase in baseline and Monitoring feature assertions
|
|
- **Review-stop questions**: Did any new helper start hiding expensive inventory/run setup? Did the plan accidentally widen into compare-engine or generic artifact-state work? Did any runtime branch bypass `OperationRunService`? Did any surface add local copy that duplicates the shared reason/summary path?
|
|
- **Escalation path**: `document-in-feature` unless legacy empty-snapshot backfill proves structurally necessary, in which case reassess inside this feature before widening further
|
|
- **Active feature PR close-out entry**: `Guardrail`
|
|
- **Why no dedicated follow-up spec is needed**: The slice is a bounded hardening change on one existing workflow and one existing operator truth family. Only a forced legacy-row reclassification problem would justify widening further.
|
|
|
|
## Project Structure
|
|
|
|
### Documentation (this feature)
|
|
|
|
```text
|
|
specs/235-baseline-capture-truth/
|
|
├── spec.md
|
|
├── plan.md
|
|
├── research.md
|
|
├── data-model.md
|
|
├── quickstart.md
|
|
├── checklists/
|
|
│ └── requirements.md
|
|
└── tasks.md
|
|
```
|
|
|
|
No contracts artifact is planned because this feature changes no external API, route contract, or standalone logical interaction contract.
|
|
|
|
### Source Code (repository root)
|
|
|
|
```text
|
|
apps/platform/
|
|
├── app/
|
|
│ ├── Filament/
|
|
│ │ ├── Pages/
|
|
│ │ │ └── BaselineCompareLanding.php
|
|
│ │ └── Resources/
|
|
│ │ ├── BaselineSnapshotResource/
|
|
│ │ │ └── Pages/
|
|
│ │ │ └── ViewBaselineSnapshot.php
|
|
│ │ └── BaselineProfileResource/
|
|
│ │ └── Pages/
|
|
│ │ └── ViewBaselineProfile.php
|
|
│ ├── Jobs/
|
|
│ │ └── CaptureBaselineSnapshotJob.php
|
|
│ ├── Models/
|
|
│ │ ├── BaselineProfile.php
|
|
│ │ └── BaselineSnapshot.php
|
|
│ ├── Notifications/
|
|
│ │ └── OperationRunCompleted.php
|
|
│ ├── Services/
|
|
│ │ ├── OperationRunService.php
|
|
│ │ └── Baselines/
|
|
│ │ └── BaselineCaptureService.php
|
|
│ └── Support/
|
|
│ ├── Baselines/
|
|
│ │ ├── BaselineCompareStats.php
|
|
│ │ └── BaselineReasonCodes.php
|
|
│ ├── OpsUx/
|
|
│ │ ├── GovernanceRunDiagnosticSummaryBuilder.php
|
|
│ │ └── OperationUxPresenter.php
|
|
│ ├── ReasonTranslation/
|
|
│ │ └── ReasonTranslator.php
|
|
│ └── Ui/
|
|
│ └── OperatorExplanation/
|
|
│ └── OperatorExplanationBuilder.php
|
|
└── tests/
|
|
├── Feature/
|
|
│ ├── Authorization/
|
|
│ │ └── OperatorExplanationSurfaceAuthorizationTest.php
|
|
│ ├── Baselines/
|
|
│ │ ├── BaselineCaptureTest.php
|
|
│ │ └── BaselineSnapshotBackfillTest.php
|
|
│ ├── Filament/
|
|
│ │ ├── BaselineCaptureResultExplanationSurfaceTest.php
|
|
│ │ ├── BaselineCompareLandingStartSurfaceTest.php
|
|
│ │ ├── BaselineProfileCaptureStartSurfaceTest.php
|
|
│ │ └── OperationRunBaselineTruthSurfaceTest.php
|
|
│ ├── Notifications/
|
|
│ │ └── OperationRunNotificationTest.php
|
|
│ └── Monitoring/
|
|
│ ├── AuditCoverageGovernanceTest.php
|
|
│ └── GovernanceOperationRunSummariesTest.php
|
|
```
|
|
|
|
**Structure Decision**: Keep the work entirely inside the existing Laravel runtime in `apps/platform`. The slice changes one existing queued workflow, two existing Filament start surfaces, one immutable snapshot detail surface, shared compare-readiness and explanation helpers, the existing audit/notification composition path, and focused regression families. No new module or subsystem is introduced.
|
|
|
|
## Complexity Tracking
|
|
|
|
No constitutional violation is planned. No complexity exception is currently required.
|
|
|
|
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
|
|-----------|------------|-------------------------------------|
|
|
| — | — | — |
|
|
|
|
## Proportionality Review
|
|
|
|
- **Current operator problem**: Baseline capture can report success even when no trustworthy baseline exists, which directly misleads operators and auditors.
|
|
- **Existing structure is insufficient because**: `BaselineCaptureService` currently validates only profile/tenant/scope preconditions, and `CaptureBaselineSnapshotJob` promotes `active_snapshot_id` whenever a consumable snapshot exists or can be reused, including all-zero paths that are not decision-grade.
|
|
- **Narrowest correct implementation**: Extend the existing capture reason-code family, reuse the existing snapshot lifecycle/usability model, add one shared inventory-eligibility evaluation path for start-time and runtime recheck, and adapt existing translator/stats/run-summary surfaces.
|
|
- **Ownership cost created**: A few new reason-code translations, one extra eligibility branch in capture service/job, a small amount of extra run-context metadata, and focused regression fixtures for inventory-run truth.
|
|
- **Alternative intentionally rejected**: A generic artifact-no-data framework or stale-inventory fallback. The first imports too much structure; the second would preserve false reassurance.
|
|
- **Release truth**: current-release truth
|
|
|
|
## Phase 0 Research Summary
|
|
|
|
- `BaselineCaptureService` is the current start-time gate and can reject capture without creating an `OperationRun`; it is the right place for latest-inventory eligibility preflight.
|
|
- `CaptureBaselineSnapshotJob` currently updates `active_snapshot_id` whenever the resulting snapshot is consumable and currently treats `expected_items === 0` as a valid complete capture. That is the concrete root of the false-green/no-data promotion problem.
|
|
- `BaselineReasonCodes`, `ReasonTranslator`, `BaselineCompareStats`, and `GovernanceRunDiagnosticSummaryBuilder` already centralize the operator language for baseline truth and Monitoring explanations; they are the right shared paths to extend.
|
|
- `BaselineProfile::resolveCurrentConsumableSnapshot()` already falls back to the latest complete snapshot when `active_snapshot_id` is unusable, so preserving the previous trustworthy baseline is already supported if the capture path stops advancing `active_snapshot_id` incorrectly.
|
|
- `OperationRunOutcome::PartiallySucceeded` already exists and is already rendered consistently across Ops UX, badges, and Monitoring; no new run-outcome family is needed.
|
|
- Legacy empty-snapshot backfill currently classifies proven empty captures as `complete`. The mainline plan does not widen into migration/backfill unless implementation proves that historical empty snapshots still act as current truth in active runtime paths.
|
|
|
|
## Phase 1 Design Summary
|
|
|
|
- `research.md` records the product and architectural decisions: strict latest-inventory truth, no stale fallback, no new snapshot state, and reuse of shared reason/summary infrastructure.
|
|
- `data-model.md` documents the touched existing truths: `BaselineProfile.active_snapshot_id`, `BaselineSnapshot.lifecycle_state` plus completion metadata, and `OperationRun.context` keys for inventory eligibility and current-baseline-change effect.
|
|
- `quickstart.md` gives the narrow validation order for service preflight, queued runtime recheck, no-data capture, compare-readiness truth, snapshot-detail truth, Monitoring explanation, and audit/notification alignment.
|
|
- No contracts artifact is planned because this slice changes no external API or logical interaction contract.
|
|
|
|
## Phase 1 — Agent Context Update
|
|
|
|
Run after artifact generation:
|
|
|
|
- `.specify/scripts/bash/update-agent-context.sh copilot`
|
|
|
|
## Implementation Strategy
|
|
|
|
### Phase A — Extend capture eligibility around the latest credible inventory run
|
|
|
|
**Goal**: Make capture start and queued execution agree on whether the latest relevant inventory basis is trustworthy enough to build a baseline.
|
|
|
|
| Step | File | Change |
|
|
|------|------|--------|
|
|
| A.1 | `apps/platform/app/Support/Baselines/BaselineReasonCodes.php` | Add the bounded capture reason codes for missing latest inventory, blocked latest inventory, failed latest inventory, unusable coverage, and zero-subject outcome. Keep them in the existing reason-code family. |
|
|
| A.2 | `apps/platform/app/Services/Baselines/BaselineCaptureService.php` | Extend `validatePreconditions()` with a reusable latest-inventory eligibility decision that inspects the most recent relevant inventory sync and returns the new capture reason codes without creating an `OperationRun` when the block is already known at start time. |
|
|
| A.3 | `apps/platform/app/Support/ReasonTranslation/ReasonTranslator.php` | Add operator-safe translations and next steps for the new baseline-capture reason codes so profile/start-surface, Monitoring, and audit-aligned prose stay consistent. |
|
|
| A.4 | `apps/platform/app/Jobs/CaptureBaselineSnapshotJob.php` | Re-check the same eligibility after the run starts, so prerequisite drift between page load and execution resolves through `OperationRunService` with `completed + blocked` rather than a false green run. |
|
|
|
|
### Phase B — Stop no-data captures from becoming current baseline truth
|
|
|
|
**Goal**: Treat zero-subject capture as real audit evidence with follow-up, not as a trustworthy baseline refresh, and keep compare readiness anchored to the same consumable-truth contract.
|
|
|
|
| Step | File | Change |
|
|
|------|------|--------|
|
|
| B.1 | `apps/platform/app/Jobs/CaptureBaselineSnapshotJob.php` | Split the zero-subject path from the normal consumable-snapshot path before any existing consumable snapshot is reused or `active_snapshot_id` is advanced. |
|
|
| B.2 | `apps/platform/app/Jobs/CaptureBaselineSnapshotJob.php` | Map zero-subject capture to `OperationRunOutcome::PartiallySucceeded`, record the new reason code in run context, keep numeric `summary_counts`, record `baseline_capture.subjects_total`, record `result.snapshot_lifecycle` when an artifact exists, and record whether current baseline truth changed. |
|
|
| B.3 | `apps/platform/app/Models/BaselineSnapshot.php` and job call sites | Reuse the existing lifecycle/usability model if a no-data artifact row is retained: mark it non-consumable via existing incomplete semantics and store the finalization reason in `completion_meta_jsonb` rather than introducing a new snapshot state. |
|
|
| B.4 | `apps/platform/app/Models/BaselineProfile.php` and job promotion path | Preserve the previously consumable snapshot by ensuring `active_snapshot_id` is updated only when the new capture result is actually consumable. |
|
|
| B.5 | `apps/platform/app/Filament/Resources/BaselineSnapshotResource/Pages/ViewBaselineSnapshot.php` and `apps/platform/app/Filament/Resources/BaselineProfileResource/Pages/ViewBaselineProfile.php` | Distinguish current trustworthy baseline truth from no-data evidence on snapshot and profile detail surfaces so operators do not read a zero-subject artifact as a normal refresh. |
|
|
| B.6 | `apps/platform/app/Support/Baselines/BaselineCompareStats.php` | Extend compare-readiness and missing-snapshot guidance so compare landing and profile-level compare affordances can explain why compare is unavailable after a blocked, failed, or zero-subject capture without inferring success from snapshot existence or the latest run alone. |
|
|
| B.7 | `apps/platform/app/Filament/Pages/BaselineCompareLanding.php` | Keep compare availability derived from consumable baseline truth and show the updated explanation-first guidance when the latest capture failed, drifted to a non-credible prerequisite, or produced no usable baseline. |
|
|
|
|
### Phase C — Align Monitoring explanation and shared audit/notification copy with the hardened capture truth
|
|
|
|
**Goal**: Make Monitoring and the existing completion summary path speak the same truthful baseline-capture language as the hardened capture and compare-readiness surfaces.
|
|
|
|
| Step | File | Change |
|
|
|------|------|--------|
|
|
| C.1 | `apps/platform/app/Support/OpsUx/GovernanceRunDiagnosticSummaryBuilder.php` | Teach baseline-capture summaries to distinguish blocked latest-inventory prerequisites, after-enqueue prerequisite drift, and zero-subject no-data captures from normal success before diagnostics are shown. |
|
|
| C.2 | `apps/platform/app/Support/OpsUx/OperationUxPresenter.php`, `apps/platform/app/Support/Ui/OperatorExplanation/OperatorExplanationBuilder.php`, and `apps/platform/app/Notifications/OperationRunCompleted.php` | Keep Monitoring, audit prose, and terminal notification copy aligned to the same dominant baseline-capture reason, whether current baseline truth changed, and initiator-aware notification rules. |
|
|
|
|
### Phase D — Audit, test, and edge-condition follow-through
|
|
|
|
**Goal**: Lock the hardened truth into the existing regression families and keep historical edge cases explicit.
|
|
|
|
| Step | File | Change |
|
|
|------|------|--------|
|
|
| D.1 | `apps/platform/tests/Feature/Baselines/BaselineCaptureTest.php` | Replace the implicit “empty capture succeeds” assumption with explicit coverage for no inventory, blocked inventory, failed inventory, unusable coverage, after-enqueue prerequisite drift, zero subjects, and previous snapshot preservation. |
|
|
| D.2 | `apps/platform/tests/Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php`, `apps/platform/tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`, `apps/platform/tests/Feature/Filament/BaselineCaptureResultExplanationSurfaceTest.php` | Prove capture preflight messaging, compare readiness, snapshot-detail no-data truth, and no-data explanation on the affected Filament surfaces. |
|
|
| D.3 | `apps/platform/tests/Feature/Filament/OperationRunBaselineTruthSurfaceTest.php`, `apps/platform/tests/Feature/Monitoring/GovernanceOperationRunSummariesTest.php`, `apps/platform/tests/Feature/Monitoring/AuditCoverageGovernanceTest.php`, and `apps/platform/tests/Feature/Notifications/OperationRunNotificationTest.php` | Prove Monitoring detail separates blocked/no-data capture truth from raw counts and generic success wording, and that audit summary plus terminal notification copy preserve the same dominant reason with initiator-aware delivery rules. |
|
|
| D.4 | `apps/platform/tests/Feature/Authorization/OperatorExplanationSurfaceAuthorizationTest.php` | Keep the authorized happy-path surface access proof explicit and preserve 404 vs 403 semantics on the touched explanation-first surfaces. |
|
|
| D.5 | `apps/platform/tests/Feature/Baselines/BaselineSnapshotBackfillTest.php` | Only if implementation proves legacy empty snapshots still participate in active runtime truth, adjust the legacy classification rule and regression accordingly inside this feature instead of adding a second follow-up spec. |
|
|
|
|
## Risks and Mitigations
|
|
|
|
- **Local copy drift on capture surfaces**: Existing Filament actions currently branch on reason code locally. Mitigation: converge on `ReasonTranslator` instead of adding more local message cases.
|
|
- **Zero-subject path still reuses a historical empty complete snapshot**: Current job flow can reuse an existing consumable snapshot before creating a new one. Mitigation: short-circuit zero-subject handling before `findExistingConsumableSnapshot()` or any `active_snapshot_id` promotion logic can make it authoritative.
|
|
- **Queued runtime recheck bypasses Ops-UX rules**: It is easy to update context only and forget terminal run outcome. Mitigation: all blocked/partial terminal states remain service-owned through `OperationRunService` and keep numeric summary counts.
|
|
- **Legacy empty backfill broadens the slice unexpectedly**: Historical classification may need adjustment if runtime truth still depends on it. Mitigation: treat it as a conditional step inside this feature, only if a focused regression proves it is necessary.
|
|
|
|
## Post-Design Re-check
|
|
|
|
The package remains constitution-compliant, Livewire v4 / Filament v5 compliant, and narrow. It introduces no new persistence, no new UI framework, no new auth plane, and no new operation type. It reuses the existing baseline snapshot lifecycle/usability truth and the existing shared reason/Monitoring explanation paths, and the generated implementation artifacts are aligned for execution.
|