TenantAtlas/specs/361-report-evidence-reconciliation/spec.md
ahmido 252cd4513d feat: implement report evidence reconciliation (#432)
Implemented report evidence reconciliation.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #432
2026-06-06 22:40:59 +00:00

39 KiB

Feature Specification: Spec 361 - Report and Evidence Reconciliation Adapters

Feature Branch: 361-report-evidence-reconciliation
Created: 2026-06-06
Status: Draft
Input: User-provided Spec 361 draft from /Users/ahmeddarrazi/.codex/attachments/a0817e2c-be58-40c1-9108-1e1880e423d4/pasted-text.txt, reconciled against current repo truth

Spec Candidate Check (mandatory - SPEC-GATE-001)

  • Problem: current OperationRun monitoring can still leave report-family or evidence-family generation runs queued, running, or stale even after the repo already has a scope-safe artifact that proves the intended output exists.
  • Today's failure: operators can be forced to compare Operations, Review Pack, Evidence Snapshot, and report surfaces manually to decide whether a run is genuinely unfinished or whether the artifact already exists and the run is now ghost state.
  • User-visible improvement: existing operations surfaces, related-artifact links, and current artifact truth surfaces will show one honest execution story: reconcile only when a safe artifact already proves success, otherwise stay pending or attention-required without false calm.
  • Smallest enterprise-capable version: extend the current OperationRun reconciliation registry for repo-verifiable artifact families only: tenant.evidence.snapshot.generate and environment.review_pack.generate. Keep generic StoredReport reconciliation fail-closed unless current repo truth already proves direct causal linkage without new persistence.
  • Explicit non-goals: no new table, no new OperationRun status column, no new queue family, no new report renderer, no new PDF/HTML work, no new stored_report.generate operation type, no sync/backup/restore adapter expansion, no customer portal work, no destructive action changes, and no legacy compatibility layer.
  • Permanent complexity imported: two bounded reconciliation adapters, at most one small derived proof/helper path, focused Unit/Feature/Browser tests, and small operator-facing copy or link adjustments on existing monitoring and artifact surfaces.
  • Why now: Spec 359 merged the review-compose adapter baseline, and current platform-dev already contains the shared registry, context.reconciliation, and context.dispatch seams. The next repo-real trust gap is artifact-backed reconciliation for evidence and review-pack outputs.
  • Why not local: fixing one banner, one presenter, or one detail page would not repair the shared run lifecycle truth across Operations, run detail, Review Pack, and Evidence Snapshot surfaces.
  • Approval class: Core Enterprise
  • Red flags triggered: new abstraction/helper pressure and shared operator-facing status semantics. Defense: the repo already has real adapter-backed reconciliation consumers (restore.execute, environment.review.compose), and queue correctness plus audit-visible truth justify a bounded extension instead of more special cases.
  • Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 1 | Wiederverwendung: 2 | Gesamt: 10/12
  • Decision: approve

Repo Truth Reconciliation

The user draft is directionally correct, but current repo truth narrows the safe implementation slice:

  1. docs/product/spec-candidates.md still records no safe automatic next-best-prep target. This package is therefore an explicit manual promotion from the user-provided draft, not an auto-selected queue item.
  2. platform-dev already contains the merged Spec 359 runtime baseline at 3a750726 feat: implement review compose reconciliation adapter (spec 359) (#430), plus the shared OperationRunReconciliationRegistry, OperationRunCorrelationResolver, and context.dispatch write path in OperationRunService.
  3. EvidenceSnapshot and ReviewPack are safe primary artifact families for this slice because they already carry workspace/environment scope, lifecycle status, fingerprint data, and direct operation_run_id linkage.
  4. Generic StoredReport truth is weaker than the draft assumes: the model has no direct operation_run_id, no status enum, and no canonical readiness lifecycle. Spec 361 therefore treats generic report reconciliation for permission.posture.check and entra.admin_roles.scan as explicitly unsupported. This package must not add any StoredReport-backed success path; any future direct report-artifact proof contract belongs in a separate follow-up spec.
  5. Existing review-pack productization and report-output semantics from Specs 347, 349, 351, 356, and 357 are context only. This spec must reuse those seams and must not reopen rendered-report or disclosure-policy scope.
  6. Related existing specs are context only and must not be rewritten:
    • Spec 358 - generic queue-truth baseline
    • Spec 359 - merged review-compose adapter baseline
    • Spec 360 - canonical cutover follow-through context
    • Specs 347/349/351/356/357 - review-pack and rendered-report productization context

Spec Scope Fields (mandatory)

  • Scope: workspace, tenant, canonical-view
  • Primary Routes:
    • /admin/workspaces/{workspace}/operations
    • /admin/workspaces/{workspace}/operations/{run}
    • existing environment-scoped Evidence Snapshot routes via App\Filament\Resources\EvidenceSnapshotResource
    • existing environment-scoped Review Pack routes via App\Filament\Resources\ReviewPackResource
  • Data Ownership:
    • operation_runs remain the only execution and reconciliation truth
    • evidence_snapshots remain the only persisted evidence-generation truth
    • review_packs remain the only persisted review-pack output truth
    • stored_reports remain supporting artifact context only unless current repo truth proves safe direct reconciliation without new persistence
  • RBAC:
    • existing workspace-first OperationRun access rules remain authoritative
    • existing environment-scoped EvidenceSnapshot and ReviewPack policies remain authoritative
    • non-members and out-of-scope actors remain 404
    • no new capability strings are introduced

For canonical-view specs, the spec MUST define:

  • Default filter behavior when tenant-context is active: the Operations hub remains workspace-scoped with explicit environment filters; adapter decisions must rely on the run's recorded workspace/environment scope and never on remembered environment state or current page filters.
  • Explicit entitlement checks preventing cross-tenant leakage: no adapter may reconcile to an artifact outside the run's workspace and managed environment, and any related-artifact link must resolve only through current-scope canonical routes.

UI Surface Impact (mandatory - UI-COV-001)

Does this spec add, remove, rename, or materially change any reachable UI surface?

  • No UI surface impact
  • Existing page changed
  • New page/route added
  • Navigation changed
  • Filament panel/provider surface changed
  • New modal/drawer/wizard/action added
  • New table/form/state added
  • Customer-facing surface changed
  • Dangerous action changed
  • Status/evidence/review presentation changed
  • Workspace/environment context presentation changed

UI/Productization Coverage (mandatory when UI Surface Impact is not "No UI surface impact")

  • Route/page/surface:
    • workspace operations hub (App\Filament\Pages\Monitoring\Operations)
    • canonical run detail (App\Filament\Pages\Operations\TenantlessOperationRunViewer)
    • existing Evidence Snapshot related-context and detail surfaces
    • existing Review Pack related-context and detail surfaces
  • Current or new page archetype: existing monitoring/detail family plus existing governance-artifact detail family
  • Design depth: Domain Pattern Surface
  • Repo-truth level: repo-verified
  • Existing pattern reused: current OperationRun monitoring family, current artifact-truth/detail family, current related-artifact link conventions
  • New pattern required: none; this is a run-truth follow-through inside existing pattern families
  • Screenshot required: no; one bounded browser smoke is sufficient unless implementation produces a materially new visible hierarchy
  • Page audit required: no new page-report identity is required; existing monitoring and artifact page reports remain the anchors
  • Customer-safe review required: no; touched copy remains operator-facing and diagnostic
  • Dangerous-action review required: no; this spec adds no new mutation surface and no destructive action
  • Coverage files updated or explicitly not needed:
    • docs/ui-ux-enterprise-audit/route-inventory.md
    • docs/ui-ux-enterprise-audit/design-coverage-matrix.md
    • docs/ui-ux-enterprise-audit/page-reports/...
    • docs/ui-ux-enterprise-audit/strategic-surfaces.md
    • docs/ui-ux-enterprise-audit/grouped-follow-up-candidates.md
    • docs/ui-ux-enterprise-audit/unresolved-pages.md
    • N/A - existing monitoring and artifact page families already cover these reachable surfaces
  • No-impact rationale when applicable: no new page family, route family, or navigation entry is added; the slice stays inside existing operations, review-pack, and evidence artifact surfaces

Cross-Cutting / Shared Pattern Reuse (mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write N/A - no shared interaction family touched)

  • Cross-cutting feature?: yes
  • Interaction class(es): status messaging, action links, evidence/report viewers, related-artifact diagnostics
  • Systems touched:
    • App\Services\AdapterRunReconciler
    • App\Services\OperationRunService
    • App\Support\Operations\Reconciliation\OperationRunReconciliationRegistry
    • App\Support\OperationRunLinks
    • App\Support\Ui\GovernanceArtifactTruth\ArtifactTruthPresenter
    • App\Support\OpsUx\GovernanceRunDiagnosticSummaryBuilder
    • existing Review Pack and Evidence Snapshot resource/detail surfaces
  • Existing pattern(s) to extend: existing reconciliation metadata path, existing operations monitoring/detail language, current artifact-truth/detail family, and current canonical artifact links
  • Shared contract / presenter / builder / renderer to reuse: OperationRunService::updateRunWithReconciliation(), OperationRun::reconciliation(), OperationRunLinks, ArtifactTruthPresenter, GovernanceRunDiagnosticSummaryBuilder, and current Evidence Snapshot / Review Pack resources
  • Why the existing shared path is sufficient or insufficient: the repo already has the right write seam and related-artifact presentation family, but the registry does not yet cover repo-verifiable artifact-backed success for evidence or review-pack outputs.
  • Allowed deviation and why: one bounded helper or proof object is allowed only if it removes duplicated scope/completeness checks across the two in-scope adapters. It must stay derived-only and local to current reconciliation work.
  • Consistency impact: reconciled evidence or review-pack outcomes must read consistently across start feedback, operations list/detail, and related-artifact views, while unsupported generic stored-report families must stay attention-first instead of silently appearing successful.
  • Review focus: no second reconciliation write path, no new stored-report lifecycle model, no artifact mutation from adapters, and no false success from "latest artifact exists" heuristics alone.
  • Touches OperationRun start/completion/link UX?: yes, reuse-only
  • Shared OperationRun UX contract/layer reused: current OperationRunService, OperationRunLinks, registry-backed reconciliation, and existing operations monitoring/detail presenters
  • Delegated start/completion UX behaviors: existing queued toasts, canonical run links, canonical artifact links, current run-enqueued browser events, and current terminal notification path remain unchanged
  • Local surface-owned behavior that remains: placement and explanation text only
  • Queued DB-notification policy: unchanged
  • Terminal notification path: unchanged central lifecycle mechanism
  • Exception required?: none

Provider Boundary / Platform Core Check (mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write N/A - no shared provider/platform boundary touched)

  • Shared provider/platform boundary touched?: no
  • Boundary classification: N/A
  • Seams affected: N/A
  • Neutral platform terms preserved or introduced: operation, artifact, review pack, evidence snapshot, reconciliation
  • Provider-specific semantics retained and why: none
  • Why this does not deepen provider coupling accidentally: the slice uses platform-owned artifact and operation truth only
  • Follow-up path: none

UI / Surface Guardrail Impact (mandatory when operator-facing surfaces are changed; otherwise write N/A)

Surface / Change Operator-facing surface change? Native vs Custom Shared-Family Relevance State Layers Touched Exception Needed? Low-Impact / N/A Note
Operations hub reconciliation copy and related-artifact state yes Native Filament + shared presenters OperationRun monitoring family page, detail, URL-query no no new action hierarchy
Run detail reconciliation diagnostics and related links yes Native Filament + shared presenters OperationRun monitoring family detail no existing link model stays canonical
Evidence Snapshot / Review Pack related-artifact surfaces yes Native Filament + shared artifact-truth helpers artifact detail family detail no no new route family or mutation

Decision-First Surface Role (mandatory when operator-facing surfaces are changed)

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
Operations hub Primary Decision Surface Decide whether a run still needs follow-up lifecycle, outcome, safe related-artifact state, next action raw failures, reconciliation evidence, artifact details primary because operators decide whether to wait, inspect, or move on here stays aligned to monitoring workflow removes manual cross-checking between run and artifact lists
Run detail Secondary Context Surface Verify why a run was reconciled or left pending reconciled reason, related artifact, scope-safe link full context payload, existing diagnostic sections secondary because it confirms a decision already hinted in the hub stays aligned to detail workflow keeps proof in one canonical place
Evidence Snapshot / Review Pack detail Tertiary Evidence / Diagnostics Inspect the artifact that justified or blocked reconciliation current artifact state payloads, summary metadata, existing artifact diagnostics tertiary because artifact pages prove evidence after the run decision stays aligned to current artifact detail workflow avoids duplicating full artifact truth on the run list

Audience-Aware Disclosure (mandatory when operator-facing surfaces are changed)

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
Operations hub operator-MSP, support-platform run status, honest reconciliation state, safe related artifact, next action failures, related metadata, timestamps after explicit reveal by an actor already entitled to view the run raw context.reconciliation evidence remains secondary and stays limited to the existing support/platform diagnostics path on the run host Open operation or related artifact link raw context stays diagnostic-only and is never default-visible the hub states the outcome once; later sections add proof only
Run detail operator-MSP, support-platform reconciled or not reconciled state with safe reason full reconciliation metadata and existing failure detail after explicit reveal by an actor already entitled to view the run raw payload inspection stays secondary and remains available only through the existing support/platform diagnostics path on the run host Open related artifact when safe low-level payloads remain subordinate and capability-gated where the host already distinguishes support/platform access no second "success" summary beyond the canonical outcome
Evidence Snapshot / Review Pack detail operator-MSP, support-platform current artifact state, scope-safe relation to the run, and concise artifact outcome summary existing artifact diagnostics and related run context after explicit reveal by an actor already entitled to view the artifact raw/support artifact evidence remains behind the existing host-specific diagnostics or payload affordance and never becomes the default first-read layer Open related operation when safe payloads, fingerprints, and raw evidence stay secondary and host-gated artifact pages prove or explain one outcome only; they do not restate a competing default-visible success summary

Layer unlocks for changed surfaces:

  • Decision content: any actor who already passes the current workspace/environment and run/artifact view entitlement for the host surface.
  • Operator diagnostics: the same entitled actor, but only after an explicit reveal affordance on the host surface.
  • Support / raw evidence: only the existing support/platform diagnostics path on the current host surface; this spec introduces no new capability string and no widened raw-evidence audience.

UI/UX Surface Classification (mandatory when operator-facing surfaces are changed)

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
Operations hub Monitoring / Queue / Workbench Read-only Registry / Report Surface Open the run or its proven artifact row click to run detail required existing filters and contextual links only unchanged /admin/workspaces/{workspace}/operations /admin/workspaces/{workspace}/operations/{run} workspace route plus explicit environment filter Operations / Operation honest lifecycle plus safe artifact state none
Run detail Record / Detail / Edit Detail-first Operational Surface Inspect related artifact proof canonical detail page N/A existing navigation and related links only unchanged /admin/workspaces/{workspace}/operations /admin/workspaces/{workspace}/operations/{run} run-owned workspace/environment scope Operation reconciliation outcome and reason none
Evidence Snapshot / Review Pack detail Record / Detail / Edit Detail-first Operational Surface Inspect the artifact proof and, if needed, follow the safe link back to the operation canonical detail page N/A existing related links and host-owned secondary actions only unchanged existing Evidence Snapshot / Review Pack collection routes existing Evidence Snapshot / Review Pack detail routes artifact-owned workspace/environment scope plus current host context Evidence Snapshot / Review Pack current artifact truth and safe relation to the reconciled run none

Operator Surface Contract (mandatory when operator-facing surfaces are changed)

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
Operations hub MSP operator Decide whether the run still needs attention list/workbench Is the artifact already proven, or is this run still unfinished? lifecycle state, reconciled outcome, safe artifact state, next step raw failures, detailed metadata, timestamps lifecycle, artifact completeness, scope safety none existing inspect/open actions only none
Run detail MSP operator or support Confirm why the run reconciled or stayed pending detail What exact artifact truth did the run resolve against? reconciled reason, related artifact, summary counts raw context.reconciliation, raw context payload, deep diagnostic sections lifecycle, artifact completeness, support state none open related artifact when safe none
Evidence Snapshot / Review Pack detail MSP operator or support Confirm whether the artifact really justifies or blocks reconciliation detail Does this artifact safely prove the run outcome for the current scope? artifact readiness, scope-safe linkage, concise supporting summary payloads, fingerprints, deeper host diagnostics, and related run context artifact readiness, completeness/expiration, scope safety none open related operation when safe none

Proportionality Review (mandatory when structural complexity is introduced)

  • New source of truth?: no
  • New persisted entity/table/artifact?: no
  • New abstraction?: yes, bounded adapter classes and at most one small derived proof/helper path
  • New enum/state/reason family?: no new family; only current reconciliation reason semantics may be reused or narrowly extended if behaviorally required
  • New cross-domain UI framework/taxonomy?: no
  • Current operator problem: artifact-producing runs can remain queued/running/stale even after the repo already has a safe artifact, forcing manual cross-checks and risking false calm or false alarm.
  • Existing structure is insufficient because: the current registry only covers restore and review-compose truth, while evidence and review-pack runs still lack artifact-backed reconciliation even though their artifact models already expose scope, lifecycle, and fingerprint proof.
  • Narrowest correct implementation: add only evidence snapshot and review-pack adapters over existing models and write seams; keep generic stored-report reconciliation deferred until direct causal proof exists.
  • Ownership cost: adapter maintenance, focused tests, and some monitoring/detail copy review. No migration, new artifact table, or new operator workflow family is introduced.
  • Alternative intentionally rejected: a generic "latest artifact exists => mark success" heuristic was rejected because it would overclaim success for unsupported or ambiguous report families, especially StoredReport.
  • Release truth: current-release truth

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 is preferred over preservation.

Testing / Lane / Runtime Impact (mandatory for runtime behavior changes)

  • Test purpose / classification: Unit, Feature, Browser
  • Validation lane(s): fast-feedback, confidence, browser
  • Why this classification and these lanes are sufficient: adapter selection, proof evaluation, and metadata formatting are cheapest in Unit coverage; run finalization, scope safety, and artifact-link behavior require Feature coverage; one bounded Browser smoke is enough for existing Operations and artifact surfaces if visible operator wording changes.
  • New or expanded test families: one explicit Spec 361 Unit/Feature family and one bounded Browser smoke
  • Fixture / helper cost impact: moderate existing factory usage for OperationRun, EvidenceSnapshot, ReviewPack, EnvironmentReview, and workspace/environment membership; no new expensive global defaults should be introduced
  • Heavy-family visibility / justification: no heavy-governance family is added
  • Special surface test profile: monitoring-state-page
  • Standard-native relief or required special coverage: ordinary Feature coverage for existing Filament surfaces plus one bounded Browser smoke when UI wording changes
  • Reviewer handoff: reviewers must confirm generic StoredReport families stay fail-closed unless safe proof is demonstrated, that adapters do not mutate artifacts, and that proof commands stay scoped to Spec 361 plus contextual artifact regressions only
  • Budget / baseline / trend impact: none expected beyond one bounded browser smoke
  • Escalation needed: document-in-feature if generic stored-report proof remains insufficient; follow-up-spec only if the repo later needs a dedicated stored-report causality contract
  • Active feature PR close-out entry: Guardrail / Smoke Coverage
  • Planned validation commands:
    • cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Unit/Support/Operations/Reconciliation tests/Feature/Operations/Spec361*
    • cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Feature/Evidence/GenerateEvidenceSnapshotJobTest.php tests/Feature/Evidence/EvidenceSnapshotResourceTest.php
    • cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Feature/ReviewPack/EnvironmentReviewDerivedReviewPackTest.php tests/Feature/ReviewPack/ReviewPackDownloadTest.php tests/Feature/ReviewPack/Spec347ReviewPackOutputContractTest.php
    • cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec361ArtifactReconciliationSmokeTest.php
    • cd apps/platform && ./vendor/bin/pint --dirty
    • git diff --check

User Scenarios & Testing (mandatory)

User Story 1 - Reconcile evidence generation against an existing snapshot (Priority: P1)

An operator sees a queued, running, or stale evidence-generation run and needs the run to finalize honestly when the matching EvidenceSnapshot already exists and is scope-safe, complete, and active.

Why this priority: EvidenceSnapshot already has direct operation_run_id, lifecycle status, completeness state, and fingerprint signals, so this is the safest and highest-confidence artifact-backed reconciliation extension.

Independent Test: seed a queued or stale tenant.evidence.snapshot.generate run plus a matching active, complete snapshot in the same workspace/environment, run reconciliation, and verify the run finalizes successfully with canonical related-artifact metadata.

Acceptance Scenarios:

  1. Given a queued or stale evidence-generation run and a matching active, complete snapshot with the same scope and fingerprint, When adapter reconciliation runs, Then the run becomes completed/succeeded and links to the snapshot safely.
  2. Given a queued or stale evidence-generation run and a partial, failed, expired, or wrong-scope snapshot, When adapter reconciliation runs, Then the run does not claim success and remains pending or attention-required.

User Story 2 - Reconcile review-pack generation against an existing pack (Priority: P1)

An operator sees a queued, running, or stale review-pack generation run and needs the run to finalize honestly when the matching ReviewPack already exists, is ready, non-expired, and belongs to the same workspace/environment/review scope.

Why this priority: review-pack output is already customer-facing and productized; ghost run state here directly damages trust in delivered governance artifacts.

Independent Test: seed a queued or stale environment.review_pack.generate run plus a matching ready pack with canonical scope and fingerprint signals, run reconciliation, and verify the run finalizes successfully with canonical related-artifact metadata.

Acceptance Scenarios:

  1. Given a queued or stale review-pack run and a matching ready, non-expired pack for the same scope, When adapter reconciliation runs, Then the run becomes completed/succeeded and exposes the safe pack link through current operations surfaces.
  2. Given a queued or stale review-pack run and a generating, failed, expired, incomplete, or wrong-scope pack, When adapter reconciliation runs, Then the run does not claim success and the operator sees honest follow-up state instead.

User Story 3 - Keep unsupported generic report families honest (Priority: P2)

An operator sees a queued or stale run for a report-producing operation such as permission.posture.check or entra.admin_roles.scan and must not see false success merely because a latest StoredReport exists without direct causal proof.

Why this priority: the current StoredReport model is not strong enough to justify blind success. Preserving fail-closed behavior is a product-truth requirement and prevents overclaiming.

Independent Test: seed queued or stale report-producing runs plus retained StoredReport rows and verify the run stays unresolved or diagnostic-first because Spec 361 does not allow any StoredReport-backed success path.

Acceptance Scenarios:

  1. Given a report-producing run and only a latest retained StoredReport with no direct causal proof, When reconciliation runs, Then the run does not finalize as succeeded from that report alone.
  2. Given a future repo-real direct report-artifact proof path is absent, When implementation reaches that branch, Then the feature records a defer/follow-up note instead of inventing a new persistence or lifecycle model.

Edge Cases

  • Multiple matching artifacts exist and no single current-scope winner is provable.
  • An artifact exists but belongs to another workspace or managed environment.
  • A snapshot is active but partial, missing, or otherwise incomplete.
  • A review pack is ready but expired or no longer the current export for the review context.
  • A run already has reconciliation metadata from another source and the adapter should not overwrite terminal truth incorrectly.
  • A generic StoredReport looks current but still cannot prove causal linkage to the run that is being reconciled.

Requirements (mandatory)

Functional Requirements

  • FR-361-001: New artifact-backed reconciliation MUST reuse the current OperationRunReconciliationRegistry, OperationRunReconciliationAdapter contract, AdapterRunReconciler, and OperationRunService::updateRunWithReconciliation() write seam. No second registry or direct model write path is allowed.
  • FR-361-002: The feature MUST implement bounded reconciliation for tenant.evidence.snapshot.generate using existing EvidenceSnapshot scope, status, fingerprint, completeness, and operation_run_id truth.
  • FR-361-003: The feature MUST implement bounded reconciliation for environment.review_pack.generate using existing ReviewPack scope, status, fingerprint, expiration, and operation_run_id truth.
  • FR-361-004: Unsupported generic report families, especially permission.posture.check and entra.admin_roles.scan, MUST remain fail-closed in Spec 361 and MUST NOT gain any StoredReport-backed success path in this package.
  • FR-361-005: Any shared proof helper introduced for this feature MUST remain derived-only, read-only, and local to current reconciliation scope; it MUST NOT create new persisted truth or a generic artifact workflow engine.
  • FR-361-006: Evidence and review-pack adapters MUST validate workspace/environment scope before success. If present, they SHOULD also validate direct operation_run_id, fingerprint, review scope, or other current repo-real identity signals.
  • FR-361-007: Evidence reconciliation MUST require a snapshot state that is good enough to prove success: active plus non-missing completeness. Partial, failed, expired, stale, or wrong-scope states must not succeed silently.
  • FR-361-008: Review-pack reconciliation MUST require a pack state that is good enough to prove success: ready, non-expired, current-scope, and tied to the same review/evidence context when current repo truth exposes those links.
  • FR-361-009: All successful artifact-backed reconciliation MUST persist canonical metadata only through context.reconciliation, including reason, adapter key, previous lifecycle state, and related artifact reference.
  • FR-361-010: Adapters MUST be read-only toward EvidenceSnapshot, ReviewPack, and StoredReport. They may read and compare; they may not mutate artifact lifecycle or regenerate output.
  • FR-361-011: Existing operations surfaces MUST explain reconciled or unsupported states calmly and truthfully without adding a new route family, a new page family, or raw storage/debug data as the primary visible message.
  • FR-361-012: The feature MUST NOT widen restore, backup, sync, or review-compose behavior beyond the current registry-owned contract.

Non-Functional Requirements

  • NFR-361-001: The feature MUST fail closed on ambiguous, partial, expired, stale, or cross-scope artifact states.
  • NFR-361-002: The feature MUST preserve auditability by keeping reconciliation writes inside the current OperationRun lifecycle path.
  • NFR-361-003: The feature MUST be idempotent; re-running reconciliation over the same eligible artifact must not create duplicate lifecycle churn.
  • NFR-361-004: The feature SHOULD avoid migrations. If implementation somehow proves a migration is required, work must stop and spec/plan must be updated before coding further.
  • NFR-361-005: The feature MUST not add compatibility shims for pre-production historical report aliases or old fixture shapes.
  • NFR-361-006: The feature adds no destructive action, so no new confirmation flows are expected.
  • NFR-361-007: Filament and Livewire posture remains current repo truth: Filament v5 on Livewire v4, with provider registration in apps/platform/bootstrap/providers.php.
  • NFR-361-008: No new Filament asset registration is allowed; filament:assets remains unchanged.
  • NFR-361-009: Changed operator-facing surfaces MUST keep default-visible decision content above diagnostics, keep raw/support evidence behind existing host-gated reveal paths, and preserve exactly one dominant default next action.

UI Action Matrix (mandatory when Filament is changed)

Surface Location Header Actions Inspect Affordance (List/Table) Row Actions (max 2 visible) Bulk Actions (grouped) Empty-State CTA(s) View Header Actions Create/Edit Save+Cancel Audit log? Notes / Exemptions
Operations hub apps/platform/app/Filament/Pages/Monitoring/Operations.php existing only row click to canonical detail existing only existing only unchanged N/A N/A existing run lifecycle audit only no new action
Run detail apps/platform/app/Filament/Pages/Operations/TenantlessOperationRunViewer.php existing only N/A N/A N/A unchanged existing navigation only N/A existing run lifecycle audit only no new action
Evidence Snapshot detail apps/platform/app/Filament/Resources/EvidenceSnapshotResource.php existing only row click remains canonical existing only existing only unchanged existing only N/A existing audit only related run or artifact copy only
Review Pack detail apps/platform/app/Filament/Resources/ReviewPackResource.php existing only row click remains canonical existing only existing only unchanged existing only N/A existing audit only no new mutation surface

Key Entities (include if feature involves data)

  • OperationRun: persisted execution and reconciliation truth; owns type, status, outcome, summary_counts, and context.reconciliation
  • EvidenceSnapshot: persisted evidence-generation truth with operation_run_id, status, completeness state, scope, and fingerprint
  • ReviewPack: persisted review-pack artifact truth with operation_run_id, status, scope, expiration, and fingerprint
  • StoredReport: retained report artifact context only; currently lacks direct causal linkage strong enough for generic reconciliation
  • ReconciliationResult / proof helper: bounded derived decision output only; no new persistence

Success Criteria (mandatory)

Measurable Outcomes

  • SC-361-001: queued, running, or stale tenant.evidence.snapshot.generate runs can be reconciled to an existing active, current-scope snapshot without adding new persistence or new operation types.
  • SC-361-002: queued, running, or stale environment.review_pack.generate runs can be reconciled to an existing ready, non-expired, current-scope pack without adding new persistence or rendered-report scope.
  • SC-361-003: operations surfaces show one canonical artifact-backed success or non-success story, and unsupported generic StoredReport families do not silently appear successful.
  • SC-361-004: focused Unit, Feature, and bounded Browser validation passes with no new asset strategy, no migration, and no new destructive action.

Assumptions

  • Spec 359 runtime is already merged and remains the baseline adapter consumer next to restore reconciliation.
  • Current platform-dev already contains the shared context.dispatch seam and OperationRunCorrelationResolver.
  • EvidenceSnapshot and ReviewPack lifecycle fields remain the current repo-real truth for artifact readiness.
  • Generic StoredReport causality is intentionally out of scope unless implementation can prove it without new persistence or compatibility logic.

Risks

  • A helper introduced for shared proof checks could drift into a generic artifact framework if review is not strict about the two-family boundary.
  • Review-pack or evidence detail copy could overclaim success if it exposes "artifact exists" without retaining completeness or scope checks.
  • Implementers may be tempted to rescue generic StoredReport families with weak heuristics; this must be treated as out-of-scope creep unless the spec is updated first.

Open Questions

  • None blocking prep. The main repo-truth deviation is already resolved in this spec: generic StoredReport reconciliation is not part of the initial safe implementation slice.

Follow-up Spec Candidates

  • Stored-report causal reconciliation follow-through: if a future repo slice introduces direct StoredReport causal linkage, readiness lifecycle, or canonical report-output proof strong enough for safe success reconciliation, promote a separate follow-up instead of widening Spec 361 silently.