405 lines
34 KiB
Markdown
405 lines
34 KiB
Markdown
# Feature Specification: Decision Register Evidence / OperationRun Link Polish
|
|
|
|
**Feature Branch**: `307-decision-register-evidence-operationrun-link-polish`
|
|
**Created**: 2026-05-15
|
|
**Status**: Draft
|
|
**Input**: User-provided full draft for Spec 307, promoted from the manual `decision-register-evidence-operationrun-link-polish` candidate after Spec 306 reconciliation.
|
|
|
|
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
|
|
|
|
- **Problem**: The operator Decision Register exists and is backed by existing `FindingException` / `FindingExceptionDecision` truth, but proof, evidence/report references, and related `OperationRun` context are not visible enough from the register path.
|
|
- **Today's failure**: Operators can see a governance decision, but must often open the detail page or reconstruct context elsewhere to learn which proof, report, or execution record supports the decision. A count without a truthful affordance weakens confidence in the governance-of-record story.
|
|
- **User-visible improvement**: Register rows show a calm proof state, direct evidence/report or aggregate proof links only where repo-real and authorized, optional canonical operation links only where real run references exist, and clear missing states when no proof/run link exists.
|
|
- **Smallest enterprise-capable version**: Extend the existing read-only Decision Register row projection and Filament table display with safe derived link metadata. Reuse existing artifact resources, existing `FindingException` detail handoff, and existing OperationRun link helpers. Do not add persistence, lifecycle actions, or a new workflow engine.
|
|
- **Explicit non-goals**: No new `governance_decisions` table, no approval engine, no inline register approve/reject/renew/revoke actions, no OperationRun lifecycle controller, no evidence payload storage, no Review Pack redesign, no customer-facing register/export, no notification system, no provider/Graph changes, and no broad navigation redesign.
|
|
- **Permanent complexity imported**: Low. The slice may add derived array metadata to the existing builder, focused tests, and compact table/link rendering. It must not add a new model, table, enum family, DTO class, presenter framework, route family, or asset bundle.
|
|
- **Why now**: `docs/product/roadmap.md`, `docs/product/implementation-ledger.md`, and `docs/product/spec-candidates.md` rank this as the first current manual promotion. Spec 306 specifically classifies the current register as partial productization and names this narrow proof-link follow-up as the next step.
|
|
- **Why not local**: The current local count-only display does not answer the operator's next question: "What proof supports this decision, and what execution or evidence record should I inspect next?" The smallest fix belongs in the existing register builder/page, not in a new workflow or artifact system.
|
|
- **Approval class**: Workflow Compression
|
|
- **Red flags triggered**: Cross-cutting evidence/report and OperationRun link affordances. Defense: the slice reuses existing helpers and destination authorization, introduces no new persisted truth, and forbids fake links.
|
|
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 2 | Produktnaehe: 2 | Wiederverwendung: 2 | **Gesamt: 12/12**
|
|
- **Decision**: approve
|
|
|
|
## Spec Scope Fields *(mandatory)*
|
|
|
|
- **Scope**: canonical-view
|
|
- **Primary Routes**:
|
|
- Existing `/admin/governance/decisions` Decision Register page.
|
|
- Existing workspace/environment scoped `FindingExceptionResource` view route for detail handoff and aggregate proof fallback.
|
|
- Existing `EvidenceSnapshotResource` view route when a referenced evidence snapshot can be resolved safely.
|
|
- Existing `StoredReportResource` view route when a referenced stored report can be resolved safely.
|
|
- Existing canonical `admin.operations.view` route through `OperationRunLinks` / `OperationRunUrl` when a real operation run reference can be resolved safely.
|
|
- **Data Ownership**:
|
|
- `FindingException`, `FindingExceptionDecision`, and `FindingExceptionEvidenceReference` remain decision truth.
|
|
- `EvidenceSnapshot` and `StoredReport` remain artifact truth.
|
|
- `OperationRun` remains execution truth.
|
|
- The register stores no copied payloads and introduces no new persisted decision or proof model.
|
|
- **RBAC**:
|
|
- Workspace membership is the first boundary.
|
|
- Register visibility continues to use `Capabilities::FINDING_EXCEPTION_VIEW`.
|
|
- Destination pages keep their own policies/capabilities: evidence, stored reports, finding exceptions, and operation runs are server-side authorized.
|
|
- Non-member or out-of-scope workspace/environment targets remain deny-as-not-found (`404`).
|
|
- Member-but-missing-capability destination access remains `403` where existing policies define capability denial.
|
|
|
|
For canonical-view specs:
|
|
|
|
- **Default filter behavior when tenant-context is active**: Existing Decision Register environment prefilter behavior is preserved. Link polish must not change the default open-decision register or recently-closed redirect behavior.
|
|
- **Explicit entitlement checks preventing cross-tenant leakage**: Proof/run link resolution must begin from the already scoped `FindingException` row and only resolve artifacts/runs within the same workspace and environment. Hidden destinations must produce a disabled/unavailable state or no URL, not a cross-scope URL.
|
|
|
|
## Cross-Cutting / Shared Pattern Reuse *(mandatory)*
|
|
|
|
- **Cross-cutting feature?**: yes
|
|
- **Interaction class(es)**: action links, evidence/report viewers, operation links, navigation continuity, table proof state, missing-state copy.
|
|
- **Systems touched**: `DecisionRegister`, `GovernanceDecisionRegisterBuilder`, `FindingExceptionResource`, `ViewFindingException`, `FindingExceptionEvidenceReference`, `EvidenceSnapshotResource`, `StoredReportResource`, `OperationRunLinks`, `OperationRunUrl`, `CanonicalNavigationContext`, and focused governance/findings/evidence/operation tests.
|
|
- **Existing pattern(s) to extend**: existing Filament resources and resource `getUrl()` methods, existing `WorkspaceScopedTenantRoutes`, existing tenant-owned record authorization, existing `OperationRunLinks::tenantlessView()`, existing FindingException detail handoff.
|
|
- **Shared contract / presenter / builder / renderer to reuse**: Reuse the existing builder rather than adding a new decision presenter. Reuse existing resource URL helpers and OperationRun link helpers rather than constructing URLs locally.
|
|
- **Why the existing shared path is sufficient or insufficient**: Existing destination pages and link helpers are sufficient for canonical links. The current register builder/page is insufficient because it exposes only proof count/missing copy and not safe link metadata.
|
|
- **Allowed deviation and why**: A small derived link-metadata array inside the existing builder/page is allowed if it keeps the projection read-only and avoids a new class hierarchy.
|
|
- **Consistency impact**: Link labels must stay calm: `View proof`, `View evidence`, `View report`, `View operation`, `No linked proof`, and `No operation linked`.
|
|
- **Review focus**: Block fake links, raw URL concatenation, cross-workspace/environment URL generation, copied evidence payloads, and lifecycle actions on the register.
|
|
|
|
## OperationRun UX Impact *(mandatory)*
|
|
|
|
- **Touches OperationRun start/completion/link UX?**: yes, link-only.
|
|
- **Shared OperationRun UX contract/layer reused**: `OperationRunLinks` and, where locally established, `App\Support\OpsUx\OperationRunUrl`.
|
|
- **Delegated start/completion UX behaviors**: Only canonical `View operation` / `Open operation` URL resolution. No queued toast, no browser event, no DB notification, no dedupe/start failure messaging, and no status/outcome mutation.
|
|
- **Local surface-owned behavior that remains**: The register may show an optional secondary operation link when a same-scope, authorized run exists. It may show `No operation linked` or omit the operation link when no real run exists.
|
|
- **Queued DB-notification policy**: N/A
|
|
- **Terminal notification path**: N/A
|
|
- **Exception required?**: none
|
|
|
|
## Provider Boundary / Platform Core Check *(mandatory)*
|
|
|
|
- **Shared provider/platform boundary touched?**: no
|
|
- **Boundary classification**: N/A
|
|
- **Seams affected**: Existing artifact metadata may contain provider-owned labels, but the register link logic must use platform-core terms: proof, evidence, report, operation, workspace, environment.
|
|
- **Neutral platform terms preserved or introduced**: proof, evidence, stored report, operation, workspace, environment.
|
|
- **Provider-specific semantics retained and why**: Existing artifact destination pages may display provider-specific report details because they already own that truth. The register must not promote provider payload detail into row-level decision truth.
|
|
- **Why this does not deepen provider coupling accidentally**: Link resolution is based on repo-real models, IDs, scope, and existing resources, not provider-specific text or Graph payload fields.
|
|
- **Follow-up path**: none for this slice.
|
|
|
|
## UI / Surface Guardrail Impact *(mandatory)*
|
|
|
|
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|
|
|---|---|---|---|---|---|---|
|
|
| Decision Register page | yes | Native Filament table/page with existing Blade host only | proof links, operation links, read-only decision register | page, table row, URL-query context | no | Compact link polish over existing surface |
|
|
| FindingException detail evidence section | maybe minimal | Native Filament infolist | aggregate proof fallback and unsupported reference display | detail | no | Only polish labels or anchors if needed |
|
|
|
|
Implementation intent: use Filament table columns/actions or existing linkable text primitives. Do not add local CSS, ad-hoc cards, custom button systems, hover affordance without a real URL, or new assets. Filament remains v5 with Livewire v4.
|
|
|
|
## Decision-First Surface Role *(mandatory)*
|
|
|
|
| Surface | Decision Role | Human-in-the-loop Moment | Immediately Visible for First Decision | On-Demand Detail / Evidence | Why This Is Primary or Why Not | Workflow Alignment | Attention-load Reduction |
|
|
|---|---|---|---|---|---|---|---|
|
|
| Decision Register page | Primary Decision Surface | Operator chooses which governance decision to inspect next | decision state, owner, due context, proof state, optional operation link, `Open decision` | full decision history and evidence details stay on FindingException/artifact/run pages | Primary because it is the workspace register for follow-through | Answers "what needs proof inspection now?" without becoming the proof owner | Reduces searching across detail, evidence, reports, and operations |
|
|
| FindingException detail page | Secondary Context | Operator validates proof and performs existing lifecycle actions | current decision summary, detail-owned actions, evidence references | artifact details, decision history, audit context | Secondary because it owns proof depth and lifecycle action | Preserves existing queue/detail ownership | Avoids duplicating lifecycle controls on the register |
|
|
|
|
## Audience-Aware Disclosure *(mandatory)*
|
|
|
|
| Surface | Audience Modes In Scope | Decision-First Default-Visible Content | Operator Diagnostics | Support / Raw Evidence | One Dominant Next Action | Hidden / Gated By Default | Duplicate-Truth Prevention |
|
|
|---|---|---|---|---|---|---|---|
|
|
| Decision Register page | operator-MSP | proof count/state, one proof affordance, optional operation link, existing next action | destination pages hold diagnostics | raw payloads, fingerprints, provider dumps, and JSON stay off rows | `Open decision` remains the primary row inspect action | artifact/run URLs hidden or disabled when unavailable or unauthorized | row states summarize availability only; artifact pages own details |
|
|
| FindingException detail page | operator-MSP | decision and evidence-reference summary | decision history and evidence references | raw/support evidence remains secondary/collapsible where present | existing lifecycle action when allowed | unsupported references show truthful non-linked state | detail deepens one selected decision only |
|
|
|
|
## UI/UX Surface Classification *(mandatory)*
|
|
|
|
| Surface | Action Surface Class | Surface Type | Likely Next Operator Action | Primary Inspect/Open Model | Row Click | Secondary Actions Placement | Destructive Actions Placement | Canonical Collection Route | Canonical Detail Route | Scope Signals | Canonical Noun | Critical Truth Visible by Default | Exception Type / Justification |
|
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Decision Register page | Utility / Workspace Decision | Read-only registry report | Open decision, then inspect proof or operation if needed | existing row click/detail handoff remains primary | allowed/current behavior preserved | compact proof/run links stay secondary | none | `/admin/governance/decisions` | existing FindingException view route | workspace, optional environment, register state | Decision register | proof availability and next inspection target | none |
|
|
|
|
## Operator Surface Contract *(mandatory)*
|
|
|
|
| Surface | Primary Persona | Decision / Operator Action Supported | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions |
|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Decision Register page | Workspace operator / MSP operator | Decide which decision proof or operation record to inspect next | Read-only decision register | What proof supports this decision, and where should I inspect next? | current decision row, proof count/state/link, optional operation link, missing proof/run copy | raw evidence summaries, artifact payloads, run diagnostics | decision status, validity/impact, proof availability, operation-link availability | none | Open decision | none |
|
|
| FindingException detail page | Workspace operator / approver | Validate proof and use existing lifecycle controls | Detail / reviewable governance record | Why is this decision in this state and what action is allowed now? | decision summary, evidence references, existing header actions | deeper audit/evidence payloads and unsupported reference metadata | decision lifecycle, evidence availability, audit history | existing FindingException lifecycle only | renew/revoke or queue-owned approve/reject when already allowed | existing detail-owned destructive actions only, with confirmation |
|
|
|
|
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
|
|
|
- **New source of truth?**: no
|
|
- **New persisted entity/table/artifact?**: no
|
|
- **New abstraction?**: no new class or framework; only derived metadata on the existing builder/page if needed.
|
|
- **New enum/state/reason family?**: no persisted family. Allowed derived link states are local projection strings only: `linked_evidence`, `linked_report`, `linked_detail_section`, `unavailable`, `not_linked`, `linked_run`, `run_not_available`.
|
|
- **New cross-domain UI framework/taxonomy?**: no
|
|
- **Current operator problem**: Operators need visible proof/run affordances for existing decisions without rebuilding decision truth.
|
|
- **Existing structure is insufficient because**: The current register proof column shows a count or `No linked proof` but does not expose safe direct links where existing artifact/run truth is resolvable.
|
|
- **Narrowest correct implementation**: Add read-only derived link metadata and compact rendering to the existing builder/page; fallback to the existing detail surface for aggregate or unsupported cases.
|
|
- **Ownership cost**: Focused tests and a small builder/page extension. No migration, no new lifecycle owner, no new navigation family.
|
|
- **Alternative intentionally rejected**: New decision table, proof storage, artifact-link service framework, operation lifecycle integration, and customer-safe export were rejected as over-scoped.
|
|
- **Release truth**: current-release productization polish over existing operator truth.
|
|
|
|
### Compatibility posture
|
|
|
|
This feature assumes a pre-production environment. No legacy `/admin/t` route, compatibility alias, migration shim, or stale tenant-panel URL is allowed.
|
|
|
|
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
|
|
|
|
- **Test purpose / classification**: Unit, Feature, and one Browser smoke recommendation because the feature changes operator UI/link behavior.
|
|
- **Validation lane(s)**: fast-feedback and confidence for focused Pest coverage; browser only for the manual/in-app smoke path.
|
|
- **Why this classification and these lanes are sufficient**: Builder unit tests prove derived link states cheaply. Feature tests prove rendering, URL canonicality, authorization, and cross-scope denial. Browser smoke verifies the Filament table/link experience without creating a new browser family.
|
|
- **New or expanded test families**: Existing `GovernanceDecisionRegisterBuilderTest`, `DecisionRegisterPageTest`, `DecisionRegisterAuthorizationTest`, `FindingExceptionDecisionRegisterNavigationTest`, `FindingExceptionDecisionRegisterBoundariesTest`, and existing evidence/operation link guard tests may be extended. No new heavy-governance family.
|
|
- **Fixture / helper cost impact**: Moderate, feature-local. Tests need scoped workspaces/environments, FindingException evidence references, optional EvidenceSnapshot/StoredReport/OperationRun records, and negative cross-scope fixtures. Helpers should stay opt-in.
|
|
- **Heavy-family visibility / justification**: none.
|
|
- **Special surface test profile**: global-context-shell plus standard-native-filament.
|
|
- **Reviewer handoff**: Confirm no lifecycle actions moved into the register, no fake links appear from loose text, `/admin/t` is absent, and destination policies still enforce access.
|
|
- **Budget / baseline / trend impact**: low feature-local increase only.
|
|
- **Escalation needed**: none.
|
|
- **Active feature PR close-out entry**: Guardrail / Smoke Coverage.
|
|
- **Planned validation commands**: see Validation Commands.
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### User Story 1 - See truthful proof state on each decision row (Priority: P1)
|
|
|
|
As a workspace operator, I want the Decision Register to show whether a decision has linked proof so I know whether the visible decision is supported before opening detail pages.
|
|
|
|
**Why this priority**: This is the minimum visible productization improvement and protects against false calmness.
|
|
|
|
**Independent Test**: Seed decisions with zero, one, and multiple evidence references and verify the register displays truthful count/state/copy without fake URLs.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a visible decision has no evidence references, **When** the register renders, **Then** the proof column shows `No linked proof` or equivalent and no proof URL is emitted.
|
|
2. **Given** a visible decision has evidence references, **When** the register renders, **Then** the proof count matches existing references and the row exposes either a safe proof link or detail-section handoff.
|
|
3. **Given** multiple proof references exist, **When** the register renders, **Then** it uses one calm aggregate proof affordance instead of multiple noisy peer links.
|
|
|
|
### User Story 2 - Open real evidence/report/operation truth from the register (Priority: P1)
|
|
|
|
As a workspace operator, I want direct links to evidence snapshots, stored reports, or operations where they are real and authorized so I can inspect the proof trail without reconstructing it.
|
|
|
|
**Why this priority**: It closes the Spec 306 productization gap without changing lifecycle ownership.
|
|
|
|
**Independent Test**: Seed same-scope EvidenceSnapshot, StoredReport, and OperationRun references and verify generated links are canonical, authorized, and absent when references cannot be resolved.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** exactly one resolvable same-scope evidence snapshot reference exists, **When** the row renders, **Then** `View evidence` or `View proof` opens the existing EvidenceSnapshot view.
|
|
2. **Given** exactly one resolvable same-scope stored-report reference exists, **When** the row renders, **Then** `View report` opens the existing StoredReport view.
|
|
3. **Given** a real same-scope OperationRun reference exists through the decision source or linked artifact, **When** the row renders, **Then** `View operation` uses the canonical OperationRun helper URL.
|
|
4. **Given** a source reference cannot be resolved to a real model and authorized route, **When** the row renders, **Then** the row shows a truthful non-linked state.
|
|
|
|
### User Story 3 - Preserve scope, authorization, and lifecycle boundaries (Priority: P1)
|
|
|
|
As a workspace operator, I need proof and operation links to respect workspace/environment/RBAC boundaries and keep lifecycle actions on existing surfaces.
|
|
|
|
**Why this priority**: Proof links are trust features; cross-scope leakage or lifecycle drift would be a security and product-truth regression.
|
|
|
|
**Independent Test**: Attempt cross-workspace and cross-environment link access and verify generated URLs are absent or destination access denies as existing policies define.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a referenced artifact belongs to another workspace, **When** the register builds rows, **Then** no URL for that artifact is rendered and direct access remains denied.
|
|
2. **Given** a referenced operation belongs to another environment, **When** the register builds rows, **Then** no operation URL is rendered and direct access remains denied.
|
|
3. **Given** the operator opens the register, **When** they inspect row actions, **Then** approve, reject, renew, revoke, and closure actions are not introduced on the register.
|
|
|
|
### Edge Cases
|
|
|
|
- Evidence reference has a `source_type` but no `source_id`.
|
|
- Evidence reference `source_id` is a loose external key rather than a numeric local artifact ID.
|
|
- Evidence reference points to a deleted or inaccessible artifact.
|
|
- Stored report exists but the user lacks the report-family capability.
|
|
- Evidence snapshot exists but the current user cannot view evidence for that environment.
|
|
- OperationRun exists but the user lacks workspace membership, environment entitlement, or the run-required capability.
|
|
- Multiple evidence references include mixed resolvable and unsupported sources.
|
|
- Query parameters or generated links must not contain legacy `/admin/t`.
|
|
- Recently closed decisions keep proof affordances but do not become lifecycle-action surfaces.
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
### Functional Requirements
|
|
|
|
- **FR-001**: Decision Register rows MUST expose a truthful proof state for each visible decision: linked proof, aggregate proof on detail, unavailable proof, or no linked proof.
|
|
- **FR-002**: The register MUST NOT render a proof URL unless a real same-scope model/id/context exists and the current user can safely attempt the destination.
|
|
- **FR-003**: A single resolvable `EvidenceSnapshot` reference MUST link to the existing EvidenceSnapshot view using the resource URL helper and workspace/environment-scoped route semantics.
|
|
- **FR-004**: A single resolvable `StoredReport` reference MUST link to the existing StoredReport view using the resource URL helper and stored-report capability semantics.
|
|
- **FR-005**: Multiple evidence/report references SHOULD link to the existing FindingException detail proof section or equivalent safe aggregate detail target rather than rendering a noisy multi-link cluster.
|
|
- **FR-006**: Unsupported evidence references MUST render as truthful non-linked proof availability and MUST NOT break the row or detail rendering.
|
|
- **FR-007**: OperationRun links MUST appear only when a real same-scope OperationRun reference exists directly or through a repo-real linked artifact/source.
|
|
- **FR-008**: OperationRun URLs MUST use `OperationRunLinks` or `OperationRunUrl`; raw string-concatenated operation URLs are forbidden.
|
|
- **FR-009**: Generated proof/report/run URLs MUST be canonical workspace/environment/admin URLs and MUST NOT contain `/admin/t`.
|
|
- **FR-010**: Link resolution MUST remain scoped to the current workspace and visible environment set before counts and labels are derived.
|
|
- **FR-011**: Destination pages MUST keep their own server-side authorization; register link visibility is not a security boundary.
|
|
- **FR-012**: The existing Decision Register row to FindingException detail handoff MUST remain intact and must continue to carry navigation context.
|
|
- **FR-013**: Approval, rejection, renewal, revocation, and closure actions MUST remain on existing queue/detail surfaces and MUST NOT be added to the register.
|
|
- **FR-014**: Evidence/report payloads, stored-report payloads, and OperationRun lifecycle truth MUST NOT be copied into register rows or decision records.
|
|
- **FR-015**: Any derived builder metadata MUST remain read-only, deterministic, testable, and bounded to already scoped queries.
|
|
|
|
### Non-Functional Requirements
|
|
|
|
- **NFR-001**: UI copy must stay calm and non-alarming for missing references: `No linked proof`, `No operation linked`, `Proof available on detail`, or equivalent.
|
|
- **NFR-002**: The register must remain scanable with one primary row inspect model and at most compact secondary proof/run affordances.
|
|
- **NFR-003**: No local UI styling system, new assets, or custom CSS framework may be introduced.
|
|
- **NFR-004**: No Microsoft Graph/provider boundary changes may be introduced.
|
|
- **NFR-005**: No migration is expected; any proposed migration must prove existing relations cannot safely support the narrow link behavior.
|
|
|
|
## 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 |
|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Decision Register page | `apps/platform/app/Filament/Pages/Governance/DecisionRegister.php` | existing scope/filter controls only | existing row/detail handoff remains primary | proof link, optional operation link only when real and authorized | none | existing filter reset/current decision CTA behavior preserved | N/A | N/A | none, read-only | No lifecycle actions |
|
|
| FindingException detail | `apps/platform/app/Filament/Resources/FindingExceptionResource.php`; `.../Pages/ViewFindingException.php` | existing return/renew/revoke actions preserved | N/A | N/A | none | existing | existing lifecycle actions preserved | N/A | existing service audit for mutations | Minimal evidence-label/link polish only if needed |
|
|
|
|
## Key Entities *(include if feature involves data)*
|
|
|
|
- **FindingException**: Current decision aggregate and register row source.
|
|
- **FindingExceptionDecision**: Append-only decision history and current decision pointer.
|
|
- **FindingExceptionEvidenceReference**: Existing proof-reference records with `source_type`, `source_id`, `source_fingerprint`, label, summary, and measured timestamp.
|
|
- **EvidenceSnapshot**: Existing evidence artifact truth with workspace/environment scope and optional OperationRun relationship.
|
|
- **StoredReport**: Existing retained report artifact truth with workspace/environment scope and report-family capability semantics.
|
|
- **OperationRun**: Existing execution truth and canonical operation detail destination.
|
|
|
|
## Success Criteria *(mandatory)*
|
|
|
|
### Measurable Outcomes
|
|
|
|
- **SC-001**: A user can identify from the register whether a decision has linked proof without opening the detail page.
|
|
- **SC-002**: Decisions with no proof render a truthful missing state and no proof URL.
|
|
- **SC-003**: Resolvable same-scope evidence/report links from the register open existing canonical artifact views.
|
|
- **SC-004**: Resolvable same-scope operation links from the register open the canonical OperationRun view and never emit `/admin/t`.
|
|
- **SC-005**: Cross-workspace and cross-environment proof/run references do not leak URLs or data.
|
|
- **SC-006**: Existing detail handoff and lifecycle ownership tests remain green.
|
|
- **SC-007**: No new persistence, workflow engine, approval engine, OperationRun lifecycle behavior, provider integration, or asset bundle is introduced.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- **AC-001**: Proof affordance improved for real references.
|
|
- **AC-002**: Missing proof is truthful and non-linked.
|
|
- **AC-003**: Evidence links are canonical and scope-safe.
|
|
- **AC-004**: Stored-report links appear only for repo-real, authorized stored-report references.
|
|
- **AC-005**: OperationRun links appear only for real, authorized run references and use existing helpers.
|
|
- **AC-006**: Evidence/report payloads and run lifecycle truth are not duplicated.
|
|
- **AC-007**: Existing FindingException detail handoff still works.
|
|
- **AC-008**: Lifecycle actions are not moved into the register.
|
|
- **AC-009**: Workspace isolation is preserved.
|
|
- **AC-010**: Environment isolation is preserved.
|
|
- **AC-011**: Destination RBAC remains server-side enforced.
|
|
- **AC-012**: Focused Decision Register, Governance Inbox, FindingException, artifact, and OperationRun link tests pass.
|
|
- **AC-013**: `git diff --check` passes.
|
|
- **AC-014**: Browser smoke passes or close-out documents why it was not run.
|
|
- **AC-015**: No broad Decision Register rebuild occurs.
|
|
|
|
## Current Truth Boundary
|
|
|
|
- `GovernanceDecisionRegisterBuilder` currently derives rows from scoped `FindingException` records and current decisions.
|
|
- `DecisionRegister` currently renders a native Filament table, proof count from `evidence_summary.reference_count`, and `No linked proof` when zero.
|
|
- `FindingExceptionEvidenceReference` currently stores `source_type` and `source_id` as reference metadata, not a guaranteed foreign key.
|
|
- `EvidenceSnapshotResource`, `StoredReportResource`, and canonical OperationRun pages exist with their own scope/authorization semantics.
|
|
- `OperationRunPolicy` enforces workspace membership, environment entitlement, and run-specific capability where required.
|
|
- The implementation must use repo-real names/fields if they differ from this spec and document any adjustment in implementation close-out.
|
|
|
|
## Validation Commands
|
|
|
|
Primary Decision Register lane:
|
|
|
|
```bash
|
|
cd apps/platform && ./vendor/bin/sail artisan test --compact \
|
|
tests/Unit/Support/GovernanceDecisions/GovernanceDecisionRegisterBuilderTest.php \
|
|
tests/Unit/Support/GovernanceInbox/GovernanceInboxSectionBuilderTest.php \
|
|
tests/Feature/Governance/DecisionRegisterPageTest.php \
|
|
tests/Feature/Governance/DecisionRegisterAuthorizationTest.php \
|
|
tests/Feature/Governance/GovernanceInboxPageTest.php \
|
|
tests/Feature/Governance/GovernanceInboxAuthorizationTest.php \
|
|
tests/Feature/Findings/FindingExceptionDecisionRegisterNavigationTest.php \
|
|
tests/Feature/Findings/FindingExceptionDetailDecisionSummaryTest.php \
|
|
tests/Feature/Findings/FindingExceptionDecisionRegisterBoundariesTest.php
|
|
```
|
|
|
|
FindingException lifecycle/audit lane:
|
|
|
|
```bash
|
|
cd apps/platform && ./vendor/bin/sail artisan test --compact \
|
|
tests/Unit/Findings/FindingExceptionDecisionTest.php \
|
|
tests/Feature/Findings/FindingExceptionWorkflowTest.php \
|
|
tests/Feature/Findings/FindingExceptionRenewalTest.php \
|
|
tests/Feature/Findings/FindingExceptionRevocationTest.php
|
|
```
|
|
|
|
Evidence/review/artifact lane:
|
|
|
|
```bash
|
|
cd apps/platform && ./vendor/bin/sail artisan test --compact \
|
|
tests/Feature/Evidence/EvidenceSnapshotResourceTest.php \
|
|
tests/Feature/Evidence/EvidenceSnapshotAuditLogTest.php \
|
|
tests/Feature/EnvironmentReview/EnvironmentReviewAuditLogTest.php \
|
|
tests/Feature/EnvironmentReview/EnvironmentReviewRegisterTest.php \
|
|
tests/Feature/EnvironmentReview/EnvironmentReviewRegisterRbacTest.php \
|
|
tests/Feature/Reviews/CustomerReviewWorkspacePageTest.php \
|
|
tests/Feature/Reviews/CustomerReviewWorkspaceAuthorizationTest.php \
|
|
tests/Feature/Reviews/CustomerReviewWorkspacePackAccessTest.php \
|
|
tests/Feature/Reviews/CustomerReviewWorkspaceLaunchLinksTest.php \
|
|
tests/Feature/Filament/GovernanceArtifacts/GovernanceArtifactDeepLinkContractTest.php
|
|
```
|
|
|
|
OperationRun/link guard lane:
|
|
|
|
```bash
|
|
cd apps/platform && ./vendor/bin/sail artisan test --compact \
|
|
tests/Feature/Monitoring/OperationsDashboardDrillthroughTest.php \
|
|
tests/Feature/Operations/LegacyRunRoutesNotFoundTest.php \
|
|
tests/Feature/ProviderConnections/LegacyRedirectTest.php \
|
|
tests/Feature/RequiredPermissions/RequiredPermissionsLegacyRouteTest.php \
|
|
tests/Feature/Guards/ManagedEnvironmentCanonicalRouteContractTest.php \
|
|
tests/Feature/Filament/PolicyVersionResolvedReferenceLinksTest.php
|
|
```
|
|
|
|
Whitespace:
|
|
|
|
```bash
|
|
git diff --check
|
|
```
|
|
|
|
Browser smoke is recommended because this changes operator UI/link behavior:
|
|
|
|
1. Open Governance > Decisions.
|
|
2. Confirm rows render.
|
|
3. Confirm a decision with proof shows a proof affordance.
|
|
4. Confirm a decision without proof shows a calm missing state.
|
|
5. Open a proof link where available.
|
|
6. Open an OperationRun link where available.
|
|
7. Confirm row detail handoff still opens FindingException detail.
|
|
8. Confirm no lifecycle actions moved into the register.
|
|
9. Confirm no `/admin/t` URL appears.
|
|
|
|
## Out of Scope
|
|
|
|
- New decision persistence model.
|
|
- New lifecycle actions.
|
|
- Inline register approval/closure controls.
|
|
- Evidence ingestion or payload storage.
|
|
- Review Pack redesign or inclusion.
|
|
- Customer-facing Decision Register.
|
|
- Generic customer-safe export.
|
|
- PSA/ITSM handoff.
|
|
- Notification engine.
|
|
- AI summaries.
|
|
- Broad Governance Inbox or navigation redesign.
|
|
- Provider/Graph changes.
|
|
- Migrations unless repo verification proves a tiny metadata/index gap is unavoidable.
|
|
- Assets unless required by existing build conventions.
|
|
|
|
## Assumptions
|
|
|
|
- The user-provided Spec 307 draft is the selected manual promotion.
|
|
- Spec 265 is implemented/closed and must be treated as context only.
|
|
- Spec 306 reconciliation is authoritative for the partial-productization classification.
|
|
- Some existing `FindingExceptionEvidenceReference.source_id` values may be loose external identifiers; implementation must not treat them as local artifact IDs without verification.
|
|
- StoredReport direct links are possible only for references resolvable to `StoredReport` records under existing report-family authorization.
|
|
- OperationRun direct links are possible only for real run IDs or artifact relationships that resolve to `OperationRun` records under existing policy.
|
|
|
|
## Risks
|
|
|
|
- **Risk: Fake OperationRun links**. Mitigation: only link real `OperationRun` records and use helper URLs.
|
|
- **Risk: Evidence payload duplication**. Mitigation: link only; do not copy payloads into register rows.
|
|
- **Risk: Register becomes noisy**. Mitigation: one proof affordance and optional compact operation link only.
|
|
- **Risk: Cross-scope leak**. Mitigation: scope resolution from the row's workspace/environment and destination policy tests.
|
|
- **Risk: Lifecycle drift**. Mitigation: no register mutations and run existing FindingException workflow tests.
|
|
|
|
## Follow-up Candidates
|
|
|
|
- `decision-register-review-pack-inclusion`
|
|
- `decision-register-customer-safe-summary`
|
|
- `decision-register-governance-inbox-cta-polish`
|
|
- `decision-register-notification-follow-up`
|
|
|
|
Do not create a broad `Decision Register v1`.
|