TenantAtlas/specs/174-evidence-freshness-publication-trust/plan.md
2026-04-04 13:29:40 +02:00

295 lines
23 KiB
Markdown

# Implementation Plan: Evidence Temporal Freshness & Review Publication Trust
**Branch**: `174-evidence-freshness-publication-trust` | **Date**: 2026-04-04 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/174-evidence-freshness-publication-trust/spec.md`
**Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/174-evidence-freshness-publication-trust/spec.md`
## Summary
Harden evidence freshness and publication trust across the existing evidence snapshot, tenant review, review pack, evidence overview, and canonical review register surfaces without adding new persistence, a new trust layer, or a new reporting subsystem. The implementation will reuse the source-derived stale semantics and their existing source-defined freshness thresholds, tighten propagation in `ArtifactTruthPresenter`, keep review readiness and publication readiness distinct, preserve the current tenant and canonical routes and action inventory, and close the existing cross-surface gap where stale or partial evidence can still look publishable.
Key approach: keep the work inside the current `EvidenceSnapshotService` freshness semantics, `TenantReviewReadinessGate`, `ArtifactTruthPresenter`, tenant-scoped Filament resources, and canonical summary pages. The slice is primarily about better derivation and consistent display, not about new models or new workflows.
## Technical Context
**Language/Version**: PHP 8.4, Laravel 12, Filament v5, Livewire v4, Blade
**Primary Dependencies**: Filament v5, Livewire v4, Pest v4, Laravel Sail, existing `ArtifactTruthPresenter`, `ArtifactTruthEnvelope`, `TenantReviewReadinessGate`, `EvidenceSnapshotService`, `TenantReviewRegisterService`, and current evidence/review/review-pack resources and pages
**Storage**: PostgreSQL with existing `evidence_snapshots`, `evidence_snapshot_items`, `tenant_reviews`, and `review_packs` tables using current summary JSON and timestamps; no schema change planned
**Testing**: Pest feature tests and Livewire page tests run via Sail, plus existing governance-artifact fixture helpers
**Target Platform**: Laravel web application in Sail locally and containerized Linux deployment in staging and production
**Project Type**: Laravel monolith web application
**Performance Goals**: Preserve DB-only render behavior on detail and canonical surfaces, avoid any render-time external calls, keep list-row truth derivation lightweight enough for canonical table scans, and keep operator trust signals readable within a 5-10 second scan on summary surfaces
**Constraints**: No new tables, no new enum families, no new presenter or resolver subsystem, no route changes, no RBAC drift, no destructive-action placement drift, no global asset changes, and no new global freshness engine if existing source-derived stale semantics are sufficient
**Scale/Scope**: Five operator-facing surfaces (`/admin/evidence/overview`, `/admin/reviews`, `/admin/t/{tenant}/evidence/{snapshot}`, `/admin/t/{tenant}/reviews/{review}`, `/admin/t/{tenant}/review-packs/{pack}`), one central truth presenter, existing readiness helpers, and focused regression coverage across fresh, stale, partial, blocked, internal-only, and publishable scenarios
## Constitution Check
*GATE: Passed before Phase 0 research. Re-checked after Phase 1 design and still passing.*
| Principle | Status | Notes |
|-----------|--------|-------|
| Inventory-first | Pass | Evidence freshness remains derived from the existing snapshot-item and source-evaluation chain; no new snapshot ownership semantics |
| Read/write separation | Pass | This slice primarily changes truth derivation and display; existing mutate actions remain unchanged |
| Graph contract path | Pass | No new Graph calls or contract-registry changes are introduced |
| Deterministic capabilities | Pass | No new capability derivation or role mapping is added |
| RBAC-UX planes and 404 vs 403 | Pass | Tenant-scoped resources remain tenant-scoped; canonical `/admin` pages stay workspace- and tenant-entitlement-safe |
| Workspace isolation | Pass | Canonical summary pages continue to derive rows only from entitled tenants in the current workspace |
| Tenant isolation | Pass | Drill-through links remain tenant-scoped and non-entitled users remain deny-as-not-found |
| Destructive confirmation | Pass | Existing destructive actions (`Expire snapshot`, `Archive review`, `Expire pack`) already require confirmation and remain unchanged |
| Global search safety | Pass | No global-search behavior is added or broadened; `EvidenceSnapshotResource`, `TenantReviewResource`, and `ReviewPackResource` already have view pages |
| Run observability | Pass | Existing evidence, review, and pack generation flows keep their current `OperationRun` types and ownership; no new run type is introduced |
| Ops-UX 3-surface feedback | Pass | No toast, progress, or terminal-notification behavior changes |
| Ops-UX lifecycle ownership | Pass | No `OperationRun.status` or `outcome` transition logic is touched |
| Ops-UX summary counts | Pass | No changes to `summary_counts` contracts are required |
| Ops-UX guards | Pass | Existing operation lifecycle guards stay in place; this feature adds truth-surface regression tests instead |
| Data minimization | Pass | No new payload exposure or raw-report surface is introduced |
| Proportionality (PROP-001) | Pass | The implementation stays inside existing freshness, readiness, and truth layers rather than adding persistence or abstraction |
| No premature abstraction (ABSTR-001) | Pass | No new resolver, gate, presenter family, registry, or taxonomy is planned |
| Persisted truth (PERSIST-001) | Pass | All new semantics remain derived from existing timestamps, summary state, and linked records |
| Behavioral state (STATE-001) | Pass | No new persisted states are introduced; existing stale/partial/publishable/internal-only semantics become stricter |
| UI semantics (UI-SEM-001) | Pass | Existing badge and truth primitives are reused; no second interpretation framework is introduced |
| V1 explicitness / few layers (V1-EXP-001, LAYER-001) | Pass | One central presenter and existing pages remain the implementation seam |
| Badge semantics (BADGE-001) | Pass | Existing freshness, completeness, publication-readiness, and artifact-truth badge domains stay canonical |
| Filament-native UI (UI-FIL-001) | Pass | Existing Filament resources, pages, badges, tables, and infolists are reused; no page-local status language is added |
| UI/UX surface taxonomy (UI-CONST-001 / UI-SURF-001) | Pass | Evidence snapshot, tenant review, and review pack remain `CRUD / List-first Resource` surfaces with dedicated detail pages, while evidence overview and review register remain `Read-only Registry / Report Surface` surfaces |
| UI/UX inspect model (UI-HARD-001) | Pass | Clickable-row inspect remains primary on the affected lists; no redundant view action is introduced |
| UI/UX action hierarchy (UI-HARD-001 / UI-EX-001) | Pass | Existing one-inline-safe-shortcut patterns remain; no new row-level destructive actions are added |
| UI/UX scope, truth, and naming (UI-HARD-001 / UI-NAMING-001 / OPSURF-001) | Pass | The feature strengthens default-visible trust truth while preserving canonical nouns and existing verbs |
| List-surface review checklist (UI-STD-001) | Pass | The affected list and report surfaces will be reviewed against `docs/product/standards/list-surface-review-checklist.md` during implementation and final verification |
| Filament Action Surface Contract | Pass | Current surface declarations already match the required list/detail behavior; the feature changes truth semantics, not action topology |
| Filament UX-001 | Pass | Existing Infolist and table layouts remain; this slice strengthens the truth surfaces inside them |
| Filament v5 / Livewire v4 compliance | Pass | The work remains inside the current Filament v5 + Livewire v4 stack |
| Provider registration location | Pass | No panel/provider changes; Laravel 11+ provider registration remains in `bootstrap/providers.php` |
| Asset strategy | Pass | No new panel or shared assets are required; deployment `filament:assets` behavior remains unchanged |
## Phase 0 Research
Research outcomes are captured in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/174-evidence-freshness-publication-trust/research.md`.
Key decisions:
- Reuse the existing source-derived stale semantics from evidence providers and `EvidenceCompletenessEvaluator` instead of creating a new global freshness engine.
- Tighten `ArtifactTruthPresenter` rather than introducing a new publication-trust resolver or freshness-trust gate.
- Degrade tenant review and review pack publication trust when freshness is stale and downgrade partial evidence to `internal_only` unless stronger existing blockers already make the artifact `blocked`.
- Make review packs inherit stale and partial burden from their linked review and evidence basis instead of treating pack freshness as `current` whenever the file itself is not expired.
- Keep canonical register and overview surfaces aligned by reusing the same truth envelope and next-step language rather than adding page-local taxonomies or ad-hoc columns.
- Expand existing Pest coverage and fixture builders rather than creating a new UI test harness.
## Phase 1 Design
Design artifacts are created under `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/174-evidence-freshness-publication-trust/`:
- `data-model.md`: derived trust-propagation model for evidence snapshots, tenant reviews, review packs, and canonical summary rows
- `contracts/evidence-review-trust-surfaces.openapi.yaml`: internal page-contract schema for the affected rendered HTML surfaces and their structured truth payloads
- `quickstart.md`: focused verification workflow for manual and automated validation
Design decisions:
- No schema migration is required; freshness remains derived from existing evidence-source timestamps and summary state.
- The primary implementation seam is `ArtifactTruthPresenter`, supported by the current evidence and review readiness services and existing page row builders.
- `TenantReviewReadinessGate` remains the publish-blocker authority for required stale or missing sections; this feature tightens how that burden is translated into operator-facing trust and publication surfaces.
- `EvidenceOverview` and `ReviewRegister` continue to render read-only summary rows, but must no longer sound calmer than the corresponding tenant-scoped detail surfaces.
- Existing destructive actions and capabilities remain unchanged; only truth presentation, next-step guidance, and consistency rules are hardened.
## Project Structure
### Documentation (this feature)
```text
specs/174-evidence-freshness-publication-trust/
├── spec.md
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│ └── evidence-review-trust-surfaces.openapi.yaml
├── checklists/
│ └── requirements.md
└── tasks.md
```
### Source Code (repository root)
```text
app/
├── Filament/
│ ├── Pages/
│ │ ├── Monitoring/
│ │ │ └── EvidenceOverview.php
│ │ └── Reviews/
│ │ └── ReviewRegister.php
│ └── Resources/
│ ├── EvidenceSnapshotResource.php
│ ├── ReviewPackResource.php
│ ├── TenantReviewResource.php
│ ├── EvidenceSnapshotResource/
│ │ └── Pages/
│ │ └── ViewEvidenceSnapshot.php
│ ├── ReviewPackResource/
│ │ └── Pages/
│ │ └── ViewReviewPack.php
│ └── TenantReviewResource/
│ └── Pages/
│ └── ViewTenantReview.php
├── Models/
│ ├── EvidenceSnapshot.php
│ ├── EvidenceSnapshotItem.php
│ ├── ReviewPack.php
│ └── TenantReview.php
├── Services/
│ ├── Evidence/
│ │ ├── EvidenceCompletenessEvaluator.php
│ │ ├── EvidenceSnapshotService.php
│ │ └── Sources/
│ │ ├── BaselineDriftPostureSource.php
│ │ ├── EntraAdminRolesSource.php
│ │ ├── FindingsSummarySource.php
│ │ ├── OperationsSummarySource.php
│ │ └── PermissionPostureSource.php
│ └── TenantReviews/
│ ├── TenantReviewReadinessGate.php
│ └── TenantReviewRegisterService.php
└── Support/
└── Ui/
└── GovernanceArtifactTruth/
├── ArtifactTruthEnvelope.php
└── ArtifactTruthPresenter.php
resources/
└── views/
└── filament/
├── infolists/
│ └── entries/
│ └── governance-artifact-truth.blade.php
└── pages/
├── monitoring/
│ └── evidence-overview.blade.php
└── reviews/
└── review-register.blade.php
routes/
└── web.php
tests/
├── Feature/
│ ├── Concerns/
│ │ └── BuildsGovernanceArtifactTruthFixtures.php
│ ├── Evidence/
│ │ ├── EvidenceOverviewPageTest.php
│ │ └── EvidenceSnapshotResourceTest.php
│ ├── Monitoring/
│ │ └── ArtifactTruthRunDetailTest.php
│ ├── ReviewPack/
│ │ └── ReviewPackResourceTest.php
│ └── TenantReview/
│ ├── TenantReviewLifecycleTest.php
│ └── TenantReviewRegisterTest.php
└── Pest.php
```
**Structure Decision**: Standard Laravel monolith. The change is concentrated in one existing truth-presenter seam, current readiness helpers, a small set of existing Filament resources/pages, and focused Pest coverage. No new base directories, services, or presentation frameworks are required.
## Implementation Strategy
### Phase A — Preserve Source-Derived Freshness As The Canonical Input
**Goal**: Keep existing provider-level stale semantics as the source of truth and document them clearly in the implementation so the feature does not accidentally invent a second freshness system.
| Step | File | Change |
|------|------|--------|
| A.1 | `app/Services/Evidence/EvidenceCompletenessEvaluator.php` | Confirm that source-level `stale` evaluation and snapshot completeness remain the canonical freshness input used by the UI truth layer |
| A.2 | `app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php` | Keep evidence-snapshot truth derived from snapshot status, completeness, and `summary.stale_dimensions` rather than introducing new page-local age logic |
| A.3 | `specs/174-evidence-freshness-publication-trust/research.md` and `data-model.md` | Record the source-derived freshness chain so implementation does not drift into a new threshold engine |
### Phase B — Downgrade Tenant Review Publication Trust When Freshness Or Completeness Weakens Confidence
**Goal**: Ensure tenant reviews can remain useful internally while no longer appearing publishable when their evidence basis is stale or partial.
| Step | File | Change |
|------|------|--------|
| B.1 | `app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php` | Tighten `buildTenantReviewEnvelope()` so stale freshness and partial evidence degrade publication readiness and next-step guidance appropriately |
| B.2 | `app/Services/TenantReviews/TenantReviewReadinessGate.php` | Reuse existing required-section stale and missing blocker semantics; do not create a second publish-blocker system |
| B.3 | `app/Filament/Resources/TenantReviewResource.php` and `app/Filament/Resources/TenantReviewResource/Pages/ViewTenantReview.php` | Verify the tightened truth envelope is visible on list and detail surfaces without changing action topology or copy vocabulary |
### Phase C — Propagate Source Review And Evidence Burden Into Review Pack Trust
**Goal**: Prevent review packs from appearing calmer than the review or evidence basis they were generated from.
| Step | File | Change |
|------|------|--------|
| C.1 | `app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php` | Tighten `buildReviewPackEnvelope()` so pack freshness and publication readiness inherit stale or partial burden from the source review and evidence resolution |
| C.2 | `app/Filament/Resources/ReviewPackResource.php` and `app/Filament/Resources/ReviewPackResource/Pages/ViewReviewPack.php` | Ensure pack list/detail surfaces expose internal-only or cautionary trust and next-step caveats before download or sharing |
| C.3 | `resources/views/filament/infolists/entries/governance-artifact-truth.blade.php` | Reuse the existing truth partial to surface freshness and publication dimensions with stronger consistency rather than new local markup |
### Phase D — Align Canonical Overview And Register Rows With Tenant-Scoped Detail Truth
**Goal**: Ensure `/admin/evidence/overview` and `/admin/reviews` summarize the same truth direction as the tenant-scoped detail pages.
| Step | File | Change |
|------|------|--------|
| D.1 | `app/Filament/Pages/Monitoring/EvidenceOverview.php` | Keep row truth and next-step guidance sourced from the same envelope semantics used by snapshot detail |
| D.2 | `app/Filament/Pages/Reviews/ReviewRegister.php` | Keep artifact truth, publication readiness, and next-step rows aligned with tenant review detail without adding new ad-hoc row taxonomy |
| D.3 | `routes/web.php` and current navigation helpers | Preserve existing canonical route shape and tenant-prefilter continuity; no routing change |
### Phase E — Regression Protection And Focused Validation
**Goal**: Add the smallest useful test set that protects stale propagation, partial-evidence trust, review/pack consistency, and canonical summary alignment.
| Step | File | Change |
|------|------|--------|
| E.1 | `tests/Feature/Concerns/BuildsGovernanceArtifactTruthFixtures.php` | Add fixture helpers for stale and partial evidence scenarios so tests do not duplicate setup logic |
| E.2 | `tests/Feature/Evidence/EvidenceSnapshotResourceTest.php` | Add fresh-vs-stale snapshot truth assertions, including stale-dimension next-step behavior |
| E.3 | `tests/Feature/TenantReview/TenantReviewLifecycleTest.php` | Add stale and partial review publication-trust assertions without changing lifecycle behavior |
| E.4 | `tests/Feature/ReviewPack/ReviewPackResourceTest.php` | Add pack trust propagation assertions for stale or partial source review/evidence combinations |
| E.5 | `tests/Feature/TenantReview/TenantReviewRegisterTest.php` and `tests/Feature/Evidence/EvidenceOverviewPageTest.php` | Add canonical row-alignment assertions so summary pages do not sound calmer than detail |
| E.6 | `vendor/bin/sail bin pint --dirty --format agent` and focused Pest runs | Required formatting and targeted verification before task completion |
## Key Design Decisions
### D-001 — Source-specific stale evaluation stays canonical
Evidence sources already produce `stale` item states using their own domain-appropriate recency logic, and `EvidenceCompletenessEvaluator` already rolls those into snapshot completeness. The plan reuses that chain instead of inventing a separate global age-policy system.
### D-002 — `ArtifactTruthPresenter` remains the single trust-propagation seam
The current code already centralizes evidence snapshot, tenant review, and review pack trust in one presenter. Tightening that presenter is narrower and safer than introducing a new publication-trust resolver or freshness framework.
### D-003 — Publication readiness remains distinct from freshness and completeness
The feature must not collapse all trust dimensions into one vague `ready` state. Freshness, completeness, and publication readiness remain separate dimensions, but stale evidence downgrades share safety and partial evidence downgrades publication readiness to `internal_only` unless existing blockers already make the artifact `blocked`.
### D-004 — Canonical summary pages must reuse existing truth, not invent row-local semantics
`EvidenceOverview` and `ReviewRegister` already surface artifact truth, publication, and next-step information. The right fix is to align their inputs with the tightened truth envelope, not to add page-specific badges or prose.
### D-005 — No new persistence or reporting subsystem is justified
This is a current-release operator-trust problem, but it is still a derived-truth problem. Existing timestamps, summary state, and linked artifacts are enough to solve it without a StoredReport viewer, new export-governance model, or separate publication-trust entity.
## Risk Assessment
| Risk | Impact | Likelihood | Mitigation |
|------|--------|------------|------------|
| Review publication trust becomes too strict and downgrades healthy reviews | Medium | Medium | Base downgrades on existing stale/partial semantics already produced by evidence and review services rather than a new heuristic |
| Review pack truth diverges from review truth because pack code and review code evolve separately | High | Medium | Centralize propagation in `ArtifactTruthPresenter` and add explicit review-vs-pack consistency tests |
| Canonical summary pages become denser or harder to scan | Medium | Low | Reuse existing columns and next-step fields instead of adding more row furniture |
| `fresh` versus non-`fresh` envelope variants diverge across surfaces | Medium | Low | Keep one truth-building path and only use `fresh` variants when cache bypass is genuinely needed |
| Implementation accidentally introduces a new freshness policy or new abstraction | Medium | Low | Lock the design to current source-derived stale semantics and reject new persistence or resolver additions in review |
## Test Strategy
- Extend the current evidence, tenant review, review pack, and canonical summary Pest tests instead of adding a new testing layer.
- Use `BuildsGovernanceArtifactTruthFixtures` and existing `composeTenantReviewForTest()` helpers to build fresh, stale, and partial scenarios consistently.
- Add explicit assertions for fresh versus stale evidence snapshots, partial versus complete review evidence, review-pack versus review trust alignment, and canonical row truth alignment.
- Preserve existing authorization semantics: non-entitled users remain `404`, in-scope users without manage capability remain `403` for actions, and summary truth remains visible only within entitled scope.
- Keep destructive actions and operation-launch semantics unchanged; test additions should focus on trust consequences, not on unrelated lifecycle behavior.
- Focused verification targets: `EvidenceSnapshotResourceTest`, `TenantReviewLifecycleTest`, `ReviewPackResourceTest`, `TenantReviewRegisterTest`, `EvidenceOverviewPageTest`, and fixture helpers.
## Complexity Tracking
No constitution violations or justified complexity exceptions were identified.
## Proportionality Review
Not triggered beyond the already-passed spec review. The plan introduces no new enum/status family, DTO/presenter family, persisted entity, registry, resolver, taxonomy, or cross-domain UI framework.