TenantAtlas/specs/174-evidence-freshness-publication-trust/research.md
ahmido 44898a98ac feat: harden evidence freshness publication trust (#205)
## Summary
- harden governance artifact truth propagation so stale or partial evidence downgrades evidence snapshots, tenant reviews, review packs, the canonical evidence overview, and the canonical review register consistently
- add the full Spec 174 artifact set under `specs/174-evidence-freshness-publication-trust/` including spec, plan, research, data model, contracts, quickstart, checklist, and completed tasks
- add focused fixture helpers plus a new browser smoke test for the touched evidence, review, and review-pack trust surfaces

## Testing
- `vendor/bin/sail artisan test --compact tests/Feature/Evidence/EvidenceSnapshotResourceTest.php tests/Feature/Evidence/EvidenceOverviewPageTest.php tests/Feature/TenantReview/TenantReviewLifecycleTest.php tests/Feature/TenantReview/TenantReviewRegisterTest.php tests/Feature/ReviewPack/ReviewPackResourceTest.php tests/Feature/Monitoring/ArtifactTruthRunDetailTest.php tests/Browser/Spec174EvidenceFreshnessPublicationTrustSmokeTest.php`
- manual integrated-browser smoke pass across Evidence Overview, Review Register, tenant review detail, tenant evidence snapshot detail, and review-packs list

## Notes
- Livewire v4 compliance is preserved and no Filament v3/v4 APIs were introduced
- no panel or provider changes were made; Laravel 11+ provider registration remains in `bootstrap/providers.php`
- no new global-search behavior was introduced; existing resource view pages remain the relevant detail endpoints
- destructive actions were not broadened; existing confirmation and authorization behavior remains in place
- no new assets were added, so the current Filament asset strategy and deploy-time `php artisan filament:assets` behavior stay unchanged
- branch `174-evidence-freshness-publication-trust` is pushed at `7f2c82c26dc83bbc09fbf9e732d5644cdd143113` and targets `dev`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #205
2026-04-04 11:31:27 +00:00

60 lines
7.3 KiB
Markdown

# Research: Evidence Temporal Freshness & Review Publication Trust
## Decision 1: Reuse the existing source-derived stale semantics instead of introducing a global freshness engine
- Decision: Treat provider-level `stale` evaluation and the existing `EvidenceCompletenessEvaluator` as the canonical source of temporal freshness for this feature.
- Rationale: Evidence freshness is already derived upstream in the evidence domain. `EvidenceSnapshotService` collects per-dimension payloads, providers such as `BaselineDriftPostureSource` already mark data stale using domain-appropriate recency rules, and `EvidenceCompletenessEvaluator` already escalates any required stale dimension into snapshot completeness. A second global threshold engine would duplicate truth and risk disagreement with the evidence domain.
- Alternatives considered:
- Add a new global `freshness_threshold_hours` configuration and recompute staleness on the page layer. Rejected because the existing evidence sources already encode domain-aware freshness and the page layer should not create its own recency semantics.
- Derive staleness purely from `generated_at` on snapshots and reviews. Rejected because the meaningful freshness signal already exists at the dimension level, and a snapshot can be freshly generated from stale inputs.
## Decision 2: Tighten `ArtifactTruthPresenter` instead of adding a new trust or publication resolver
- Decision: Keep `ArtifactTruthPresenter` as the single seam for evidence snapshot, tenant review, and review pack trust propagation.
- Rationale: The presenter already builds envelopes for `EvidenceSnapshot`, `TenantReview`, and `ReviewPack`, including freshness, content, publication, actionability, and next-step guidance. The current bug is not the absence of a trust layer, but that stale and partial semantics are not fully propagated through the existing one.
- Alternatives considered:
- Create a dedicated `PublicationReadinessResolver` or `FreshnessTrustGate`. Rejected because the current architecture already centralizes the needed truth and a second layer would violate the repo's proportionality and few-layers rules.
- Push the logic into page classes. Rejected because it would fragment truth across summary pages and detail resources.
## Decision 3: Tenant review publication readiness must degrade when freshness is stale
- Decision: Make stale review freshness capable of downgrading a review from publishable to an internal-only or cautionary posture even when the review status is `ready` or `published`.
- Rationale: `TenantReviewReadinessGate` already treats stale required sections as publication blockers at composition time, and `buildTenantReviewEnvelope()` already calculates a `freshnessState` of `stale`. The current contradiction is that publication readiness still becomes `publishable` from status alone, which lets stale reviews sound calmer than the evidence basis justifies.
- Rule: A stale review may remain internally useful, but it must not remain `publishable` solely because its lifecycle status is `ready` or `published`. If stronger blockers already exist, `blocked` still takes precedence.
- Alternatives considered:
- Leave publication readiness based only on status and blocker arrays. Rejected because it allows a stale review to look publishable even when the same presenter calls it stale.
- Introduce a new persisted review trust field. Rejected because the stale condition is already derivable from review completeness and section counts.
## Decision 4: Partial evidence must lower publication confidence even when it does not fully block review use
- Decision: Distinguish between reviews that are usable internally and reviews that are truly publishable when the evidence basis is partial.
- Rationale: The spec requires a meaningful difference between internal-use artifacts and publishable artifacts. The current truth model already supports separate `contentState`, `freshnessState`, `publicationReadiness`, and `actionability` dimensions, so the implementation can express this nuance without new state families.
- Rule: Partial evidence downgrades publication readiness to `internal_only` unless stronger existing blockers already make the artifact `blocked`.
- Alternatives considered:
- Treat partial evidence exactly like complete evidence whenever hard blockers are absent. Rejected because that is the current trust problem.
- Convert all partial evidence into hard publish blockers. Rejected because the spec wants internal-use versus publishable to remain distinct, not collapsed into blocked versus not blocked.
## Decision 5: Review packs must inherit stale and partial burden from the linked review and evidence basis
- Decision: Make `ReviewPack` truth inherit source review and evidence burden rather than treating a ready, non-expired file as inherently current and publishable.
- Rationale: `buildReviewPackEnvelope()` currently treats pack freshness as `current` whenever the file is not expired, even if the source review or source evidence is stale. That allows packs to appear calmer than the review they were generated from, which is exactly the contradiction this spec is meant to close.
- Rule: A pack is only `publishable` when its source review remains current and strong enough to publish. Stale or partial source burden must downgrade the pack to `internal_only`, unless stronger blockers already make it `blocked`.
- Alternatives considered:
- Keep pack freshness tied only to file expiration. Rejected because a current file can still be generated from stale governance evidence.
- Persist a separate pack trust state. Rejected because the necessary source review and evidence inputs already exist.
## Decision 6: Canonical summary pages should reuse the same truth envelope and next-step semantics
- Decision: Keep `EvidenceOverview` and `ReviewRegister` aligned by reusing the same envelope semantics that power the tenant-scoped detail pages.
- Rationale: Both canonical pages already display artifact truth and next-step or publication surfaces. The current risk is not missing UI slots, but summary rows sounding calmer than the detail pages because stale and partial burden are not fully represented in the underlying truth.
- Alternatives considered:
- Add new page-specific columns, banners, or taxonomy labels. Rejected because the repo already has canonical truth and badge primitives.
- Leave canonical summary rows untouched and rely on drill-through. Rejected because the spec explicitly targets trust propagation on summary surfaces.
## Decision 7: Expand the current Pest test surfaces and fixture helpers instead of creating a new test harness
- Decision: Extend the current evidence, review, pack, review-register, and evidence-overview tests, and strengthen shared governance-artifact fixtures.
- Rationale: The current suite already covers resource routing, basic artifact truth visibility, review publication blockers, and canonical row scoping. The missing coverage is specific: fresh versus stale propagation, partial-evidence publication trust, and review-versus-pack consistency.
- Alternatives considered:
- Rely on manual browser validation only. Rejected because this feature is about preventing semantic drift across multiple related surfaces.
- Add a separate browser suite as the primary guard. Rejected because the existing Pest feature surfaces are already well aligned with the affected code paths and will be faster and cheaper to maintain.